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,buffer_len2, max;
1338 header_field_info *hfinfo;
1340 di=pinfo->private_data;
1341 if(di->conformant_run){
1342 /* just a run to handle conformant arrays, no scalars to dissect */
1347 string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1348 proto_registrar_get_name(hfindex));
1349 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1355 /* NDR array header */
1357 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1358 hf_dcerpc_array_max_count, &max);
1360 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1361 hf_dcerpc_array_offset, NULL);
1363 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1364 hf_dcerpc_array_actual_count, &len);
1365 buffer_len = size_is * len;
1366 buffer_len2 = size_is * max;
1367 hfinfo = proto_registrar_get_nth(hfindex);
1370 if (offset % size_is)
1371 offset += size_is - (offset % size_is);
1372 if( buffer_len2 != buffer_len && hfinfo->type == FT_STRING && tvb_reported_length_remaining(tvb,offset) > (gint)buffer_len2) {
1373 /* Max can be bigger that len
1374 * if the packet is comming from windows it normally means that the
1375 * last two bytes are null terminators. In this case we change the length
1376 * in order to consume them ...
1377 * If it's from samba then it's more unlikely to be terminator so we carefully check if
1378 * it's null terminators or not in order to know if we should consume them */
1380 buf = ep_alloc(sizeof(guint8)*buffer_len2);
1381 tvb_memcpy(tvb,buf,offset,buffer_len2);
1382 if( buf[buffer_len2-2] == 0x0 && buf[buffer_len2-1] == 0x0) {
1383 buffer_len = buffer_len2;
1386 if (size_is == sizeof(guint16)) {
1387 /* XXX - use drep to determine the byte order? */
1388 s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
1390 * XXX - we don't support a string type with Unicode
1391 * characters, so if this is a string item, we make
1392 * its value be the "fake Unicode" string.
1394 if (tree && buffer_len) {
1395 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1396 if (hfinfo->type == FT_STRING) {
1397 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1400 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1401 buffer_len, drep[0] & 0x10);
1406 * "tvb_get_ephemeral_string()" throws an exception if the entire string
1407 * isn't in the tvbuff. If the length is bogus, this should
1408 * keep us from trying to allocate an immensely large buffer.
1409 * (It won't help if the length is *valid* but immensely large,
1410 * but that's another matter; in any case, that would happen only
1411 * if we had an immensely large tvbuff....)
1413 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1414 s = tvb_get_ephemeral_string(tvb, offset, buffer_len);
1415 if (tree && buffer_len)
1416 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1417 buffer_len, drep[0] & 0x10);
1420 if (string_item != NULL)
1421 proto_item_append_text(string_item, ": %s", s);
1426 offset += buffer_len;
1428 proto_item_set_end(string_item, tvb, offset);
1433 /* Dissect an conformant varying string of chars.
1434 This corresponds to IDL of the form '[string] char *foo'.
1436 XXX - at least according to the DCE RPC 1.1 spec, a string has
1437 a null terminator, which isn't necessary as a terminator for
1438 the transfer language (as there's a length), but is presumably
1439 there for the benefit of null-terminated-string languages
1440 such as C. Is this ever used for purely counted strings?
1441 (Not that it matters if it is.) */
1443 dissect_ndr_char_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1444 proto_tree *tree, guint8 *drep)
1447 di=pinfo->private_data;
1449 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1450 sizeof(guint8), di->hf_index,
1454 /* Dissect a conformant varying string of wchars (wide characters).
1455 This corresponds to IDL of the form '[string] wchar *foo'
1457 XXX - at least according to the DCE RPC 1.1 spec, a string has
1458 a null terminator, which isn't necessary as a terminator for
1459 the transfer language (as there's a length), but is presumably
1460 there for the benefit of null-terminated-string languages
1461 such as C. Is this ever used for purely counted strings?
1462 (Not that it matters if it is.) */
1464 dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1465 proto_tree *tree, guint8 *drep)
1468 di=pinfo->private_data;
1470 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1471 sizeof(guint16), di->hf_index,
1475 /* This function is aimed for PIDL useage and dissects a UNIQUE pointer to
1479 PIDL_dissect_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep, int chsize, int hfindex, guint32 param)
1483 gint levels = CB_STR_ITEM_LEVELS(param);
1485 di=pinfo->private_data;
1487 offset = dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1491 if(!di->conformant_run){
1492 /* Append string to COL_INFO */
1493 if (param & PIDL_SET_COL_INFO) {
1494 if (check_col(pinfo->cinfo, COL_INFO))
1495 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", s);
1497 /* Save string to dcv->private_data */
1498 if((param & PIDL_STR_SAVE)
1499 && (!pinfo->fd->flags.visited)){
1500 dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1501 dcv->private_data = se_strdup(s);
1503 /* Append string to upper-level proto_items */
1504 if (levels > 0 && tree && s && s[0]) {
1505 proto_item_append_text(tree, ": %s", s);
1506 tree = tree->parent;
1509 proto_item_append_text(tree, ": %s", s);
1510 tree = tree->parent;
1512 while (levels > 0) {
1513 proto_item_append_text(tree, " %s", s);
1514 tree = tree->parent;
1526 /* Dissect an NDR varying string of elements.
1527 The length of each element is given by the 'size_is' parameter;
1528 the elements are assumed to be characters or wide characters.
1531 dissect_ndr_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1532 proto_tree *tree, guint8 *drep, int size_is,
1533 int hfindex, gboolean add_subtree, char **data)
1536 proto_item *string_item;
1537 proto_tree *string_tree;
1538 guint32 len, buffer_len;
1540 header_field_info *hfinfo;
1542 di=pinfo->private_data;
1543 if(di->conformant_run){
1544 /* just a run to handle conformant arrays, no scalars to dissect */
1549 string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1550 proto_registrar_get_name(hfindex));
1551 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1557 /* NDR array header */
1558 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1559 hf_dcerpc_array_offset, NULL);
1561 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1562 hf_dcerpc_array_actual_count, &len);
1564 buffer_len = size_is * len;
1567 if (offset % size_is)
1568 offset += size_is - (offset % size_is);
1570 if (size_is == sizeof(guint16)) {
1571 /* XXX - use drep to determine the byte order? */
1572 s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
1574 * XXX - we don't support a string type with Unicode
1575 * characters, so if this is a string item, we make
1576 * its value be the "fake Unicode" string.
1578 if (tree && buffer_len) {
1579 hfinfo = proto_registrar_get_nth(hfindex);
1580 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1581 if (hfinfo->type == FT_STRING) {
1582 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1585 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1586 buffer_len, drep[0] & 0x10);
1591 * "tvb_get_ephemeral_string()" throws an exception if the entire string
1592 * isn't in the tvbuff. If the length is bogus, this should
1593 * keep us from trying to allocate an immensely large buffer.
1594 * (It won't help if the length is *valid* but immensely large,
1595 * but that's another matter; in any case, that would happen only
1596 * if we had an immensely large tvbuff....)
1598 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1599 s = tvb_get_ephemeral_string(tvb, offset, buffer_len);
1600 if (tree && buffer_len)
1601 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1602 buffer_len, drep[0] & 0x10);
1605 if (string_item != NULL)
1606 proto_item_append_text(string_item, ": %s", s);
1611 offset += buffer_len;
1613 proto_item_set_end(string_item, tvb, offset);
1618 /* Dissect an varying string of chars.
1619 This corresponds to IDL of the form '[string] char *foo'.
1621 XXX - at least according to the DCE RPC 1.1 spec, a string has
1622 a null terminator, which isn't necessary as a terminator for
1623 the transfer language (as there's a length), but is presumably
1624 there for the benefit of null-terminated-string languages
1625 such as C. Is this ever used for purely counted strings?
1626 (Not that it matters if it is.) */
1628 dissect_ndr_char_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1629 proto_tree *tree, guint8 *drep)
1632 di=pinfo->private_data;
1634 return dissect_ndr_vstring(tvb, offset, pinfo, tree, drep,
1635 sizeof(guint8), di->hf_index,
1639 /* Dissect a varying string of wchars (wide characters).
1640 This corresponds to IDL of the form '[string] wchar *foo'
1642 XXX - at least according to the DCE RPC 1.1 spec, a string has
1643 a null terminator, which isn't necessary as a terminator for
1644 the transfer language (as there's a length), but is presumably
1645 there for the benefit of null-terminated-string languages
1646 such as C. Is this ever used for purely counted strings?
1647 (Not that it matters if it is.) */
1649 dissect_ndr_wchar_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1650 proto_tree *tree, guint8 *drep)
1653 di=pinfo->private_data;
1655 return dissect_ndr_vstring(tvb, offset, pinfo, tree, drep,
1656 sizeof(guint16), di->hf_index,
1661 /* ndr pointer handling */
1662 /* list of pointers encountered so far */
1663 static GSList *ndr_pointer_list = NULL;
1665 /* position where in the list to insert newly encountered pointers */
1666 static int ndr_pointer_list_pos=0;
1668 /* boolean controlling whether pointers are top-level or embedded */
1669 static gboolean pointers_are_top_level = TRUE;
1671 /* as a kludge, we represent all embedded reference pointers as id==-1
1672 hoping that his will not collide with any non-ref pointers */
1673 typedef struct ndr_pointer_data {
1675 proto_item *item; /* proto_item for pointer */
1676 proto_tree *tree; /* subtree of above item */
1677 dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
1679 dcerpc_callback_fnct_t *callback;
1680 void *callback_args;
1681 } ndr_pointer_data_t;
1684 init_ndr_pointer_list(packet_info *pinfo)
1688 di=pinfo->private_data;
1689 di->conformant_run=0;
1691 while(ndr_pointer_list){
1692 ndr_pointer_data_t *npd;
1694 npd=g_slist_nth_data(ndr_pointer_list, 0);
1695 ndr_pointer_list=g_slist_remove(ndr_pointer_list, npd);
1699 ndr_pointer_list=NULL;
1700 ndr_pointer_list_pos=0;
1701 pointers_are_top_level=TRUE;
1705 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, guint8 *drep)
1707 int found_new_pointer;
1713 di=pinfo->private_data;
1717 found_new_pointer=0;
1718 len=g_slist_length(ndr_pointer_list);
1719 for(i=next_pointer;i<len;i++){
1720 ndr_pointer_data_t *tnpd;
1721 tnpd=g_slist_nth_data(ndr_pointer_list, i);
1723 dcerpc_dissect_fnct_t *fnct;
1726 found_new_pointer=1;
1729 ndr_pointer_list_pos=i+1;
1730 di->hf_index=tnpd->hf_index;
1731 /* first a run to handle any conformant
1733 di->conformant_run=1;
1734 di->conformant_eaten=0;
1735 old_offset = offset;
1736 offset = (*(fnct))(tvb, offset, pinfo, NULL, drep);
1738 DISSECTOR_ASSERT((offset-old_offset)==di->conformant_eaten);
1739 /* This is to check for any bugs in the dissectors.
1741 * Basically, the NDR representation will store all
1742 * arrays in two blocks, one block with the dimension
1743 * discreption, like size, number of elements and such,
1744 * and another block that contains the actual data stored
1746 * If the array is embedded directly inside another,
1747 * encapsulating aggregate type, like a union or struct,
1748 * then these two blocks will be stored at different places
1749 * in the bytestream, with other data between the blocks.
1751 * For this reason, all pointers to types (both aggregate
1752 * and scalar, for simplicity no distinction is made)
1753 * will have its dissector called twice.
1754 * The dissector will first be called with conformant_run==1
1755 * in which mode the dissector MUST NOT consume any data from
1756 * the tvbuff (i.e. may not dissect anything) except the
1757 * initial control block for arrays.
1758 * The second time the dissector is called, with
1759 * conformant_run==0, all other data for the type will be
1762 * All dissect_ndr_<type> dissectors are already prepared
1763 * for this and knows when it should eat data from the tvb
1764 * and when not to, so implementors of dissectors will
1765 * normally not need to worry about this or even know about
1766 * it. However, if a dissector for an aggregate type calls
1767 * a subdissector from outside packet-dcerpc.c, such as
1768 * the dissector in packet-smb.c for NT Security Descriptors
1769 * as an example, then it is VERY important to encapsulate
1770 * this call to an external subdissector with the appropriate
1771 * test for conformant_run, i.e. it will need something like
1775 * di=pinfo->private_data;
1776 * if(di->conformant_run){
1780 * to make sure it makes the right thing.
1781 * This assert will signal when someone has forgotten to
1782 * make the dissector aware of this requirement.
1785 /* now we dissect the actual pointer */
1786 di->conformant_run=0;
1787 old_offset = offset;
1788 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, drep);
1790 tnpd->callback(pinfo, tnpd->tree, tnpd->item, tvb, old_offset, offset, tnpd->callback_args);
1794 } while(found_new_pointer);
1801 add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
1802 dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index,
1803 dcerpc_callback_fnct_t *callback, void *callback_args)
1805 ndr_pointer_data_t *npd;
1807 /* check if this pointer is valid */
1810 dcerpc_call_value *value;
1812 di=pinfo->private_data;
1813 value=di->call_data;
1815 if(di->ptype == PDU_REQ){
1816 if(!(pinfo->fd->flags.visited)){
1817 if(id>value->max_ptr){
1822 /* if we havent seen the request bail out since we cant
1823 know whether this is the first non-NULL instance
1825 if(value->req_frame==0){
1826 /* XXX THROW EXCEPTION */
1829 /* We saw this one in the request frame, nothing to
1831 if(id<=value->max_ptr){
1837 npd=g_malloc(sizeof(ndr_pointer_data_t));
1842 npd->hf_index=hf_index;
1843 npd->callback=callback;
1844 npd->callback_args=callback_args;
1845 ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
1846 ndr_pointer_list_pos);
1847 ndr_pointer_list_pos++;
1852 find_pointer_index(guint32 id)
1854 ndr_pointer_data_t *npd;
1857 len=g_slist_length(ndr_pointer_list);
1859 npd=g_slist_nth_data(ndr_pointer_list, i);
1870 /* This function dissects an NDR pointer and stores the callback for later
1871 * deferred dissection.
1873 * fnct is the callback function for when we have reached this object in
1876 * type is what type of pointer.
1878 * this is text is what text we should put in any created tree node.
1880 * hf_index is what hf value we want to pass to the callback function when
1881 * it is called, the callback can later pich this one up from di->hf_index.
1883 * callback is executed after the pointer has been dereferenced.
1885 * callback_args is passed as an argument to the callback function
1887 * See packet-dcerpc-samr.c for examples
1890 dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1891 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
1892 int type, const char *text, int hf_index,
1893 dcerpc_callback_fnct_t *callback, void *callback_args)
1896 proto_tree *tr = NULL;
1897 gint start_offset = offset;
1899 di=pinfo->private_data;
1900 if(di->conformant_run){
1901 /* this call was only for dissecting the header for any
1902 embedded conformant array. we will not parse any
1903 pointers in this mode.
1907 /*TOP LEVEL REFERENCE POINTER*/
1908 if( pointers_are_top_level
1909 &&(type==NDR_POINTER_REF) ){
1912 /* we must find out a nice way to do the length here */
1913 item=proto_tree_add_text(tree, tvb, offset, 0,
1915 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1917 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1918 hf_index, callback, callback_args);
1922 /*TOP LEVEL FULL POINTER*/
1923 if( pointers_are_top_level
1924 && (type==NDR_POINTER_PTR) ){
1929 /* get the referent id */
1930 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1932 tvb_ensure_bytes_exist(tvb, offset-4, 4);
1933 /* we got a NULL pointer */
1935 proto_tree_add_text(tree, tvb, offset-4, 4,
1936 "(NULL pointer) %s",text);
1940 /* see if we have seen this pointer before */
1941 idx=find_pointer_index(id);
1943 /* we have seen this pointer before */
1945 proto_tree_add_text(tree, tvb, offset-4, 4,
1946 "(duplicate PTR) %s",text);
1951 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1953 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1954 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1955 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
1956 callback, callback_args);
1959 /*TOP LEVEL UNIQUE POINTER*/
1960 if( pointers_are_top_level
1961 && (type==NDR_POINTER_UNIQUE) ){
1965 /* get the referent id */
1966 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1968 tvb_ensure_bytes_exist(tvb, offset-4, 4);
1969 /* we got a NULL pointer */
1971 proto_tree_add_text(tree, tvb, offset-4, 4,
1972 "(NULL pointer) %s",text);
1977 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1979 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1980 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1981 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1982 hf_index, callback, callback_args);
1986 /*EMBEDDED REFERENCE POINTER*/
1987 if( (!pointers_are_top_level)
1988 && (type==NDR_POINTER_REF) ){
1992 /* get the referent id */
1993 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1995 tvb_ensure_bytes_exist(tvb, offset-4, 4);
1997 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1999 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2000 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
2001 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
2002 hf_index, callback, callback_args);
2006 /*EMBEDDED UNIQUE POINTER*/
2007 if( (!pointers_are_top_level)
2008 && (type==NDR_POINTER_UNIQUE) ){
2012 /* get the referent id */
2013 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
2015 tvb_ensure_bytes_exist(tvb, offset-4, 4);
2016 /* we got a NULL pointer */
2018 proto_tree_add_text(tree, tvb, offset-4, 4,
2019 "(NULL pointer) %s", text);
2024 item=proto_tree_add_text(tree, tvb, offset-4, 4,
2026 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2027 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
2028 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
2029 hf_index, callback, callback_args);
2033 /*EMBEDDED FULL POINTER*/
2034 if( (!pointers_are_top_level)
2035 && (type==NDR_POINTER_PTR) ){
2040 /* get the referent id */
2041 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
2042 tvb_ensure_bytes_exist(tvb, offset-4, 4);
2043 /* we got a NULL pointer */
2045 proto_tree_add_text(tree, tvb, offset-4, 4,
2046 "(NULL pointer) %s",text);
2050 /* see if we have seen this pointer before */
2051 idx=find_pointer_index(id);
2053 /* we have seen this pointer before */
2055 proto_tree_add_text(tree, tvb, offset-4, 4,
2056 "(duplicate PTR) %s",text);
2061 item=proto_tree_add_text(tree, tvb, offset-4, 4,
2063 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2064 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
2065 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
2066 callback, callback_args);
2072 /* After each top level pointer we have dissected we have to
2073 dissect all deferrals before we move on to the next top level
2075 if(pointers_are_top_level==TRUE){
2076 pointers_are_top_level=FALSE;
2077 offset = dissect_deferred_pointers(pinfo, tvb, offset, drep);
2078 pointers_are_top_level=TRUE;
2081 /* Set the length for the new subtree */
2083 proto_item_set_len(tr, offset-start_offset);
2089 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2090 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2091 int type, const char *text, int hf_index)
2093 return dissect_ndr_pointer_cb(
2094 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
2098 dissect_ndr_toplevel_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2099 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2100 int type, const char *text, int hf_index)
2104 pointers_are_top_level=TRUE;
2105 ret=dissect_ndr_pointer_cb(
2106 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
2111 dissect_ndr_embedded_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2112 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2113 int type, const char *text, int hf_index)
2117 pointers_are_top_level=FALSE;
2118 ret=dissect_ndr_pointer_cb(
2119 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
2125 show_stub_data (tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
2126 dcerpc_auth_info *auth_info, gboolean is_encrypted)
2128 int length, plain_length, auth_pad_len;
2129 guint auth_pad_offset;
2132 * We don't show stub data unless we have some in the tvbuff;
2133 * however, in the protocol tree, we show, as the number of
2134 * bytes, the reported number of bytes, not the number of bytes
2135 * that happen to be in the tvbuff.
2137 if (tvb_length_remaining (tvb, offset) > 0) {
2138 auth_pad_len = auth_info?auth_info->auth_pad_len:0;
2139 length = tvb_reported_length_remaining (tvb, offset);
2141 /* if auth_pad_len is larger than length then we ignore auth_pad_len totally */
2142 plain_length = length - auth_pad_len;
2143 if (plain_length < 1) {
2144 plain_length = length;
2147 auth_pad_offset = offset + plain_length;
2148 if (auth_info != NULL &&
2149 auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
2151 tvb_ensure_bytes_exist(tvb, offset, length);
2152 proto_tree_add_text(dcerpc_tree, tvb, offset, length,
2153 "Encrypted stub data (%d byte%s)",
2154 length, plurality(length, "", "s"));
2155 /* is the padding is still inside the encrypted blob, don't display it explicit */
2159 tvb_ensure_bytes_exist(tvb, offset, plain_length);
2160 proto_tree_add_text(dcerpc_tree, tvb, offset, plain_length,
2161 "Decrypted stub data (%d byte%s)",
2162 plain_length, plurality(plain_length, "", "s"));
2166 tvb_ensure_bytes_exist(tvb, offset, plain_length);
2167 proto_tree_add_text (dcerpc_tree, tvb, offset, plain_length,
2168 "Stub data (%d byte%s)", plain_length,
2169 plurality(plain_length, "", "s"));
2171 /* If there is auth padding at the end of the stub, display it */
2172 if (auth_pad_len != 0) {
2173 tvb_ensure_bytes_exist(tvb, auth_pad_offset, auth_pad_len);
2174 proto_tree_add_text (dcerpc_tree, tvb, auth_pad_offset,
2175 auth_pad_len, "Auth Padding (%u byte%s)",
2176 auth_pad_len, plurality(auth_pad_len, "", "s"));
2182 dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
2183 proto_tree *dcerpc_tree,
2184 tvbuff_t *volatile tvb, tvbuff_t *decrypted_tvb,
2185 guint8 *drep, dcerpc_info *info,
2186 dcerpc_auth_info *auth_info)
2188 volatile gint offset = 0;
2189 dcerpc_uuid_key key;
2190 dcerpc_uuid_value *sub_proto;
2191 proto_tree *volatile sub_tree = NULL;
2192 dcerpc_sub_dissector *proc;
2193 const gchar *name = NULL;
2194 dcerpc_dissect_fnct_t *volatile sub_dissect;
2195 const char *volatile saved_proto;
2196 void *volatile saved_private_data;
2197 guint length = 0, reported_length = 0;
2198 tvbuff_t *volatile stub_tvb;
2199 volatile guint auth_pad_len;
2200 volatile int auth_pad_offset;
2201 proto_item *sub_item=NULL;
2202 proto_item *pi, *hidden_item;
2204 key.uuid = info->call_data->uuid;
2205 key.ver = info->call_data->ver;
2208 if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == NULL
2209 || !proto_is_protocol_enabled(sub_proto->proto)) {
2211 * We don't have a dissector for this UUID, or the protocol
2212 * for that UUID is disabled.
2215 hidden_item = proto_tree_add_boolean(dcerpc_tree, hf_dcerpc_unknown_if_id,
2216 tvb, offset, 0, TRUE);
2217 PROTO_ITEM_SET_HIDDEN(hidden_item);
2218 if (check_col (pinfo->cinfo, COL_INFO)) {
2219 col_append_fstr (pinfo->cinfo, COL_INFO, " %s V%u",
2220 guids_resolve_uuid_to_str(&info->call_data->uuid), info->call_data->ver);
2223 if (decrypted_tvb != NULL) {
2224 show_stub_data (decrypted_tvb, 0, dcerpc_tree, auth_info,
2227 show_stub_data (tvb, 0, dcerpc_tree, auth_info, TRUE);
2231 for (proc = sub_proto->procs; proc->name; proc++) {
2232 if (proc->num == info->call_data->opnum) {
2241 if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
2242 col_set_str (pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
2245 if (check_col (pinfo->cinfo, COL_INFO)) {
2246 col_add_fstr (pinfo->cinfo, COL_INFO, "%s %s",
2247 name, (info->ptype == PDU_REQ) ? "request" : "response");
2250 sub_dissect = (info->ptype == PDU_REQ) ?
2251 proc->dissect_rqst : proc->dissect_resp;
2254 sub_item = proto_tree_add_item (tree, sub_proto->proto_id,
2255 (decrypted_tvb != NULL)?decrypted_tvb:tvb,
2259 sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
2260 proto_item_append_text(sub_item, ", %s", name);
2264 * Put the operation number into the tree along with
2265 * the operation's name.
2267 if (sub_proto->opnum_hf != -1)
2268 proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
2269 tvb, 0, 0, info->call_data->opnum,
2270 "Operation: %s (%u)",
2271 name, info->call_data->opnum);
2273 proto_tree_add_uint_format(sub_tree, hf_dcerpc_op, tvb,
2274 0, 0, info->call_data->opnum,
2275 "Operation: %s (%u)",
2276 name, info->call_data->opnum);
2278 if(info->ptype == PDU_REQ && info->call_data->rep_frame!=0) {
2279 pi = proto_tree_add_uint(sub_tree, hf_dcerpc_response_in,
2280 tvb, 0, 0, info->call_data->rep_frame);
2281 PROTO_ITEM_SET_GENERATED(pi);
2283 if(info->ptype == PDU_RESP && info->call_data->req_frame!=0) {
2284 pi = proto_tree_add_uint(sub_tree, hf_dcerpc_request_in,
2285 tvb, 0, 0, info->call_data->req_frame);
2286 PROTO_ITEM_SET_GENERATED(pi);
2290 if (decrypted_tvb != NULL) {
2291 /* Either there was no encryption or we successfully decrypted
2292 the encrypted payload. */
2294 /* We have a subdissector - call it. */
2295 saved_proto = pinfo->current_proto;
2296 saved_private_data = pinfo->private_data;
2297 pinfo->current_proto = sub_proto->name;
2298 pinfo->private_data = (void *)info;
2300 init_ndr_pointer_list(pinfo);
2302 length = tvb_length(decrypted_tvb);
2303 reported_length = tvb_reported_length(decrypted_tvb);
2306 * Remove the authentication padding from the stub data.
2308 if (auth_info != NULL && auth_info->auth_pad_len != 0) {
2309 if (reported_length >= auth_info->auth_pad_len) {
2311 * OK, the padding length isn't so big that it
2312 * exceeds the stub length. Trim the reported
2313 * length of the tvbuff.
2315 reported_length -= auth_info->auth_pad_len;
2318 * If that exceeds the actual amount of data in
2319 * the tvbuff (which means we have at least one
2320 * byte of authentication padding in the tvbuff),
2321 * trim the actual amount.
2323 if (length > reported_length)
2324 length = reported_length;
2326 stub_tvb = tvb_new_subset(decrypted_tvb, 0, length, reported_length);
2327 auth_pad_len = auth_info->auth_pad_len;
2328 auth_pad_offset = reported_length;
2331 * The padding length exceeds the stub length.
2332 * Don't bother dissecting the stub, trim the padding
2333 * length to what's in the stub data, and show the
2334 * entire stub as authentication padding.
2337 auth_pad_len = reported_length;
2338 auth_pad_offset = 0;
2340 reported_length = 0;
2344 * No authentication padding.
2346 stub_tvb = decrypted_tvb;
2348 auth_pad_offset = 0;
2352 proto_item_set_len(sub_item, length);
2355 if (stub_tvb != NULL) {
2357 * Catch all exceptions other than BoundsError, so that even
2358 * if the stub data is bad, we still show the authentication
2361 * If we get BoundsError, it means the frame was cut short
2362 * by a snapshot length, so there's nothing more to
2363 * dissect; just re-throw that exception.
2368 offset = sub_dissect (stub_tvb, 0, pinfo, sub_tree,
2371 /* If we have a subdissector and it didn't dissect all
2372 data in the tvb, make a note of it. */
2373 remaining = tvb_reported_length_remaining(stub_tvb, offset);
2374 if (remaining > 0) {
2375 proto_tree_add_text(sub_tree, stub_tvb, offset,
2377 "[Long frame (%d byte%s)]",
2379 plurality(remaining, "", "s"));
2380 if (check_col(pinfo->cinfo, COL_INFO))
2381 col_append_fstr(pinfo->cinfo, COL_INFO,
2382 "[Long frame (%d byte%s)]",
2384 plurality(remaining, "", "s"));
2387 } CATCH(BoundsError) {
2390 show_exception(stub_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
2394 /* If there is auth padding at the end of the stub, display it */
2395 if (auth_pad_len != 0) {
2396 tvb_ensure_bytes_exist(tvb, auth_pad_offset, auth_pad_len);
2397 proto_tree_add_text (sub_tree, decrypted_tvb, auth_pad_offset,
2399 "Auth Padding (%u byte%s)",
2401 plurality(auth_pad_len, "", "s"));
2404 pinfo->current_proto = saved_proto;
2405 pinfo->private_data = saved_private_data;
2407 /* No subdissector - show it as stub data. */
2409 show_stub_data (decrypted_tvb, 0, sub_tree, auth_info, FALSE);
2411 show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
2415 show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
2417 tap_queue_packet(dcerpc_tap, pinfo, info);
2422 dissect_dcerpc_verifier (tvbuff_t *tvb, packet_info *pinfo,
2423 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
2424 dcerpc_auth_info *auth_info)
2428 auth_info->auth_data = NULL;
2430 if (auth_info->auth_size != 0) {
2431 dcerpc_auth_subdissector_fns *auth_fns;
2434 auth_offset = hdr->frag_len - hdr->auth_len;
2436 auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
2439 auth_info->auth_data = auth_tvb;
2441 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
2442 auth_info->auth_type))) {
2444 * Catch all exceptions, so that even if the verifier is bad
2445 * or we don't have all of it, we still show the stub data.
2448 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
2451 show_exception(auth_tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
2454 tvb_ensure_bytes_exist(tvb, 0, hdr->auth_len);
2455 proto_tree_add_text (dcerpc_tree, auth_tvb, 0, hdr->auth_len,
2460 return hdr->auth_len;
2464 dissect_dcerpc_cn_auth (tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
2465 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
2466 gboolean are_credentials, dcerpc_auth_info *auth_info)
2468 volatile int offset;
2471 * Initially set auth_level and auth_type to zero to indicate that we
2472 * haven't yet seen any authentication level information.
2474 auth_info->auth_level = 0;
2475 auth_info->auth_type = 0;
2476 auth_info->auth_size = 0;
2477 auth_info->auth_pad_len = 0;
2480 * The authentication information is at the *end* of the PDU; in
2481 * request and response PDUs, the request and response stub data
2484 * Is there any authentication data (i.e., is the authentication length
2485 * non-zero), and is the authentication length valid (i.e., is it, plus
2486 * 8 bytes for the type/level/pad length/reserved/context id, less than
2487 * or equal to the fragment length minus the starting offset of the
2492 && (hdr->auth_len + 8 <= hdr->frag_len - stub_offset)) {
2495 * Yes, there is authentication data, and the length is valid.
2496 * Do we have all the bytes of stub data?
2497 * (If not, we'd throw an exception dissecting *that*, so don't
2498 * bother trying to dissect the authentication information and
2499 * throwing another exception there.)
2501 offset = hdr->frag_len - (hdr->auth_len + 8);
2502 if (offset == 0 || tvb_offset_exists(tvb, offset - 1)) {
2504 * Either there's no stub data, or the last byte of the stub
2505 * data is present in the captured data, so we shouldn't
2506 * get a BoundsError dissecting the stub data.
2508 * Try dissecting the authentication data.
2509 * Catch all exceptions, so that even if the auth info is bad
2510 * or we don't have all of it, we still show the stuff we
2511 * dissect after this, such as stub data.
2514 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2515 hf_dcerpc_auth_type,
2516 &auth_info->auth_type);
2517 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2518 hf_dcerpc_auth_level,
2519 &auth_info->auth_level);
2521 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2522 hf_dcerpc_auth_pad_len,
2523 &auth_info->auth_pad_len);
2524 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2525 hf_dcerpc_auth_rsrvd, NULL);
2526 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2527 hf_dcerpc_auth_ctx_id, NULL);
2530 * Dissect the authentication data.
2532 if (are_credentials) {
2534 dcerpc_auth_subdissector_fns *auth_fns;
2536 auth_tvb = tvb_new_subset(tvb, offset,
2537 MIN(hdr->auth_len,tvb_length_remaining(tvb, offset)),
2540 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
2541 auth_info->auth_type)))
2542 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
2545 proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len,
2546 "Auth Credentials");
2549 /* Compute the size of the auth block. Note that this should not
2550 include auth padding, since when NTLMSSP encryption is used, the
2551 padding is actually inside the encrypted stub */
2552 auth_info->auth_size = hdr->auth_len + 8;
2554 show_exception(tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
2561 /* We need to hash in the SMB fid number to generate a unique hash table
2562 * key as DCERPC over SMB allows several pipes over the same TCP/IP
2564 * We pass this function the transport type here to make sure we only look
2565 * at this function if it came across an SMB pipe.
2566 * Other transports might need to mix in their own extra multiplexing data
2567 * as well in the future.
2570 guint16 dcerpc_get_transport_salt (packet_info *pinfo)
2572 switch(pinfo->dcetransporttype){
2573 case DCE_CN_TRANSPORT_SMBPIPE:
2574 /* DCERPC over smb */
2575 return pinfo->dcetransportsalt;
2578 /* Some other transport... */
2583 * Connection oriented packet types
2587 dissect_dcerpc_cn_bind (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2588 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2590 conversation_t *conv = NULL;
2591 guint8 num_ctx_items = 0;
2593 gboolean saw_ctx_item = FALSE;
2595 guint8 num_trans_items;
2600 guint16 if_ver, if_ver_minor;
2601 dcerpc_auth_info auth_info;
2603 const char *uuid_name = NULL;
2604 proto_item *iface_item = NULL;
2606 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2607 hf_dcerpc_cn_max_xmit, NULL);
2609 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2610 hf_dcerpc_cn_max_recv, NULL);
2612 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2613 hf_dcerpc_cn_assoc_group, NULL);
2615 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2616 hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
2621 for (i = 0; i < num_ctx_items; i++) {
2622 proto_item *ctx_item = NULL;
2623 proto_tree *ctx_tree = NULL, *iface_tree = NULL;
2624 gint ctx_offset = offset;
2626 dissect_dcerpc_uint16 (tvb, offset, pinfo, NULL, hdr->drep,
2627 hf_dcerpc_cn_ctx_id, &ctx_id);
2629 if (check_col (pinfo->cinfo, COL_DCE_CTX)) {
2630 if(pinfo->dcectxid == 0) {
2631 col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "%u", ctx_id);
2633 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
2634 * prepend a delimiter */
2635 col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "#%u", ctx_id);
2639 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
2640 /* (if we have multiple contexts, this might cause "decode as"
2641 * to behave unpredictably) */
2642 pinfo->dcectxid = ctx_id;
2645 ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_item,
2647 hdr->drep[0] & 0x10);
2648 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
2651 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, ctx_tree, hdr->drep,
2652 hf_dcerpc_cn_ctx_id, &ctx_id);
2653 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, ctx_tree, hdr->drep,
2654 hf_dcerpc_cn_num_trans_items, &num_trans_items);
2657 proto_item_append_text(ctx_item, "[%u]: ID:%u", i+1, ctx_id);
2663 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
2666 iface_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_abstract_syntax, tvb, offset, 0, FALSE);
2667 iface_tree = proto_item_add_subtree(iface_item, ett_dcerpc_cn_iface);
2669 uuid_str = guid_to_str((e_guid_t*)&if_id);
2670 uuid_name = guids_get_uuid_name(&if_id);
2672 proto_tree_add_guid_format (iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
2673 offset, 16, (e_guid_t *) &if_id, "Interface: %s UUID: %s", uuid_name, uuid_str);
2674 proto_item_append_text(iface_item, ": %s", uuid_name);
2676 proto_tree_add_guid_format (iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
2677 offset, 16, (e_guid_t *) &if_id, "Interface UUID: %s", uuid_str);
2678 proto_item_append_text(iface_item, ": %s", uuid_str);
2683 if (hdr->drep[0] & 0x10) {
2684 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2685 hf_dcerpc_cn_bind_if_ver, &if_ver);
2686 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2687 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2689 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2690 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2691 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2692 hf_dcerpc_cn_bind_if_ver, &if_ver);
2696 proto_item_append_text(iface_item, " V%u.%u", if_ver, if_ver_minor);
2697 proto_item_set_len(iface_item, 20);
2700 if (!saw_ctx_item) {
2701 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
2702 pinfo->srcport, pinfo->destport, 0);
2704 fprintf(stderr,"Creating a new conv on packet %d\n",pinfo->fd->num);
2705 conv = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
2706 pinfo->srcport, pinfo->destport, 0);
2710 /* if this is the first time we see this packet, we need to
2711 update the dcerpc_binds table so that any later calls can
2712 match to the interface.
2713 XXX We assume that BINDs will NEVER be fragmented.
2715 if(!(pinfo->fd->flags.visited)){
2716 dcerpc_bind_key *key;
2717 dcerpc_bind_value *value;
2719 key = se_alloc (sizeof (dcerpc_bind_key));
2721 key->ctx_id = ctx_id;
2722 key->smb_fid = dcerpc_get_transport_salt(pinfo);
2724 value = se_alloc (sizeof (dcerpc_bind_value));
2725 value->uuid = if_id;
2726 value->ver = if_ver;
2728 /* add this entry to the bind table, first removing any
2729 previous ones that are identical
2731 if(g_hash_table_lookup(dcerpc_binds, key)){
2732 g_hash_table_remove(dcerpc_binds, key);
2734 g_hash_table_insert (dcerpc_binds, key, value);
2737 if (check_col (pinfo->cinfo, COL_INFO)) {
2738 if (num_ctx_items > 1)
2739 col_append_fstr(pinfo->cinfo, COL_INFO, ", %u context items, 1st", num_ctx_items);
2741 col_append_fstr(pinfo->cinfo, COL_INFO, " %s V%u.%u",
2742 guids_resolve_uuid_to_str(&if_id), if_ver, if_ver_minor);
2744 saw_ctx_item = TRUE;
2747 for (j = 0; j < num_trans_items; j++) {
2748 proto_tree *trans_tree = NULL;
2749 proto_item *trans_item = NULL;
2751 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2754 trans_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_trans_syntax, tvb, offset, 0, FALSE);
2755 trans_tree = proto_item_add_subtree(trans_item, ett_dcerpc_cn_trans_syntax);
2757 uuid_str = guid_to_str((e_guid_t *) &trans_id);
2758 proto_tree_add_guid_format (trans_tree, hf_dcerpc_cn_bind_trans_id, tvb,
2759 offset, 16, (e_guid_t *) &trans_id, "Transfer Syntax: %s", uuid_str);
2760 proto_item_append_text(trans_item, "[%u]: %s", j+1, uuid_str);
2764 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, trans_tree, hdr->drep,
2765 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
2767 proto_item_set_len(trans_item, 20);
2768 proto_item_append_text(trans_item, " V%u", trans_ver);
2773 proto_item_set_len(ctx_item, offset - ctx_offset);
2778 * XXX - we should save the authentication type *if* we have
2779 * an authentication header, and associate it with an authentication
2780 * context, so subsequent PDUs can use that context.
2782 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2786 dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2787 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2789 guint16 max_xmit, max_recv;
2790 guint16 sec_addr_len;
2797 dcerpc_auth_info auth_info;
2799 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2800 hf_dcerpc_cn_max_xmit, &max_xmit);
2802 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2803 hf_dcerpc_cn_max_recv, &max_recv);
2805 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2806 hf_dcerpc_cn_assoc_group, NULL);
2808 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2809 hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
2810 if (sec_addr_len != 0) {
2811 tvb_ensure_bytes_exist(tvb, offset, sec_addr_len);
2812 proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
2813 sec_addr_len, FALSE);
2814 offset += sec_addr_len;
2818 offset += 4 - offset % 4;
2821 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2822 hf_dcerpc_cn_num_results, &num_results);
2827 for (i = 0; i < num_results; i++) {
2828 proto_tree *ctx_tree = NULL;
2831 proto_item *ctx_item;
2832 ctx_item = proto_tree_add_text(dcerpc_tree, tvb, offset, 24, "Context ID[%u]", i+1);
2833 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
2836 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, ctx_tree,
2837 hdr->drep, hf_dcerpc_cn_ack_result,
2840 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, ctx_tree,
2841 hdr->drep, hf_dcerpc_cn_ack_reason,
2845 * The reason for rejection isn't meaningful, and often isn't
2846 * set, when the syntax was accepted.
2851 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2853 proto_tree_add_guid_format (ctx_tree, hf_dcerpc_cn_ack_trans_id, tvb,
2854 offset, 16, (e_guid_t *) &trans_id, "Transfer Syntax: %s",
2855 guid_to_str((e_guid_t *) &trans_id));
2859 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, ctx_tree, hdr->drep,
2860 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
2864 * XXX - do we need to do anything with the authentication level
2865 * we get back from this?
2867 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2869 if (check_col (pinfo->cinfo, COL_INFO)) {
2870 if (num_results != 0 && result == 0) {
2871 /* XXX - only checks the last result */
2872 col_append_fstr (pinfo->cinfo, COL_INFO,
2873 " accept max_xmit: %u max_recv: %u",
2874 max_xmit, max_recv);
2876 /* XXX - only shows the last result and reason */
2877 col_append_fstr (pinfo->cinfo, COL_INFO, " %s, reason: %s",
2878 val_to_str(result, p_cont_result_vals,
2879 "Unknown result (%u)"),
2880 val_to_str(reason, p_provider_reason_vals,
2887 dissect_dcerpc_cn_bind_nak (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2888 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2891 guint8 num_protocols;
2894 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2895 hdr->drep, hf_dcerpc_cn_reject_reason,
2898 if (check_col (pinfo->cinfo, COL_INFO)) {
2899 col_append_fstr (pinfo->cinfo, COL_INFO, " reason: %s",
2900 val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
2903 if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
2904 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2905 hf_dcerpc_cn_num_protocols,
2908 for (i = 0; i < num_protocols; i++) {
2909 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2910 hdr->drep, hf_dcerpc_cn_protocol_ver_major,
2912 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2913 hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
2919 /* Return a string describing a DCE/RPC fragment as first, middle, or end
2922 #define PFC_FRAG_MASK 0x03
2925 fragment_type(guint8 flags)
2927 flags = flags & PFC_FRAG_MASK;
2929 if (flags == PFC_FIRST_FRAG)
2935 if (flags == PFC_LAST_FRAG)
2938 if (flags == (PFC_FIRST_FRAG | PFC_LAST_FRAG))
2944 /* Dissect stub data (payload) of a DCERPC packet. */
2947 dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
2948 proto_tree *dcerpc_tree, proto_tree *tree,
2949 e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
2950 dcerpc_auth_info *auth_info, guint32 alloc_hint _U_,
2953 gint length, reported_length;
2954 gboolean save_fragmented;
2955 fragment_data *fd_head=NULL;
2957 tvbuff_t *auth_tvb, *payload_tvb, *decrypted_tvb;
2959 proto_item *parent_pi;
2960 proto_item *dcerpc_tree_item;
2962 save_fragmented = pinfo->fragmented;
2963 length = tvb_length_remaining(tvb, offset);
2964 reported_length = tvb_reported_length_remaining(tvb, offset);
2965 if (reported_length < 0 ||
2966 (guint32)reported_length < auth_info->auth_size) {
2967 /* We don't even have enough bytes for the authentication
2971 reported_length -= auth_info->auth_size;
2972 if (length > reported_length)
2973 length = reported_length;
2974 payload_tvb = tvb_new_subset(tvb, offset, length, reported_length);
2977 /*dont bother if we dont have the entire tvb */
2978 /*XXX we should really make sure we calculate auth_info->auth_data
2979 *and use that one instead of this auth_tvb hack
2981 if(tvb_length(tvb)==tvb_reported_length(tvb)){
2982 if(tvb_length_remaining(tvb, offset+length)>8){
2983 auth_tvb = tvb_new_subset(tvb, offset+length+8, -1, -1);
2987 /* Decrypt the PDU if it is encrypted */
2989 if (auth_info->auth_type &&
2990 auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
2992 * We know the authentication type, and the authentication
2993 * level is "Packet privacy", meaning the payload is
2994 * encrypted; attempt to decrypt it.
2996 dcerpc_auth_subdissector_fns *auth_fns;
2998 /* Start out assuming we won't succeed in decrypting. */
2999 decrypted_tvb = NULL;
3000 /* Schannel needs informations into the footer (verifier) in order to setup decryptions keys
3001 * so we call it in order to have a chance to decypher the data
3003 if (DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN == auth_info->auth_type) {
3004 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, auth_info);
3007 if ((auth_fns = get_auth_subdissector_fns(
3008 auth_info->auth_level, auth_info->auth_type))) {
3010 result = decode_encrypted_data( payload_tvb, auth_tvb, pinfo, auth_fns,
3011 hdr->ptype == PDU_REQ, auth_info);
3014 proto_tree_add_text(dcerpc_tree, payload_tvb, 0, -1,
3015 "Encrypted stub data (%d byte%s)",
3016 tvb_reported_length(payload_tvb),
3017 plurality(tvb_length(payload_tvb), "", "s"));
3019 add_new_data_source(pinfo, result, "Decrypted stub data");
3021 decrypted_tvb = result;
3026 decrypted_tvb = payload_tvb;
3028 /* if this packet is not fragmented, just dissect it and exit */
3029 if(PFC_NOT_FRAGMENTED(hdr)) {
3030 pinfo->fragmented = FALSE;
3032 dcerpc_try_handoff( pinfo, tree, dcerpc_tree, payload_tvb,
3033 decrypted_tvb, hdr->drep, di, auth_info);
3035 pinfo->fragmented = save_fragmented;
3039 /* The packet is fragmented. */
3040 pinfo->fragmented = TRUE;
3042 /* debug output of essential fragment data. */
3043 /* leave it here for future debugging sessions */
3044 /*printf("DCE num:%u offset:%u frag_len:%u tvb_len:%u\n",
3045 pinfo->fd->num, offset, hdr->frag_len, tvb_length(decrypted_tvb));*/
3047 /* if we are not doing reassembly and this is the first fragment
3048 then just dissect it and exit
3049 XXX - if we're not doing reassembly, can we decrypt an
3052 if( (!dcerpc_reassemble) && hdr->flags&PFC_FIRST_FRAG ){
3055 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
3056 hdr->drep, di, auth_info);
3058 if (check_col(pinfo->cinfo, COL_INFO)) {
3059 col_append_fstr(pinfo->cinfo, COL_INFO,
3060 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
3062 expert_add_info_format(pinfo, NULL, PI_REASSEMBLE, PI_CHAT,
3063 "%s fragment", fragment_type(hdr->flags));
3064 pinfo->fragmented = save_fragmented;
3068 /* if we have already seen this packet, see if it was reassembled
3069 and if so dissect the full pdu.
3072 if(pinfo->fd->flags.visited){
3073 fd_head=fragment_get_reassembled(pinfo, frame, dcerpc_co_reassemble_table);
3077 /* if we are not doing reassembly and it was neither a complete PDU
3078 nor the first fragment then there is nothing more we can do
3079 so we just have to exit
3081 if( !dcerpc_reassemble || (tvb_length(tvb)!=tvb_reported_length(tvb)) )
3084 /* if we didnt get 'frame' we dont know where the PDU started and thus
3085 it is pointless to continue
3090 /* from now on we must attempt to reassemble the PDU
3093 /* if we get here we know it is the first time we see the packet
3094 and we also know it is only a fragment and not a full PDU,
3095 thus we must reassemble it.
3098 /* Do we have any non-encrypted data to reassemble? */
3099 if (decrypted_tvb == NULL) {
3100 /* No. We can't even try to reassemble. */
3104 /* defragmentation is a bit tricky, as there's no offset of the fragment
3105 * in the protocol data.
3107 * just use fragment_add_seq_next() and hope that TCP/SMB segments coming
3108 * in with the correct sequence.
3110 fd_head = fragment_add_seq_next(decrypted_tvb, 0, pinfo, frame,
3111 dcerpc_co_fragment_table, dcerpc_co_reassemble_table,
3112 tvb_length(decrypted_tvb),
3113 hdr->flags&PFC_LAST_FRAG ? FALSE : TRUE /* more_frags */);
3117 /* if reassembly is complete and this is the last fragment
3118 * (multiple fragments in one PDU are possible!)
3119 * dissect the full PDU
3121 if(fd_head && (fd_head->flags&FD_DEFRAGMENTED) ){
3123 if(pinfo->fd->num==fd_head->reassembled_in && (hdr->flags&PFC_LAST_FRAG) ){
3125 proto_item *frag_tree_item;
3127 next_tvb = tvb_new_child_real_data((decrypted_tvb)?decrypted_tvb:payload_tvb,
3128 fd_head->data, fd_head->len, fd_head->len);
3130 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3131 show_fragment_tree(fd_head, &dcerpc_frag_items,
3132 tree, pinfo, next_tvb, &frag_tree_item);
3133 /* the toplevel fragment subtree is now behind all desegmented data,
3134 * move it right behind the DCE/RPC tree */
3135 dcerpc_tree_item = proto_tree_get_parent(dcerpc_tree);
3136 if(frag_tree_item && dcerpc_tree_item) {
3137 proto_tree_move_item(tree, dcerpc_tree_item, frag_tree_item);
3140 pinfo->fragmented = FALSE;
3142 expert_add_info_format(pinfo, frag_tree_item, PI_REASSEMBLE, PI_CHAT,
3143 "%s fragment, reassembled",
3144 fragment_type(hdr->flags));
3146 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
3147 next_tvb, hdr->drep, di, auth_info);
3151 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
3152 decrypted_tvb, 0, 0, fd_head->reassembled_in);
3154 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
3155 payload_tvb, 0, 0, fd_head->reassembled_in);
3157 PROTO_ITEM_SET_GENERATED(pi);
3158 parent_pi = proto_tree_get_parent(dcerpc_tree);
3159 if(parent_pi != NULL) {
3160 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
3162 if (check_col(pinfo->cinfo, COL_INFO)) {
3163 col_append_fstr(pinfo->cinfo, COL_INFO,
3164 " [DCE/RPC %s fragment, reas: #%u]", fragment_type(hdr->flags), fd_head->reassembled_in);
3166 expert_add_info_format(pinfo, NULL, PI_REASSEMBLE, PI_CHAT,
3167 "%s fragment, reassembled in #%u", fragment_type(hdr->flags), fd_head->reassembled_in);
3170 /* Reassembly not complete - some fragments
3171 are missing. Just show the stub data. */
3172 if (check_col(pinfo->cinfo, COL_INFO)) {
3173 col_append_fstr(pinfo->cinfo, COL_INFO,
3174 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
3176 expert_add_info_format(pinfo, NULL, PI_REASSEMBLE, PI_CHAT,
3177 "%s fragment", fragment_type(hdr->flags));
3180 show_stub_data (decrypted_tvb, 0, tree, auth_info, FALSE);
3182 show_stub_data (payload_tvb, 0, tree, auth_info, TRUE);
3186 pinfo->fragmented = save_fragmented;
3190 * Registers a conversation/UUID binding association, so that
3191 * we can invoke the proper sub-dissector for a given DCERPC
3194 * @param binding all values needed to create and bind a new conversation
3196 * @return Pointer to newly-added UUID/conversation binding.
3198 struct _dcerpc_bind_value *
3199 dcerpc_add_conv_to_bind_table(decode_dcerpc_bind_values_t *binding)
3201 dcerpc_bind_value *bind_value;
3202 dcerpc_bind_key *key;
3203 conversation_t *conv;
3205 conv = find_conversation (
3215 fprintf(stderr,"Creating a new conv on this bind packet \n");
3216 conv = conversation_new (
3226 bind_value = se_alloc (sizeof (dcerpc_bind_value));
3227 bind_value->uuid = binding->uuid;
3228 bind_value->ver = binding->ver;
3230 key = se_alloc(sizeof (dcerpc_bind_key));
3232 key->ctx_id = binding->ctx_id;
3233 key->smb_fid = binding->smb_fid;
3235 /* add this entry to the bind table, first removing any
3236 previous ones that are identical
3238 if(g_hash_table_lookup(dcerpc_binds, key)){
3239 g_hash_table_remove(dcerpc_binds, key);
3241 g_hash_table_insert(dcerpc_binds, key, bind_value);
3248 dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3249 proto_tree *dcerpc_tree, proto_tree *tree,
3250 e_dce_cn_common_hdr_t *hdr)
3252 conversation_t *conv;
3255 e_uuid_t obj_id = DCERPC_UUID_NULL;
3256 dcerpc_auth_info auth_info;
3259 proto_item *parent_pi;
3260 dcerpc_matched_key matched_key, *new_matched_key;
3261 dcerpc_call_value *value;
3263 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3264 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3266 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3267 hf_dcerpc_cn_ctx_id, &ctx_id);
3268 parent_pi = proto_tree_get_parent(dcerpc_tree);
3269 if(parent_pi != NULL) {
3270 proto_item_append_text(parent_pi, " Ctx: %u", ctx_id);
3273 if (check_col (pinfo->cinfo, COL_DCE_CTX)) {
3274 if(pinfo->dcectxid == 0) {
3275 col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "%u", ctx_id);
3277 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
3278 * prepend a delimiter */
3279 col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "#%u", ctx_id);
3282 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3283 hf_dcerpc_opnum, &opnum);
3285 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3286 pinfo->dcectxid = ctx_id;
3288 if (check_col (pinfo->cinfo, COL_INFO)) {
3289 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u ctx_id: %u",
3293 if (hdr->flags & PFC_OBJECT_UUID) {
3294 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id);
3296 proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
3297 offset, 16, (e_guid_t *) &obj_id, "Object UUID: %s",
3298 guid_to_str((e_guid_t *) &obj_id));
3304 * XXX - what if this was set when the connection was set up,
3305 * and we just have a security context?
3307 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3308 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3309 pinfo->srcport, pinfo->destport, 0);
3311 /*conv = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3312 pinfo->srcport, pinfo->destport, 0);*/
3313 fprintf(stderr,"No conv showing raw stuf %d \n",pinfo->fd->num);
3314 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3317 /* !!! we can NOT check flags.visited here since this will interact
3318 badly with when SMB handles (i.e. calls the subdissector)
3319 and desegmented pdu's .
3320 Instead we check if this pdu is already in the matched table or not
3322 matched_key.frame = pinfo->fd->num;
3323 matched_key.call_id = hdr->call_id;
3324 value = g_hash_table_lookup(dcerpc_matched, &matched_key);
3326 dcerpc_bind_key bind_key;
3327 dcerpc_bind_value *bind_value;
3330 bind_key.ctx_id=ctx_id;
3331 bind_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3332 if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key)) ){
3333 if(!(hdr->flags&PFC_FIRST_FRAG)){
3334 dcerpc_cn_call_key call_key;
3335 dcerpc_call_value *call_value;
3338 call_key.call_id=hdr->call_id;
3339 call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3340 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3341 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
3342 *new_matched_key = matched_key;
3343 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3348 dcerpc_cn_call_key *call_key;
3349 dcerpc_call_value *call_value;
3351 /* We found the binding and it is the first fragment
3352 (or a complete PDU) of a dcerpc pdu so just add
3353 the call to both the call table and the
3356 call_key=se_alloc (sizeof (dcerpc_cn_call_key));
3357 call_key->conv=conv;
3358 call_key->call_id=hdr->call_id;
3359 call_key->smb_fid=dcerpc_get_transport_salt(pinfo);
3361 /* if there is already a matching call in the table
3362 remove it so it is replaced with the new one */
3363 if(g_hash_table_lookup(dcerpc_cn_calls, call_key)){
3364 g_hash_table_remove(dcerpc_cn_calls, call_key);
3367 call_value=se_alloc (sizeof (dcerpc_call_value));
3368 call_value->uuid = bind_value->uuid;
3369 call_value->ver = bind_value->ver;
3370 call_value->object_uuid = obj_id;
3371 call_value->opnum = opnum;
3372 call_value->req_frame=pinfo->fd->num;
3373 call_value->req_time=pinfo->fd->abs_ts;
3374 call_value->rep_frame=0;
3375 call_value->max_ptr=0;
3376 call_value->se_data = NULL;
3377 call_value->private_data = NULL;
3378 call_value->pol = NULL;
3379 g_hash_table_insert (dcerpc_cn_calls, call_key, call_value);
3381 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
3382 *new_matched_key = matched_key;
3383 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3391 /* handoff this call */
3393 di->call_id = hdr->call_id;
3394 di->smb_fid = dcerpc_get_transport_salt(pinfo);
3395 di->ptype = PDU_REQ;
3396 di->call_data = value;
3399 if(value->rep_frame!=0){
3400 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
3401 tvb, 0, 0, value->rep_frame);
3402 PROTO_ITEM_SET_GENERATED(pi);
3403 if(parent_pi != NULL) {
3404 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
3407 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
3408 hdr, di, &auth_info, alloc_hint,
3412 /* no bind information, simply show stub data */
3413 pi = proto_tree_add_text(dcerpc_tree, tvb, offset, 0, "No bind info for this interface Context ID - capture start too late?");
3414 PROTO_ITEM_SET_GENERATED(pi);
3415 expert_add_info_format(pinfo, pi, PI_UNDECODED, PI_NOTE, "No bind info for interface Context ID:%u",
3417 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3420 /* Dissect the verifier */
3421 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
3426 dissect_dcerpc_cn_resp (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3427 proto_tree *dcerpc_tree, proto_tree *tree,
3428 e_dce_cn_common_hdr_t *hdr)
3430 dcerpc_call_value *value = NULL;
3431 conversation_t *conv;
3433 dcerpc_auth_info auth_info;
3436 proto_item *parent_pi;
3437 e_uuid_t obj_id_null = DCERPC_UUID_NULL;
3439 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3440 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3442 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3443 hf_dcerpc_cn_ctx_id, &ctx_id);
3444 parent_pi = proto_tree_get_parent(dcerpc_tree);
3445 if(parent_pi != NULL) {
3446 proto_item_append_text(parent_pi, " Ctx: %u", ctx_id);
3449 if (check_col (pinfo->cinfo, COL_DCE_CTX)) {
3450 if(pinfo->dcectxid == 0) {
3451 col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "%u", ctx_id);
3453 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
3454 * prepend a delimiter */
3455 col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "#%u", ctx_id);
3460 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3461 pinfo->dcectxid = ctx_id;
3463 if (check_col (pinfo->cinfo, COL_INFO)) {
3464 col_append_fstr (pinfo->cinfo, COL_INFO, " ctx_id: %u", ctx_id);
3467 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3468 hf_dcerpc_cn_cancel_count, NULL);
3473 * XXX - what if this was set when the connection was set up,
3474 * and we just have a security context?
3476 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3478 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3479 pinfo->srcport, pinfo->destport, 0);
3482 /* no point in creating one here, really */
3483 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3485 dcerpc_matched_key matched_key, *new_matched_key;
3487 /* !!! we can NOT check flags.visited here since this will interact
3488 badly with when SMB handles (i.e. calls the subdissector)
3489 and desegmented pdu's .
3490 Instead we check if this pdu is already in the matched table or not
3492 matched_key.frame = pinfo->fd->num;
3493 matched_key.call_id = hdr->call_id;
3494 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3496 dcerpc_cn_call_key call_key;
3497 dcerpc_call_value *call_value;
3500 call_key.call_id=hdr->call_id;
3501 call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3503 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3504 /* extra sanity check, only match them if the reply
3505 came after the request */
3506 if(call_value->req_frame<pinfo->fd->num){
3507 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
3508 *new_matched_key = matched_key;
3509 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3511 if(call_value->rep_frame==0) {
3512 call_value->rep_frame=pinfo->fd->num;
3522 /* handoff this call */
3524 di->call_id = hdr->call_id;
3525 di->smb_fid = dcerpc_get_transport_salt(pinfo);
3526 di->ptype = PDU_RESP;
3527 di->call_data = value;
3529 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
3531 /* (optional) "Object UUID" from request */
3532 if (value && dcerpc_tree && memcmp(&value->object_uuid, &obj_id_null, sizeof(obj_id_null)) != 0) {
3533 pi = proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
3534 offset, 0, (e_guid_t *) &value->object_uuid, "Object UUID: %s",
3535 guid_to_str((e_guid_t *) &value->object_uuid));
3536 PROTO_ITEM_SET_GENERATED(pi);
3540 if(value->req_frame!=0) {
3542 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3543 tvb, 0, 0, value->req_frame);
3544 PROTO_ITEM_SET_GENERATED(pi);
3545 if(parent_pi != NULL) {
3546 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
3548 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
3549 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
3550 PROTO_ITEM_SET_GENERATED(pi);
3552 pi = proto_tree_add_text(dcerpc_tree,
3553 tvb, 0, 0, "No request to this DCE/RPC call found");
3554 expert_add_info_format(pinfo, pi, PI_SEQUENCE, PI_NOTE,
3555 "No request to this DCE/RPC call found");
3558 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
3559 hdr, di, &auth_info, alloc_hint,value->rep_frame);
3561 /* no bind information, simply show stub data */
3562 pi = proto_tree_add_text(dcerpc_tree, tvb, offset, 0, "No bind info for this interface Context ID - capture start too late?");
3563 PROTO_ITEM_SET_GENERATED(pi);
3564 expert_add_info_format(pinfo, pi, PI_UNDECODED, PI_NOTE, "No bind info for interface Context ID:%u",ctx_id);
3565 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3568 /* Dissect the verifier */
3569 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
3573 dissect_dcerpc_cn_fault (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3574 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
3576 dcerpc_call_value *value = NULL;
3577 conversation_t *conv;
3581 dcerpc_auth_info auth_info;
3582 proto_item *pi = NULL;
3584 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3585 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3587 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3588 hf_dcerpc_cn_ctx_id, &ctx_id);
3590 if (check_col (pinfo->cinfo, COL_DCE_CTX)) {
3591 if(pinfo->dcectxid == 0) {
3592 col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "%u", ctx_id);
3594 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
3595 * prepend a delimiter */
3596 col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "#%u", ctx_id);
3600 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3601 hf_dcerpc_cn_cancel_count, NULL);
3605 /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3606 hf_dcerpc_cn_status, &status);*/
3607 status = ((hdr->drep[0] & 0x10)
3608 ? tvb_get_letohl (tvb, offset)
3609 : tvb_get_ntohl (tvb, offset));
3612 pi = proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_status, tvb, offset, 4, (hdr->drep[0] & 0x10));
3616 expert_add_info_format(pinfo, pi, PI_RESPONSE_CODE, PI_NOTE, "Fault: %s",
3617 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
3619 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3620 pinfo->dcectxid = ctx_id;
3622 if (check_col (pinfo->cinfo, COL_INFO)) {
3623 col_append_fstr (pinfo->cinfo, COL_INFO,
3624 " ctx_id: %u status: %s", ctx_id,
3625 val_to_str(status, reject_status_vals,
3626 "Unknown (0x%08x)"));
3633 * XXX - what if this was set when the connection was set up,
3634 * and we just have a security context?
3636 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3638 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3639 pinfo->srcport, pinfo->destport, 0);
3641 /* no point in creating one here, really */
3643 dcerpc_matched_key matched_key, *new_matched_key;
3645 /* !!! we can NOT check flags.visited here since this will interact
3646 badly with when SMB handles (i.e. calls the subdissector)
3647 and desegmented pdu's .
3648 Instead we check if this pdu is already in the matched table or not
3650 matched_key.frame = pinfo->fd->num;
3651 matched_key.call_id = hdr->call_id;
3652 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3654 dcerpc_cn_call_key call_key;
3655 dcerpc_call_value *call_value;
3658 call_key.call_id=hdr->call_id;
3659 call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3661 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3662 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
3663 *new_matched_key = matched_key;
3664 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3666 if(call_value->rep_frame==0){
3667 call_value->rep_frame=pinfo->fd->num;
3674 int length, reported_length, stub_length;
3676 proto_item *parent_pi;
3679 /* handoff this call */
3681 di->call_id = hdr->call_id;
3682 di->smb_fid = dcerpc_get_transport_salt(pinfo);
3683 di->ptype = PDU_FAULT;
3684 di->call_data = value;
3686 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
3687 if(value->req_frame!=0){
3689 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3690 tvb, 0, 0, value->req_frame);
3691 PROTO_ITEM_SET_GENERATED(pi);
3692 parent_pi = proto_tree_get_parent(dcerpc_tree);
3693 if(parent_pi != NULL) {
3694 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
3696 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
3697 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
3698 PROTO_ITEM_SET_GENERATED(pi);
3700 pi = proto_tree_add_text(dcerpc_tree,
3701 tvb, 0, 0, "No request to this DCE/RPC call found");
3702 expert_add_info_format(pinfo, pi, PI_SEQUENCE, PI_NOTE,
3703 "No request to this DCE/RPC call found");
3706 length = tvb_length_remaining(tvb, offset);
3707 reported_length = tvb_reported_length_remaining(tvb, offset);
3708 /* as we now create a tvb in dissect_dcerpc_cn() containing only the
3709 * stub_data, the following calculation is no longer valid:
3710 * stub_length = hdr->frag_len - offset - auth_info.auth_size;
3711 * simply use the remaining length of the tvb instead.
3712 * XXX - or better use the reported_length?!?
3714 stub_length = length;
3715 if (length > stub_length)
3716 length = stub_length;
3717 if (reported_length > stub_length)
3718 reported_length = stub_length;
3720 /* If we don't have reassembly enabled, or this packet contains
3721 the entire PDU, or if we don't have all the data in this
3722 fragment, just call the handoff directly if this is the
3723 first fragment or the PDU isn't fragmented. */
3724 if( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
3725 !tvb_bytes_exist(tvb, offset, stub_length) ){
3726 if(hdr->flags&PFC_FIRST_FRAG){
3727 /* First fragment, possibly the only fragment */
3729 * XXX - should there be a third routine for each
3730 * function in an RPC subdissector, to handle
3731 * fault responses? The DCE RPC 1.1 spec says
3732 * three's "stub data" here, which I infer means
3733 * that it's protocol-specific and call-specific.
3735 * It should probably get passed the status code
3736 * as well, as that might be protocol-specific.
3739 if (stub_length > 0) {
3740 tvb_ensure_bytes_exist(tvb, offset, stub_length);
3741 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3742 "Fault stub data (%d byte%s)",
3744 plurality(stub_length, "", "s"));
3748 /* PDU is fragmented and this isn't the first fragment */
3749 if (check_col(pinfo->cinfo, COL_INFO)) {
3750 col_append_str(pinfo->cinfo, COL_INFO,
3751 " [DCE/RPC fragment]");
3754 if (stub_length > 0) {
3755 tvb_ensure_bytes_exist(tvb, offset, stub_length);
3756 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3757 "Fragment data (%d byte%s)",
3759 plurality(stub_length, "", "s"));
3764 /* Reassembly is enabled, the PDU is fragmented, and
3765 we have all the data in the fragment; the first two
3766 of those mean we should attempt reassembly, and the
3767 third means we can attempt reassembly. */
3770 tvb_ensure_bytes_exist(tvb, offset, stub_length);
3771 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3772 "Fragment data (%d byte%s)",
3774 plurality(stub_length, "", "s"));
3777 if(hdr->flags&PFC_FIRST_FRAG){ /* FIRST fragment */
3778 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
3779 fragment_add_seq_next(tvb, offset, pinfo, value->rep_frame,
3780 dcerpc_co_fragment_table, dcerpc_co_reassemble_table,
3784 if (check_col(pinfo->cinfo, COL_INFO)) {
3785 col_append_str(pinfo->cinfo, COL_INFO,
3786 " [DCE/RPC fragment]");
3788 } else if(hdr->flags&PFC_LAST_FRAG){ /* LAST fragment */
3789 if( value->rep_frame ){
3790 fragment_data *fd_head;
3792 fd_head = fragment_add_seq_next(tvb, offset, pinfo,
3794 dcerpc_co_fragment_table, dcerpc_co_reassemble_table,
3799 /* We completed reassembly */
3801 proto_item *frag_tree_item;
3803 next_tvb = tvb_new_child_real_data(tvb, fd_head->data, fd_head->len, fd_head->len);
3804 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3805 show_fragment_tree(fd_head, &dcerpc_frag_items,
3806 dcerpc_tree, pinfo, next_tvb, &frag_tree_item);
3809 * XXX - should there be a third routine for each
3810 * function in an RPC subdissector, to handle
3811 * fault responses? The DCE RPC 1.1 spec says
3812 * three's "stub data" here, which I infer means
3813 * that it's protocol-specific and call-specific.
3815 * It should probably get passed the status code
3816 * as well, as that might be protocol-specific.
3820 tvb_ensure_bytes_exist(tvb, offset, stub_length);
3821 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3822 "Fault stub data (%d byte%s)",
3824 plurality(stub_length, "", "s"));
3828 /* Reassembly not complete - some fragments
3830 if (check_col(pinfo->cinfo, COL_INFO)) {
3831 col_append_str(pinfo->cinfo, COL_INFO,
3832 " [DCE/RPC fragment]");
3836 } else { /* MIDDLE fragment(s) */
3837 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
3838 fragment_add_seq_next(tvb, offset, pinfo, value->rep_frame,
3839 dcerpc_co_fragment_table, dcerpc_co_reassemble_table,
3843 if (check_col(pinfo->cinfo, COL_INFO)) {
3844 col_append_str(pinfo->cinfo, COL_INFO,
3845 " [DCE/RPC fragment]");
3854 * DCERPC dissector for connection oriented calls.
3855 * We use transport type to later multiplex between what kind of
3856 * pinfo->private_data structure to expect.
3859 dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
3860 proto_tree *tree, gboolean can_desegment, int *pkt_len)
3862 static const guint8 nulls[4] = { 0 };
3865 proto_item *ti = NULL;
3866 proto_item *tf = NULL;
3867 proto_tree *dcerpc_tree = NULL;
3868 proto_tree *cn_flags_tree = NULL;
3869 proto_tree *drep_tree = NULL;
3870 e_dce_cn_common_hdr_t hdr;
3871 dcerpc_auth_info auth_info;
3872 tvbuff_t *fragment_tvb;
3875 * when done over nbt, dcerpc requests are padded with 4 bytes of null
3876 * data for some reason.
3878 * XXX - if that's always the case, the right way to do this would
3879 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
3880 * the 4 bytes of null padding, and make that the dissector
3881 * used for "netbios".
3883 if (tvb_memeql (tvb, offset, nulls, 4) == 0) {
3892 * Check if this looks like a C/O DCERPC call
3894 if (!tvb_bytes_exist (tvb, offset, sizeof (hdr))) {
3895 return FALSE; /* not enough information to check */
3897 start_offset = offset;
3898 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
3899 if (hdr.rpc_ver != 5)
3901 hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
3902 if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
3904 hdr.ptype = tvb_get_guint8 (tvb, offset++);
3908 hdr.flags = tvb_get_guint8 (tvb, offset++);
3909 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
3910 offset += sizeof (hdr.drep);
3912 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3914 hdr.auth_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3916 hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3919 if (check_col (pinfo->cinfo, COL_DCE_CALL)) {
3920 if(pinfo->dcectxid == 0) {
3921 col_append_fstr (pinfo->cinfo, COL_DCE_CALL, "%u", hdr.call_id);
3923 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
3924 * prepend a delimiter */
3925 col_append_fstr (pinfo->cinfo, COL_DCE_CALL, "#%u", hdr.call_id);
3929 if (can_desegment && pinfo->can_desegment
3930 && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
3931 pinfo->desegment_offset = start_offset;
3932 pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, start_offset);
3933 *pkt_len = 0; /* desegmentation required */
3937 if (check_col (pinfo->cinfo, COL_PROTOCOL))
3938 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
3940 if (check_col (pinfo->cinfo, COL_INFO)) {
3941 if(pinfo->dcectxid != 0) {
3942 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
3943 * append a delimiter and set a column fence */
3944 col_append_str (pinfo->cinfo, COL_INFO, " # ");
3945 col_set_fence(pinfo->cinfo,COL_INFO);
3947 col_add_fstr (pinfo->cinfo, COL_INFO, "%s: call_id: %u",
3948 pckt_vals[hdr.ptype].strptr, hdr.call_id);
3951 if(pinfo->dcectxid != 0) {
3952 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU */
3953 expert_add_info_format(pinfo, NULL, PI_SEQUENCE, PI_CHAT, "Multiple DCE/RPC fragments/PDU's in one packet");
3956 offset = start_offset;
3957 tvb_ensure_bytes_exist(tvb, offset, 16);
3959 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE);
3960 dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
3963 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
3966 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset, 1, hdr.rpc_ver_minor);
3969 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
3972 /* XXX - too much "output noise", removed for now
3973 if(hdr.ptype == PDU_BIND || hdr.ptype == PDU_ALTER ||
3974 hdr.ptype == PDU_BIND_ACK || hdr.ptype == PDU_ALTER_ACK)
3975 expert_add_info_format(pinfo, tf, PI_SEQUENCE, PI_CHAT, "Context change: %s",
3976 val_to_str(hdr.ptype, pckt_vals, "(0x%x)"));*/
3977 if(hdr.ptype == PDU_BIND_NAK)
3978 expert_add_info_format(pinfo, tf, PI_SEQUENCE, PI_WARN, "Bind not acknowledged");
3981 proto_item_append_text(ti, " %s, Fragment:", val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"));
3983 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
3984 cn_flags_tree = proto_item_add_subtree (tf, ett_dcerpc_cn_flags);
3986 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
3987 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
3988 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
3989 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
3990 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
3991 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
3992 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
3993 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
3994 if( (hdr.flags & PFC_FIRST_FRAG) && (hdr.flags & PFC_LAST_FRAG) ) {
3995 proto_item_append_text(ti, " Single");
3997 if(hdr.flags & PFC_FIRST_FRAG) {
3998 proto_item_append_text(ti, " 1st");
4000 if(hdr.flags & PFC_LAST_FRAG) {
4001 proto_item_append_text(ti, " Last");
4003 if( !(hdr.flags & PFC_FIRST_FRAG) && !(hdr.flags & PFC_LAST_FRAG) ) {
4004 proto_item_append_text(ti, " Mid");
4010 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
4011 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
4013 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
4014 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
4015 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
4016 offset += sizeof (hdr.drep);
4018 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
4021 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
4024 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
4028 proto_item_append_text(ti, ", FragLen: %u, Call: %u", hdr.frag_len, hdr.call_id);
4032 * None of the stuff done above should throw an exception, because
4033 * we would have rejected this as "not DCE RPC" if we didn't have all
4034 * of it. (XXX - perhaps we should request reassembly if we have
4035 * enough of the header to consider it DCE RPC but not enough to
4036 * get the fragment length; in that case the stuff still wouldn't
4037 * throw an exception.)
4039 * The rest of the stuff might, so return the PDU length to our caller.
4040 * XXX - should we construct a tvbuff containing only the PDU and
4041 * use that? Or should we have separate "is this a DCE RPC PDU",
4042 * "how long is it", and "dissect it" routines - which might let us
4043 * do most of the work in "tcp_dissect_pdus()"?
4045 if (pkt_len != NULL)
4046 *pkt_len = hdr.frag_len + padding;
4048 /* The remaining bytes in the current tvb might contain multiple
4049 * DCE/RPC fragments, so create a new tvb subset for this fragment.
4050 * Only limit the end of the fragment, but not the offset start,
4051 * as the authentication function dissect_dcerpc_cn_auth() will fail
4052 * (and other functions might fail as well) computing the right start
4055 fragment_tvb = tvb_new_subset(tvb, 0,
4056 MIN((hdr.frag_len + (guint) start_offset), tvb_length(tvb)) /* length */,
4057 hdr.frag_len + start_offset /* reported_length */);
4060 * Packet type specific stuff is next.
4062 switch (hdr.ptype) {
4065 dissect_dcerpc_cn_bind (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr);
4070 dissect_dcerpc_cn_bind_ack (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr);
4075 * Nothing after the common header other than credentials.
4077 dissect_dcerpc_cn_auth (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr, TRUE,
4082 dissect_dcerpc_cn_rqst (fragment_tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
4086 dissect_dcerpc_cn_resp (fragment_tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
4090 dissect_dcerpc_cn_fault (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr);
4094 dissect_dcerpc_cn_bind_nak (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr);
4100 * Nothing after the common header other than an authentication
4103 dissect_dcerpc_cn_auth (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
4109 * Nothing after the common header, not even an authentication
4115 /* might as well dissect the auth info */
4116 dissect_dcerpc_cn_auth (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
4124 * DCERPC dissector for connection oriented calls over packet-oriented
4128 dissect_dcerpc_cn_pk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4131 * Only one PDU per transport packet, and only one transport
4134 pinfo->dcetransporttype=DCE_TRANSPORT_UNKNOWN;
4135 if (!dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE, NULL)) {
4137 * It wasn't a DCERPC PDU.
4149 * DCERPC dissector for connection oriented calls over byte-stream
4151 * we need to distinguish here between SMB and non-TCP (more in the future?)
4152 * to be able to know what kind of private_data structure to expect.
4155 dissect_dcerpc_cn_bs_body (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4157 volatile int offset = 0;
4159 volatile gboolean dcerpc_pdus = 0;
4160 volatile gboolean ret = FALSE;
4163 * There may be multiple PDUs per transport packet; keep
4166 while (tvb_reported_length_remaining(tvb, offset) != 0) {
4168 * Catch ReportedBoundsError, so that even if the stub data is bad,
4169 * we don't abort the full DCE RPC dissection - there might be more
4170 * than one DCE RPC PDU in the data being dissected.
4172 * If we get BoundsError, it means the frame was cut short by a
4173 * snapshot length, so there's nothing more to dissect; just
4174 * re-throw that exception.
4178 if(dissect_dcerpc_cn (tvb, offset, pinfo, tree,
4179 dcerpc_cn_desegment, &pdu_len)) {
4182 } CATCH(BoundsError) {
4184 } CATCH(ReportedBoundsError) {
4185 show_reported_bounds_error(tvb, pinfo, tree);
4187 * Presumably it looked enough like a DCE RPC PDU that we
4188 * dissected enough of it to throw an exception.
4201 * Well, we've seen at least one DCERPC PDU.
4205 /* if we had more than one Req/Resp in this PDU change the protocol column */
4206 /* this will formerly contain the last interface name, which may not be the same for all Req/Resp */
4207 if (dcerpc_pdus >= 2 && check_col (pinfo->cinfo, COL_PROTOCOL))
4208 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "%u*DCERPC", dcerpc_pdus);
4212 * Desegmentation required - bail now, but give the user a hint that desegmentation might be done later.
4214 proto_tree_add_uint_format(tree, hf_dcerpc_cn_deseg_req, tvb, offset,
4216 tvb_reported_length_remaining(tvb, offset),
4217 "[DCE RPC: %u byte%s left, desegmentation might follow]",
4218 tvb_reported_length_remaining(tvb, offset),
4219 plurality(tvb_reported_length_remaining(tvb, offset), "", "s"));
4224 * Step to the next PDU.
4232 dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4234 pinfo->dcetransporttype=DCE_TRANSPORT_UNKNOWN;
4235 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
4239 dissect_dcerpc_cn_smbpipe (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4241 pinfo->dcetransporttype=DCE_CN_TRANSPORT_SMBPIPE;
4242 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
4246 dissect_dcerpc_cn_smb2 (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4248 pinfo->dcetransporttype=DCE_TRANSPORT_UNKNOWN;
4249 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
4255 dissect_dcerpc_dg_auth (tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
4256 e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
4258 proto_item *ti = NULL;
4259 proto_tree *auth_tree = NULL;
4260 guint8 protection_level;
4263 * Initially set "*auth_level_p" to -1 to indicate that we haven't
4264 * yet seen any authentication level information.
4266 if (auth_level_p != NULL)
4270 * The authentication information is at the *end* of the PDU; in
4271 * request and response PDUs, the request and response stub data
4274 * If the full packet is here, and there's data past the end of the
4275 * packet body, then dissect the auth info.
4277 offset += hdr->frag_len;
4278 if (tvb_length_remaining(tvb, offset) > 0) {
4279 switch (hdr->auth_proto) {
4281 case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
4282 ti = proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Kerberos authentication verifier");
4283 auth_tree = proto_item_add_subtree (ti, ett_dcerpc_krb5_auth_verf);
4284 protection_level = tvb_get_guint8 (tvb, offset);
4285 if (auth_level_p != NULL)
4286 *auth_level_p = protection_level;
4287 proto_tree_add_uint (auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
4289 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, FALSE);
4291 if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
4292 offset += 6; /* 6 bytes of padding */
4294 offset += 2; /* 6 bytes of padding */
4295 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, FALSE);
4300 proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Authentication verifier");
4307 dissect_dcerpc_dg_cancel_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
4308 proto_tree *dcerpc_tree,
4309 e_dce_dg_common_hdr_t *hdr)
4313 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4314 hdr->drep, hf_dcerpc_dg_cancel_vers,
4320 /* The only version we know about */
4321 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4322 hdr->drep, hf_dcerpc_dg_cancel_id,
4324 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
4325 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
4332 dissect_dcerpc_dg_cancel (tvbuff_t *tvb, int offset, packet_info *pinfo,
4333 proto_tree *dcerpc_tree,
4334 e_dce_dg_common_hdr_t *hdr)
4338 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4339 hdr->drep, hf_dcerpc_dg_cancel_vers,
4345 /* The only version we know about */
4346 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4347 hdr->drep, hf_dcerpc_dg_cancel_id,
4349 /* XXX - are NDR booleans 32 bits? */
4351 /* XXX - the RPC reference in chapter: "the cancel PDU" doesn't mention
4352 the accepting_cancels field (it's only in the cancel_ack PDU)! */
4353 /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4354 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
4361 dissect_dcerpc_dg_fack (tvbuff_t *tvb, int offset, packet_info *pinfo,
4362 proto_tree *dcerpc_tree,
4363 e_dce_dg_common_hdr_t *hdr)
4370 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
4371 hdr->drep, hf_dcerpc_dg_fack_vers,
4378 case 0: /* The only version documented in the DCE RPC 1.1 spec */
4379 case 1: /* This appears to be the same */
4380 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
4381 hdr->drep, hf_dcerpc_dg_fack_window_size,
4383 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4384 hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
4386 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4387 hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
4389 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
4390 hdr->drep, hf_dcerpc_dg_fack_serial_num,
4392 if (check_col (pinfo->cinfo, COL_INFO)) {
4393 col_append_fstr (pinfo->cinfo, COL_INFO, " serial: %u",
4396 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
4397 hdr->drep, hf_dcerpc_dg_fack_selack_len,
4399 for (i = 0; i < selack_len; i++) {
4400 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4401 hdr->drep, hf_dcerpc_dg_fack_selack,
4410 dissect_dcerpc_dg_reject_fault (tvbuff_t *tvb, int offset, packet_info *pinfo,
4411 proto_tree *dcerpc_tree,
4412 e_dce_dg_common_hdr_t *hdr)
4416 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4417 hdr->drep, hf_dcerpc_dg_status,
4420 if (check_col (pinfo->cinfo, COL_INFO)) {
4421 col_append_fstr (pinfo->cinfo, COL_INFO,
4423 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
4428 dissect_dcerpc_dg_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
4429 proto_tree *dcerpc_tree, proto_tree *tree,
4430 e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
4432 int length, reported_length, stub_length;
4433 gboolean save_fragmented;
4434 fragment_data *fd_head;
4437 proto_item *parent_pi;
4439 if (check_col (pinfo->cinfo, COL_INFO))
4440 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u len: %u",
4441 di->call_data->opnum, hdr->frag_len );
4443 length = tvb_length_remaining (tvb, offset);
4444 reported_length = tvb_reported_length_remaining (tvb, offset);
4445 stub_length = hdr->frag_len;
4446 if (length > stub_length)
4447 length = stub_length;
4448 if (reported_length > stub_length)
4449 reported_length = stub_length;
4451 save_fragmented = pinfo->fragmented;
4453 /* If we don't have reassembly enabled, or this packet contains
4454 the entire PDU, or if this is a short frame (or a frame
4455 not reassembled at a lower layer) that doesn't include all
4456 the data in the fragment, just call the handoff directly if
4457 this is the first fragment or the PDU isn't fragmented. */
4458 if( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
4459 !tvb_bytes_exist(tvb, offset, stub_length) ){
4460 if(hdr->frag_num == 0) {
4463 /* First fragment, possibly the only fragment */
4466 * XXX - authentication info?
4468 pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
4469 next_tvb = tvb_new_subset (tvb, offset, length,
4471 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
4472 next_tvb, hdr->drep, di, NULL);
4474 /* PDU is fragmented and this isn't the first fragment */
4475 if (check_col(pinfo->cinfo, COL_INFO)) {
4476 col_append_str(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
4480 tvb_ensure_bytes_exist(tvb, offset, stub_length);
4481 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
4482 "Fragment data (%d byte%s)",
4484 plurality(stub_length, "", "s"));
4489 /* Reassembly is enabled, the PDU is fragmented, and
4490 we have all the data in the fragment; the first two
4491 of those mean we should attempt reassembly, and the
4492 third means we can attempt reassembly. */
4495 tvb_ensure_bytes_exist(tvb, offset, stub_length);
4496 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
4497 "Fragment data (%d byte%s)", stub_length,
4498 plurality(stub_length, "", "s"));
4502 fd_head = fragment_add_dcerpc_dg(tvb, offset, pinfo,
4503 hdr->seqnum, &hdr->act_id, dcerpc_cl_reassemble_table,
4504 hdr->frag_num, stub_length,
4505 !(hdr->flags1 & PFCL1_LASTFRAG));
4506 if (fd_head != NULL) {
4507 /* We completed reassembly... */
4508 if(pinfo->fd->num==fd_head->reassembled_in) {
4509 /* ...and this is the reassembled RPC PDU */
4510 next_tvb = tvb_new_child_real_data(tvb, fd_head->data, fd_head->len, fd_head->len);
4511 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
4512 show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
4513 tree, pinfo, next_tvb, &pi);
4516 * XXX - authentication info?
4518 pinfo->fragmented = FALSE;
4519 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
4520 next_tvb, hdr->drep, di, NULL);
4522 /* ...and this isn't the reassembled RPC PDU */
4523 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
4524 tvb, 0, 0, fd_head->reassembled_in);
4525 PROTO_ITEM_SET_GENERATED(pi);
4526 parent_pi = proto_tree_get_parent(dcerpc_tree);
4527 if(parent_pi != NULL) {
4528 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
4530 if (check_col(pinfo->cinfo, COL_INFO)) {
4531 col_append_fstr(pinfo->cinfo, COL_INFO,
4532 " [DCE/RPC fragment, reas: #%u]", fd_head->reassembled_in);
4536 /* Reassembly isn't completed yet */
4537 if (check_col(pinfo->cinfo, COL_INFO)) {
4538 col_append_str(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
4542 pinfo->fragmented = save_fragmented;
4546 dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo,
4547 proto_tree *dcerpc_tree, proto_tree *tree,
4548 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4551 dcerpc_call_value *value, v;
4552 dcerpc_matched_key matched_key, *new_matched_key;
4554 proto_item *parent_pi;
4557 if(!(pinfo->fd->flags.visited)){
4558 dcerpc_call_value *call_value;
4559 dcerpc_dg_call_key *call_key;
4561 call_key=se_alloc (sizeof (dcerpc_dg_call_key));
4562 call_key->conv=conv;
4563 call_key->seqnum=hdr->seqnum;
4564 call_key->act_id=hdr->act_id;
4566 call_value=se_alloc (sizeof (dcerpc_call_value));
4567 call_value->uuid = hdr->if_id;
4568 call_value->ver = hdr->if_ver;
4569 call_value->object_uuid = hdr->obj_id;
4570 call_value->opnum = hdr->opnum;
4571 call_value->req_frame=pinfo->fd->num;
4572 call_value->req_time=pinfo->fd->abs_ts;
4573 call_value->rep_frame=0;
4574 call_value->max_ptr=0;
4575 call_value->se_data = NULL;
4576 call_value->private_data = NULL;
4577 call_value->pol = NULL;
4578 g_hash_table_insert (dcerpc_dg_calls, call_key, call_value);
4580 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
4581 new_matched_key->frame = pinfo->fd->num;
4582 new_matched_key->call_id = hdr->seqnum;
4583 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
4586 matched_key.frame = pinfo->fd->num;
4587 matched_key.call_id = hdr->seqnum;
4588 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
4590 v.uuid = hdr->if_id;
4591 v.ver = hdr->if_ver;
4592 v.object_uuid = hdr->obj_id;
4593 v.opnum = hdr->opnum;
4594 v.req_frame = pinfo->fd->num;
4598 v.private_data=NULL;
4603 di->call_id = hdr->seqnum;
4605 di->ptype = PDU_REQ;
4606 di->call_data = value;
4608 if(value->rep_frame!=0){
4609 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
4610 tvb, 0, 0, value->rep_frame);
4611 PROTO_ITEM_SET_GENERATED(pi);
4612 parent_pi = proto_tree_get_parent(dcerpc_tree);
4613 if(parent_pi != NULL) {
4614 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
4617 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
4621 dissect_dcerpc_dg_resp (tvbuff_t *tvb, int offset, packet_info *pinfo,
4622 proto_tree *dcerpc_tree, proto_tree *tree,
4623 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4626 dcerpc_call_value *value, v;
4627 dcerpc_matched_key matched_key, *new_matched_key;
4629 proto_item *parent_pi;
4632 if(!(pinfo->fd->flags.visited)){
4633 dcerpc_call_value *call_value;
4634 dcerpc_dg_call_key call_key;
4637 call_key.seqnum=hdr->seqnum;
4638 call_key.act_id=hdr->act_id;
4640 if((call_value=g_hash_table_lookup(dcerpc_dg_calls, &call_key))){
4641 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
4642 new_matched_key->frame = pinfo->fd->num;
4643 new_matched_key->call_id = hdr->seqnum;
4644 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
4645 if(call_value->rep_frame==0){
4646 call_value->rep_frame=pinfo->fd->num;
4651 matched_key.frame = pinfo->fd->num;
4652 matched_key.call_id = hdr->seqnum;
4653 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
4655 v.uuid = hdr->if_id;
4656 v.ver = hdr->if_ver;
4657 v.object_uuid = hdr->obj_id;
4658 v.opnum = hdr->opnum;
4660 v.rep_frame=pinfo->fd->num;
4662 v.private_data=NULL;
4669 di->ptype = PDU_RESP;
4670 di->call_data = value;
4672 if(value->req_frame!=0){
4674 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4675 tvb, 0, 0, value->req_frame);
4676 PROTO_ITEM_SET_GENERATED(pi);
4677 parent_pi = proto_tree_get_parent(dcerpc_tree);
4678 if(parent_pi != NULL) {
4679 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
4681 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
4682 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
4683 PROTO_ITEM_SET_GENERATED(pi);
4685 pi = proto_tree_add_text(dcerpc_tree,
4686 tvb, 0, 0, "No request to this DCE/RPC call found");
4687 expert_add_info_format(pinfo, pi, PI_SEQUENCE, PI_NOTE,
4688 "No request to this DCE/RPC call found");
4690 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
4694 dissect_dcerpc_dg_ping_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
4695 proto_tree *dcerpc_tree,
4696 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4698 proto_item *parent_pi;
4699 /* if(!(pinfo->fd->flags.visited)){*/
4700 dcerpc_call_value *call_value;
4701 dcerpc_dg_call_key call_key;
4704 call_key.seqnum=hdr->seqnum;
4705 call_key.act_id=hdr->act_id;
4707 if((call_value=g_hash_table_lookup(dcerpc_dg_calls, &call_key))){
4711 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4712 tvb, 0, 0, call_value->req_frame);
4713 PROTO_ITEM_SET_GENERATED(pi);
4714 parent_pi = proto_tree_get_parent(dcerpc_tree);
4715 if(parent_pi != NULL) {
4716 proto_item_append_text(parent_pi, ", [Req: #%u]", call_value->req_frame);
4719 if (check_col (pinfo->cinfo, COL_INFO))
4720 col_append_fstr(pinfo->cinfo, COL_INFO, " [req: #%u]", call_value->req_frame);
4722 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &call_value->req_time);
4723 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
4724 PROTO_ITEM_SET_GENERATED(pi);
4730 * DCERPC dissector for connectionless calls
4733 dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4735 proto_item *ti = NULL;
4736 proto_item *tf = NULL;
4737 proto_tree *dcerpc_tree = NULL;
4738 proto_tree *dg_flags1_tree = NULL;
4739 proto_tree *dg_flags2_tree = NULL;
4740 proto_tree *drep_tree = NULL;
4741 e_dce_dg_common_hdr_t hdr;
4743 conversation_t *conv;
4746 const char *uuid_name = NULL;
4749 * Check if this looks like a CL DCERPC call. All dg packets
4750 * have an 80 byte header on them. Which starts with
4751 * version (4), pkt_type.
4753 if (tvb_length (tvb) < sizeof (hdr)) {
4757 /* Version must be 4 */
4758 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
4759 if (hdr.rpc_ver != 4)
4762 /* Type must be <=19 or its not DCE/RPC */
4763 hdr.ptype = tvb_get_guint8 (tvb, offset++);
4767 /* flags1 has bit 1 and 8 as reserved so if any of them are set, it is
4768 probably not a DCE/RPC packet
4770 hdr.flags1 = tvb_get_guint8 (tvb, offset++);
4774 /* flags2 has all bits except bit 2 as reserved so if any of them are set
4775 it is probably not DCE/RPC.
4777 hdr.flags2 = tvb_get_guint8 (tvb, offset++);
4782 if (check_col (pinfo->cinfo, COL_PROTOCOL))
4783 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
4784 if (check_col (pinfo->cinfo, COL_INFO))
4785 col_add_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
4787 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
4788 offset += sizeof (hdr.drep);
4789 hdr.serial_hi = tvb_get_guint8 (tvb, offset++);
4790 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.obj_id);
4792 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.if_id);
4794 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.act_id);
4796 hdr.server_boot = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4798 hdr.if_ver = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4800 hdr.seqnum = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4802 hdr.opnum = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4804 hdr.ihint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4806 hdr.ahint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4808 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4810 hdr.frag_num = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4812 hdr.auth_proto = tvb_get_guint8 (tvb, offset++);
4813 hdr.serial_lo = tvb_get_guint8 (tvb, offset++);
4816 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, -1, FALSE);
4818 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
4819 proto_item_append_text(ti, " %s, Seq: %u, Serial: %u, Frag: %u, FragLen: %u",
4820 val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"),
4821 hdr.seqnum, hdr.serial_hi*256+hdr.serial_lo,
4822 hdr.frag_num, hdr.frag_len);
4828 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
4832 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
4836 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
4837 dg_flags1_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags1);
4838 if (dg_flags1_tree) {
4839 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
4840 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
4841 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
4842 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
4843 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
4844 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
4845 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
4846 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
4848 proto_item_append_text(tf, " %s%s%s%s%s%s",
4849 (hdr.flags1 & PFCL1_BROADCAST) ? "\"Broadcast\" " : "",
4850 (hdr.flags1 & PFCL1_IDEMPOTENT) ? "\"Idempotent\" " : "",
4851 (hdr.flags1 & PFCL1_MAYBE) ? "\"Maybe\" " : "",
4852 (hdr.flags1 & PFCL1_NOFACK) ? "\"No Fack\" " : "",
4853 (hdr.flags1 & PFCL1_FRAG) ? "\"Fragment\" " : "",
4854 (hdr.flags1 & PFCL1_LASTFRAG) ? "\"Last Fragment\" " : "");
4861 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
4862 dg_flags2_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags2);
4863 if (dg_flags2_tree) {
4864 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
4865 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
4866 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
4867 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
4868 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
4869 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
4870 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
4871 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
4873 proto_item_append_text(tf, " %s",
4874 (hdr.flags2 & PFCL2_CANCEL_PENDING) ? "\"Cancel Pending\" " : "");
4881 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
4882 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
4884 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
4885 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
4886 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
4887 proto_item_append_text(tf, " (Order: %s, Char: %s, Float: %s)",
4888 val_to_str(hdr.drep[0] >> 4, drep_byteorder_vals, "Unknown"),
4889 val_to_str(hdr.drep[0] & 0x0f, drep_character_vals, "Unknown"),
4890 val_to_str(hdr.drep[1], drep_fp_vals, "Unknown"));
4893 offset += sizeof (hdr.drep);
4896 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
4900 proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
4901 offset, 16, (e_guid_t *) &hdr.obj_id, "Object UUID: %s",
4902 guid_to_str((e_guid_t *) &hdr.obj_id));
4907 uuid_str = guid_to_str((e_guid_t*)&hdr.if_id);
4908 uuid_name = guids_get_uuid_name(&hdr.if_id);
4910 proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
4911 offset, 16, (e_guid_t *) &hdr.if_id, "Interface: %s UUID: %s", uuid_name, uuid_str);
4913 proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
4914 offset, 16, (e_guid_t *) &hdr.if_id, "Interface UUID: %s", uuid_str);
4920 proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
4921 offset, 16, (e_guid_t *) &hdr.act_id, "Activity: %s",
4922 guid_to_str((e_guid_t *) &hdr.act_id));
4927 nstime_t server_boot;
4929 server_boot.secs = hdr.server_boot;
4930 server_boot.nsecs = 0;
4932 if (hdr.server_boot == 0)
4933 proto_tree_add_time_format (dcerpc_tree, hf_dcerpc_dg_server_boot,
4934 tvb, offset, 4, &server_boot,
4935 "Server boot time: Unknown (0)");
4937 proto_tree_add_time (dcerpc_tree, hf_dcerpc_dg_server_boot,
4938 tvb, offset, 4, &server_boot);
4943 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
4947 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
4948 if (check_col (pinfo->cinfo, COL_INFO)) {
4949 col_append_fstr (pinfo->cinfo, COL_INFO, ": seq: %u", hdr.seqnum);
4951 if (check_col (pinfo->cinfo, COL_DCE_CALL)) {
4952 col_append_fstr (pinfo->cinfo, COL_DCE_CALL, "%u", hdr.seqnum);
4957 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
4961 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
4965 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
4969 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
4973 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
4974 if (check_col (pinfo->cinfo, COL_INFO)) {
4975 if (hdr.flags1 & PFCL1_FRAG) {
4976 /* Fragmented - put the fragment number into the Info column */
4977 col_append_fstr (pinfo->cinfo, COL_INFO, " frag: %u",
4984 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
4988 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
4989 if (check_col (pinfo->cinfo, COL_INFO)) {
4990 if (hdr.flags1 & PFCL1_FRAG) {
4991 /* Fragmented - put the serial number into the Info column */
4992 col_append_fstr (pinfo->cinfo, COL_INFO, " serial: %u",
4993 (hdr.serial_hi << 8) | hdr.serial_lo);
5000 * XXX - for Kerberos, we get a protection level; if it's
5001 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
5004 dissect_dcerpc_dg_auth (tvb, offset, dcerpc_tree, &hdr,
5009 * keeping track of the conversation shouldn't really be necessary
5010 * for connectionless packets, because everything we need to know
5011 * to dissect is in the header for each packet. Unfortunately,
5012 * Microsoft's implementation is buggy and often puts the
5013 * completely wrong if_id in the header. go figure. So, keep
5014 * track of the seqnum and use that if possible. Note: that's not
5015 * completely correct. It should really be done based on both the
5016 * activity_id and seqnum. I haven't seen anywhere that it would
5017 * make a difference, but for future reference...
5019 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
5020 pinfo->srcport, pinfo->destport, 0);
5022 fprintf(stderr,"Creating a new conv on packet %d\n",pinfo->fd->num);
5023 conv = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
5024 pinfo->srcport, pinfo->destport, 0);
5028 * Packet type specific stuff is next.
5031 switch (hdr.ptype) {
5033 case PDU_CANCEL_ACK:
5034 /* Body is optional */
5035 /* XXX - we assume "frag_len" is the length of the body */
5036 if (hdr.frag_len != 0)
5037 dissect_dcerpc_dg_cancel_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
5042 * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
5043 * but in at least one capture none of the Cl_cancel PDUs had a
5046 /* XXX - we assume "frag_len" is the length of the body */
5047 if (hdr.frag_len != 0)
5048 dissect_dcerpc_dg_cancel (tvb, offset, pinfo, dcerpc_tree, &hdr);
5052 /* Body is optional; if present, it's the same as PDU_FACK */
5053 /* XXX - we assume "frag_len" is the length of the body */
5054 if (hdr.frag_len != 0)
5055 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
5059 /* Body is optional */
5060 /* XXX - we assume "frag_len" is the length of the body */
5061 if (hdr.frag_len != 0)
5062 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
5067 dissect_dcerpc_dg_reject_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
5071 dissect_dcerpc_dg_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
5075 dissect_dcerpc_dg_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
5078 /* these requests have no body */
5081 dissect_dcerpc_dg_ping_ack (tvb, offset, pinfo, dcerpc_tree, &hdr, conv);
5092 dcerpc_init_protocol (void)
5094 /* structures and data for BIND */
5096 g_hash_table_destroy (dcerpc_binds);
5100 dcerpc_binds = g_hash_table_new (dcerpc_bind_hash, dcerpc_bind_equal);
5103 /* structures and data for CALL */
5104 if (dcerpc_cn_calls){
5105 g_hash_table_destroy (dcerpc_cn_calls);
5107 dcerpc_cn_calls = g_hash_table_new (dcerpc_cn_call_hash, dcerpc_cn_call_equal);
5108 if (dcerpc_dg_calls){
5109 g_hash_table_destroy (dcerpc_dg_calls);
5111 dcerpc_dg_calls = g_hash_table_new (dcerpc_dg_call_hash, dcerpc_dg_call_equal);
5113 /* structure and data for MATCHED */
5114 if (dcerpc_matched){
5115 g_hash_table_destroy (dcerpc_matched);
5117 dcerpc_matched = g_hash_table_new (dcerpc_matched_hash, dcerpc_matched_equal);
5119 /* call the registered hooks */
5120 g_hook_list_invoke(&dcerpc_hooks_init_protos, FALSE /* not may_recurse */);
5124 proto_register_dcerpc (void)
5126 static hf_register_info hf[] = {
5127 { &hf_dcerpc_request_in,
5128 { "Request in frame", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE,
5129 NULL, 0, "This packet is a response to the packet with this number", HFILL }},
5130 { &hf_dcerpc_response_in,
5131 { "Response in frame", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
5132 NULL, 0, "This packet will be responded in the packet with this number", HFILL }},
5133 { &hf_dcerpc_referent_id,
5134 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
5135 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
5137 { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5138 { &hf_dcerpc_ver_minor,
5139 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5140 { &hf_dcerpc_packet_type,
5141 { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS (pckt_vals), 0x0, NULL, HFILL }},
5142 { &hf_dcerpc_cn_flags,
5143 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5144 { &hf_dcerpc_cn_flags_first_frag,
5145 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFC_FIRST_FRAG, NULL, HFILL }},
5146 { &hf_dcerpc_cn_flags_last_frag,
5147 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFC_LAST_FRAG, NULL, HFILL }},
5148 { &hf_dcerpc_cn_flags_cancel_pending,
5149 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFC_PENDING_CANCEL, NULL, HFILL }},
5150 { &hf_dcerpc_cn_flags_reserved,
5151 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFC_RESERVED_1, NULL, HFILL }},
5152 { &hf_dcerpc_cn_flags_mpx,
5153 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFC_CONC_MPX, NULL, HFILL }},
5154 { &hf_dcerpc_cn_flags_dne,
5155 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFC_DID_NOT_EXECUTE, NULL, HFILL }},
5156 { &hf_dcerpc_cn_flags_maybe,
5157 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFC_MAYBE, NULL, HFILL }},
5158 { &hf_dcerpc_cn_flags_object,
5159 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFC_OBJECT_UUID, NULL, HFILL }},
5161 { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5162 { &hf_dcerpc_drep_byteorder,
5163 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS (drep_byteorder_vals), 0x0, NULL, HFILL }},
5164 { &hf_dcerpc_drep_character,
5165 { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS (drep_character_vals), 0x0, NULL, HFILL }},
5166 { &hf_dcerpc_drep_fp,
5167 { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS (drep_fp_vals), 0x0, NULL, HFILL }},
5168 { &hf_dcerpc_cn_frag_len,
5169 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5170 { &hf_dcerpc_cn_auth_len,
5171 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5172 { &hf_dcerpc_cn_call_id,
5173 { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5174 { &hf_dcerpc_cn_max_xmit,
5175 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5176 { &hf_dcerpc_cn_max_recv,
5177 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5178 { &hf_dcerpc_cn_assoc_group,
5179 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5180 { &hf_dcerpc_cn_num_ctx_items,
5181 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5182 { &hf_dcerpc_cn_ctx_item,
5183 { "Ctx Item", "dcerpc.cn_ctx_item", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5184 { &hf_dcerpc_cn_ctx_id,
5185 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5186 { &hf_dcerpc_cn_num_trans_items,
5187 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5188 { &hf_dcerpc_cn_bind_abstract_syntax,
5189 { "Abstract Syntax", "dcerpc.cn_bind_abstract_syntax", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5190 { &hf_dcerpc_cn_bind_if_id,
5191 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5192 { &hf_dcerpc_cn_bind_if_ver,
5193 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5194 { &hf_dcerpc_cn_bind_if_ver_minor,
5195 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5196 { &hf_dcerpc_cn_bind_trans_syntax,
5197 { "Transfer Syntax", "dcerpc.cn_bind_trans", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5198 { &hf_dcerpc_cn_bind_trans_id,
5199 { "ID", "dcerpc.cn_bind_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5200 { &hf_dcerpc_cn_bind_trans_ver,
5201 { "ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5202 { &hf_dcerpc_cn_alloc_hint,
5203 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5204 { &hf_dcerpc_cn_sec_addr_len,
5205 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5206 { &hf_dcerpc_cn_sec_addr,
5207 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5208 { &hf_dcerpc_cn_num_results,
5209 { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5210 { &hf_dcerpc_cn_ack_result,
5211 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, NULL, HFILL }},
5212 { &hf_dcerpc_cn_ack_reason,
5213 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, NULL, HFILL }},
5214 { &hf_dcerpc_cn_ack_trans_id,
5215 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5216 { &hf_dcerpc_cn_ack_trans_ver,
5217 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5218 { &hf_dcerpc_cn_reject_reason,
5219 { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, NULL, HFILL }},
5220 { &hf_dcerpc_cn_num_protocols,
5221 { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5222 { &hf_dcerpc_cn_protocol_ver_major,
5223 { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5224 { &hf_dcerpc_cn_protocol_ver_minor,
5225 { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5226 { &hf_dcerpc_cn_cancel_count,
5227 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5228 { &hf_dcerpc_cn_status,
5229 { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, NULL, HFILL }},
5230 { &hf_dcerpc_cn_deseg_req,
5231 { "Desegmentation Required", "dcerpc.cn_deseg_req", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5232 { &hf_dcerpc_auth_type,
5233 { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, NULL, HFILL }},
5234 { &hf_dcerpc_auth_level,
5235 { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS (authn_level_vals), 0x0, NULL, HFILL }},
5236 { &hf_dcerpc_auth_pad_len,
5237 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5238 { &hf_dcerpc_auth_rsrvd,
5239 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5240 { &hf_dcerpc_auth_ctx_id,
5241 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5242 { &hf_dcerpc_dg_flags1,
5243 { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5244 { &hf_dcerpc_dg_flags1_rsrvd_01,
5245 { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL1_RESERVED_01, NULL, HFILL }},
5246 { &hf_dcerpc_dg_flags1_last_frag,
5247 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL1_LASTFRAG, NULL, HFILL }},
5248 { &hf_dcerpc_dg_flags1_frag,
5249 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL1_FRAG, NULL, HFILL }},
5250 { &hf_dcerpc_dg_flags1_nofack,
5251 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL1_NOFACK, NULL, HFILL }},
5252 { &hf_dcerpc_dg_flags1_maybe,
5253 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL1_MAYBE, NULL, HFILL }},
5254 { &hf_dcerpc_dg_flags1_idempotent,
5255 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL1_IDEMPOTENT, NULL, HFILL }},
5256 { &hf_dcerpc_dg_flags1_broadcast,
5257 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL1_BROADCAST, NULL, HFILL }},
5258 { &hf_dcerpc_dg_flags1_rsrvd_80,
5259 { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL1_RESERVED_80, NULL, HFILL }},
5260 { &hf_dcerpc_dg_flags2,
5261 { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5262 { &hf_dcerpc_dg_flags2_rsrvd_01,
5263 { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL2_RESERVED_01, NULL, HFILL }},
5264 { &hf_dcerpc_dg_flags2_cancel_pending,
5265 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL2_CANCEL_PENDING, NULL, HFILL }},
5266 { &hf_dcerpc_dg_flags2_rsrvd_04,
5267 { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL2_RESERVED_04, NULL, HFILL }},
5268 { &hf_dcerpc_dg_flags2_rsrvd_08,
5269 { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL2_RESERVED_08, NULL, HFILL }},
5270 { &hf_dcerpc_dg_flags2_rsrvd_10,
5271 { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL2_RESERVED_10, NULL, HFILL }},
5272 { &hf_dcerpc_dg_flags2_rsrvd_20,
5273 { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL2_RESERVED_20, NULL, HFILL }},
5274 { &hf_dcerpc_dg_flags2_rsrvd_40,
5275 { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL2_RESERVED_40, NULL, HFILL }},
5276 { &hf_dcerpc_dg_flags2_rsrvd_80,
5277 { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL2_RESERVED_80, NULL, HFILL }},
5278 { &hf_dcerpc_dg_serial_lo,
5279 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5280 { &hf_dcerpc_dg_serial_hi,
5281 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5282 { &hf_dcerpc_dg_ahint,
5283 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5284 { &hf_dcerpc_dg_ihint,
5285 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5286 { &hf_dcerpc_dg_frag_len,
5287 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5288 { &hf_dcerpc_dg_frag_num,
5289 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5290 { &hf_dcerpc_dg_auth_proto,
5291 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, NULL, HFILL }},
5292 { &hf_dcerpc_dg_seqnum,
5293 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5294 { &hf_dcerpc_dg_server_boot,
5295 { "Server boot time", "dcerpc.dg_server_boot", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5296 { &hf_dcerpc_dg_if_ver,
5297 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5298 { &hf_dcerpc_krb5_av_prot_level,
5299 { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, NULL, HFILL }},
5300 { &hf_dcerpc_krb5_av_key_vers_num,
5301 { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5302 { &hf_dcerpc_krb5_av_key_auth_verifier,
5303 { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5304 { &hf_dcerpc_obj_id,
5305 { "Object", "dcerpc.obj_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5306 { &hf_dcerpc_dg_if_id,
5307 { "Interface", "dcerpc.dg_if_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5308 { &hf_dcerpc_dg_act_id,
5309 { "Activity", "dcerpc.dg_act_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5311 { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5313 { &hf_dcerpc_dg_cancel_vers,
5314 { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5316 { &hf_dcerpc_dg_cancel_id,
5317 { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5319 { &hf_dcerpc_dg_server_accepting_cancels,
5320 { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5322 { &hf_dcerpc_dg_fack_vers,
5323 { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5325 { &hf_dcerpc_dg_fack_window_size,
5326 { "Window Size", "dcerpc.fack_window_size", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5328 { &hf_dcerpc_dg_fack_max_tsdu,
5329 { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5331 { &hf_dcerpc_dg_fack_max_frag_size,
5332 { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5334 { &hf_dcerpc_dg_fack_serial_num,
5335 { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5337 { &hf_dcerpc_dg_fack_selack_len,
5338 { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5340 { &hf_dcerpc_dg_fack_selack,
5341 { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5343 { &hf_dcerpc_dg_status,
5344 { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, NULL, HFILL }},
5346 { &hf_dcerpc_array_max_count,
5347 { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
5349 { &hf_dcerpc_array_offset,
5350 { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
5352 { &hf_dcerpc_array_actual_count,
5353 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
5355 { &hf_dcerpc_array_buffer,
5356 { "Buffer", "dcerpc.array.buffer", FT_BYTES, BASE_NONE, NULL, 0x0, "Buffer: Buffer containing elements of the array", HFILL }},
5359 { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5361 { &hf_dcerpc_fragments,
5362 { "Reassembled DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
5363 NULL, 0x0, "DCE/RPC Fragments", HFILL }},
5365 { &hf_dcerpc_fragment,
5366 { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM, BASE_NONE,
5367 NULL, 0x0, NULL, HFILL }},
5369 { &hf_dcerpc_fragment_overlap,
5370 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE,
5371 NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
5373 { &hf_dcerpc_fragment_overlap_conflict,
5374 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE,
5375 NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
5377 { &hf_dcerpc_fragment_multiple_tails,
5378 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE,
5379 NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
5381 { &hf_dcerpc_fragment_too_long_fragment,
5382 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE,
5383 NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
5385 { &hf_dcerpc_fragment_error,
5386 { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE,
5387 NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
5390 { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE,
5391 NULL, 0, "Time between Request and Response for DCE-RPC calls", HFILL }},
5393 { &hf_dcerpc_reassembled_in,
5394 { "Reassembled PDU in frame", "dcerpc.reassembled_in", FT_FRAMENUM, BASE_NONE,
5395 NULL, 0x0, "The DCE/RPC PDU is completely reassembled in the packet with this number", HFILL }},
5397 { &hf_dcerpc_unknown_if_id,
5398 { "Unknown DCERPC interface id", "dcerpc.unknown_if_id", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5400 static gint *ett[] = {
5402 &ett_dcerpc_cn_flags,
5404 &ett_dcerpc_cn_iface,
5405 &ett_dcerpc_cn_trans_syntax,
5407 &ett_dcerpc_dg_flags1,
5408 &ett_dcerpc_dg_flags2,
5409 &ett_dcerpc_pointer_data,
5411 &ett_dcerpc_fragments,
5412 &ett_dcerpc_fragment,
5413 &ett_dcerpc_krb5_auth_verf,
5415 module_t *dcerpc_module;
5417 proto_dcerpc = proto_register_protocol ("DCE RPC", "DCERPC", "dcerpc");
5418 proto_register_field_array (proto_dcerpc, hf, array_length (hf));
5419 proto_register_subtree_array (ett, array_length (ett));
5420 register_init_routine (dcerpc_init_protocol);
5421 dcerpc_module = prefs_register_protocol (proto_dcerpc, NULL);
5422 prefs_register_bool_preference (dcerpc_module,
5424 "Reassemble DCE/RPC messages spanning multiple TCP segments",
5425 "Whether the DCE/RPC dissector should reassemble messages spanning multiple TCP segments."
5426 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
5427 &dcerpc_cn_desegment);
5428 prefs_register_bool_preference (dcerpc_module,
5429 "reassemble_dcerpc",
5430 "Reassemble DCE/RPC fragments",
5431 "Whether the DCE/RPC dissector should reassemble fragmented DCE/RPC PDUs",
5432 &dcerpc_reassemble);
5433 register_init_routine(dcerpc_reassemble_init);
5434 dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
5435 dcerpc_tap=register_tap("dcerpc");
5437 g_hook_list_init(&dcerpc_hooks_init_protos, sizeof(GHook));
5441 proto_reg_handoff_dcerpc (void)
5443 heur_dissector_add ("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
5444 heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
5445 heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
5446 heur_dissector_add ("smb_transact", dissect_dcerpc_cn_smbpipe, proto_dcerpc);
5447 heur_dissector_add ("smb2_heur_subdissectors", dissect_dcerpc_cn_smb2, proto_dcerpc);
5448 heur_dissector_add ("http", dissect_dcerpc_cn_bs, proto_dcerpc);
5449 dcerpc_smb_init(proto_dcerpc);