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/
40 #include <epan/packet.h>
41 #include <epan/dissectors/packet-dcerpc.h>
42 #include <epan/conversation.h>
43 #include <epan/prefs.h>
44 #include <epan/reassemble.h>
46 #include <epan/emem.h>
47 #include <epan/dissectors/packet-frame.h>
48 #include <epan/dissectors/packet-dcerpc-nt.h>
49 #include <epan/expert.h>
50 #include <epan/strutil.h>
52 static int dcerpc_tap = -1;
55 static const value_string pckt_vals[] = {
56 { PDU_REQ, "Request"},
58 { PDU_RESP, "Response"},
59 { PDU_FAULT, "Fault"},
60 { PDU_WORKING, "Working"},
61 { PDU_NOCALL, "Nocall"},
62 { PDU_REJECT, "Reject"},
64 { PDU_CL_CANCEL, "Cl_cancel"},
66 { PDU_CANCEL_ACK, "Cancel_ack"},
68 { PDU_BIND_ACK, "Bind_ack"},
69 { PDU_BIND_NAK, "Bind_nak"},
70 { PDU_ALTER, "Alter_context"},
71 { PDU_ALTER_ACK, "Alter_context_resp"},
72 { PDU_AUTH3, "AUTH3"},
73 { PDU_SHUTDOWN, "Shutdown"},
74 { PDU_CO_CANCEL, "Co_cancel"},
75 { PDU_ORPHANED, "Orphaned"},
79 static const value_string drep_byteorder_vals[] = {
81 { 1, "Little-endian" },
85 static const value_string drep_character_vals[] = {
91 #define DCE_RPC_DREP_FP_IEEE 0
92 #define DCE_RPC_DREP_FP_VAX 1
93 #define DCE_RPC_DREP_FP_CRAY 2
94 #define DCE_RPC_DREP_FP_IBM 3
96 static const value_string drep_fp_vals[] = {
97 { DCE_RPC_DREP_FP_IEEE, "IEEE" },
98 { DCE_RPC_DREP_FP_VAX, "VAX" },
99 { DCE_RPC_DREP_FP_CRAY, "Cray" },
100 { DCE_RPC_DREP_FP_IBM, "IBM" },
105 * Authentication services.
107 static const value_string authn_protocol_vals[] = {
108 { DCE_C_RPC_AUTHN_PROTOCOL_NONE, "None" },
109 { DCE_C_RPC_AUTHN_PROTOCOL_KRB5, "Kerberos 5" },
110 { DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO, "SPNEGO" },
111 { DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP, "NTLMSSP" },
112 { DCE_C_RPC_AUTHN_PROTOCOL_GSS_SCHANNEL, "SCHANNEL SSP" },
113 { DCE_C_RPC_AUTHN_PROTOCOL_GSS_KERBEROS, "Kerberos SSP" },
114 { DCE_C_RPC_AUTHN_PROTOCOL_DPA,
115 "Distributed Password Authentication SSP"},
116 { DCE_C_RPC_AUTHN_PROTOCOL_MSN, "MSN SSP"},
117 { DCE_C_RPC_AUTHN_PROTOCOL_DIGEST, "Digest SSP"},
118 { DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN,"NETLOGON Secure Channel" },
119 { DCE_C_RPC_AUTHN_PROTOCOL_MQ, "MSMQ SSP"},
126 static const value_string authn_level_vals[] = {
127 { DCE_C_AUTHN_LEVEL_NONE, "None" },
128 { DCE_C_AUTHN_LEVEL_CONNECT, "Connect" },
129 { DCE_C_AUTHN_LEVEL_CALL, "Call" },
130 { DCE_C_AUTHN_LEVEL_PKT, "Packet" },
131 { DCE_C_AUTHN_LEVEL_PKT_INTEGRITY, "Packet integrity" },
132 { DCE_C_AUTHN_LEVEL_PKT_PRIVACY, "Packet privacy" },
137 * Flag bits in first flag field in connectionless PDU header.
139 #define PFCL1_RESERVED_01 0x01 /* Reserved for use by implementations */
140 #define PFCL1_LASTFRAG 0x02 /* If set, the PDU is the last
141 * fragment of a multi-PDU
143 #define PFCL1_FRAG 0x04 /* If set, the PDU is a fragment of
144 a multi-PDU transmission */
145 #define PFCL1_NOFACK 0x08 /* If set, the receiver is not
146 * requested to send a `fack' PDU
147 * for the fragment */
148 #define PFCL1_MAYBE 0x10 /* If set, the PDU is for a `maybe'
150 #define PFCL1_IDEMPOTENT 0x20 /* If set, the PDU is for an idempotent
152 #define PFCL1_BROADCAST 0x40 /* If set, the PDU is for a broadcast
154 #define PFCL1_RESERVED_80 0x80 /* Reserved for use by implementations */
157 * Flag bits in second flag field in connectionless PDU header.
159 #define PFCL2_RESERVED_01 0x01 /* Reserved for use by implementations */
160 #define PFCL2_CANCEL_PENDING 0x02 /* Cancel pending at the call end */
161 #define PFCL2_RESERVED_04 0x04 /* Reserved for future use */
162 #define PFCL2_RESERVED_08 0x08 /* Reserved for future use */
163 #define PFCL2_RESERVED_10 0x10 /* Reserved for future use */
164 #define PFCL2_RESERVED_20 0x20 /* Reserved for future use */
165 #define PFCL2_RESERVED_40 0x40 /* Reserved for future use */
166 #define PFCL2_RESERVED_80 0x80 /* Reserved for future use */
169 * Flag bits in connection-oriented PDU header.
171 #define PFC_FIRST_FRAG 0x01 /* First fragment */
172 #define PFC_LAST_FRAG 0x02 /* Last fragment */
173 #define PFC_PENDING_CANCEL 0x04 /* Cancel was pending at sender */
174 #define PFC_RESERVED_1 0x08
175 #define PFC_CONC_MPX 0x10 /* suports concurrent multiplexing
176 * of a single connection. */
177 #define PFC_DID_NOT_EXECUTE 0x20 /* only meaningful on `fault' packet;
178 * if true, guaranteed call did not
180 #define PFC_MAYBE 0x40 /* `maybe' call semantics requested */
181 #define PFC_OBJECT_UUID 0x80 /* if true, a non-nil object UUID
182 * was specified in the handle, and
183 * is present in the optional object
184 * field. If false, the object field
188 * Tests whether a connection-oriented PDU is fragmented; returns TRUE if
189 * it's not fragmented (i.e., this is both the first *and* last fragment),
190 * and FALSE otherwise.
192 #define PFC_NOT_FRAGMENTED(hdr) \
193 ((hdr->flags&(PFC_FIRST_FRAG|PFC_LAST_FRAG))==(PFC_FIRST_FRAG|PFC_LAST_FRAG))
196 * Presentation context negotiation result.
198 static const value_string p_cont_result_vals[] = {
200 { 1, "User rejection" },
201 { 2, "Provider rejection" },
206 * Presentation context negotiation rejection reasons.
208 static const value_string p_provider_reason_vals[] = {
209 { 0, "Reason not specified" },
210 { 1, "Abstract syntax not supported" },
211 { 2, "Proposed transfer syntaxes not supported" },
212 { 3, "Local limit exceeded" },
219 #define REASON_NOT_SPECIFIED 0
220 #define TEMPORARY_CONGESTION 1
221 #define LOCAL_LIMIT_EXCEEDED 2
222 #define CALLED_PADDR_UNKNOWN 3 /* not used */
223 #define PROTOCOL_VERSION_NOT_SUPPORTED 4
224 #define DEFAULT_CONTEXT_NOT_SUPPORTED 5 /* not used */
225 #define USER_DATA_NOT_READABLE 6 /* not used */
226 #define NO_PSAP_AVAILABLE 7 /* not used */
227 #define AUTH_TYPE_NOT_RECOGNIZED 8
228 #define INVALID_CHECKSUM 9
230 static const value_string reject_reason_vals[] = {
231 { REASON_NOT_SPECIFIED, "Reason not specified" },
232 { TEMPORARY_CONGESTION, "Temporary congestion" },
233 { LOCAL_LIMIT_EXCEEDED, "Local limit exceeded" },
234 { CALLED_PADDR_UNKNOWN, "Called paddr unknown" },
235 { PROTOCOL_VERSION_NOT_SUPPORTED, "Protocol version not supported" },
236 { DEFAULT_CONTEXT_NOT_SUPPORTED, "Default context not supported" },
237 { USER_DATA_NOT_READABLE, "User data not readable" },
238 { NO_PSAP_AVAILABLE, "No PSAP available" },
239 { AUTH_TYPE_NOT_RECOGNIZED, "Authentication type not recognized" },
240 { INVALID_CHECKSUM, "Invalid checksum" },
245 * Reject status codes.
247 static const value_string reject_status_vals[] = {
248 { 0, "Stub-defined exception" },
249 { 0x00000001, "nca_s_fault_other" },
250 { 0x00000005, "nca_s_fault_access_denied" },
251 { 0x000006f7, "nca_s_fault_ndr" },
252 { 0x000006d8, "nca_s_fault_cant_perform" },
253 { 0x1c000001, "nca_s_fault_int_div_by_zero" },
254 { 0x1c000002, "nca_s_fault_addr_error" },
255 { 0x1c000003, "nca_s_fault_fp_div_zero" },
256 { 0x1c000004, "nca_s_fault_fp_underflow" },
257 { 0x1c000005, "nca_s_fault_fp_overflow" },
258 { 0x1c000006, "nca_s_fault_invalid_tag" },
259 { 0x1c000007, "nca_s_fault_invalid_bound" },
260 { 0x1c000008, "nca_rpc_version_mismatch" },
261 { 0x1c000009, "nca_unspec_reject" },
262 { 0x1c00000a, "nca_s_bad_actid" },
263 { 0x1c00000b, "nca_who_are_you_failed" },
264 { 0x1c00000c, "nca_manager_not_entered" },
265 { 0x1c00000d, "nca_s_fault_cancel" },
266 { 0x1c00000e, "nca_s_fault_ill_inst" },
267 { 0x1c00000f, "nca_s_fault_fp_error" },
268 { 0x1c000010, "nca_s_fault_int_overflow" },
269 { 0x1c000014, "nca_s_fault_pipe_empty" },
270 { 0x1c000015, "nca_s_fault_pipe_closed" },
271 { 0x1c000016, "nca_s_fault_pipe_order" },
272 { 0x1c000017, "nca_s_fault_pipe_discipline" },
273 { 0x1c000018, "nca_s_fault_pipe_comm_error" },
274 { 0x1c000019, "nca_s_fault_pipe_memory" },
275 { 0x1c00001a, "nca_s_fault_context_mismatch" },
276 { 0x1c00001b, "nca_s_fault_remote_no_memory" },
277 { 0x1c00001c, "nca_invalid_pres_context_id" },
278 { 0x1c00001d, "nca_unsupported_authn_level" },
279 { 0x1c00001f, "nca_invalid_checksum" },
280 { 0x1c000020, "nca_invalid_crc" },
281 { 0x1c000021, "ncs_s_fault_user_defined" },
282 { 0x1c000022, "nca_s_fault_tx_open_failed" },
283 { 0x1c000023, "nca_s_fault_codeset_conv_error" },
284 { 0x1c000024, "nca_s_fault_object_not_found" },
285 { 0x1c000025, "nca_s_fault_no_client_stub" },
286 { 0x1c010002, "nca_op_rng_error" },
287 { 0x1c010003, "nca_unk_if"},
288 { 0x1c010006, "nca_wrong_boot_time" },
289 { 0x1c010009, "nca_s_you_crashed" },
290 { 0x1c01000b, "nca_proto_error" },
291 { 0x1c010013, "nca_out_args_too_big" },
292 { 0x1c010014, "nca_server_too_busy" },
293 { 0x1c010017, "nca_unsupported_type" },
294 /* MS Windows specific values
295 * see: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/system_error_codes__1700-3999_.asp
296 * and: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/seccrypto/security/common_hresult_values.asp
297 * and: http://www.megos.ch/support/doserrors.txt
299 * XXX - we might need a way to dynamically add entries here, as higher layer protocols use these values too,
300 * at least MS protocols (like DCOM) do it that way ... */
301 { 0x80004001, "E_NOTIMPL" },
302 { 0x80004003, "E_POINTER" },
303 { 0x80004004, "E_ABORT" },
304 { 0x8000FFFF, "E_UNEXPECTED" },
305 { 0x80010105, "RPC_E_SERVERFAULT" },
306 { 0x80010108, "RPC_E_DISCONNECTED" },
307 { 0x80010113, "RPC_E_INVALID_IPID" },
308 { 0x8001011F, "RPC_E_TIMEOUT" },
309 { 0x80020003, "DISP_E_MEMBERNOTFOUND" },
310 { 0x80020006, "DISP_E_UNKNOWNNAME" },
311 { 0x8002000E, "DISP_E_BADPARAMCOUNT" },
312 { 0x8004CB00, "CBA_E_MALFORMED" },
313 { 0x8004CB01, "CBA_E_UNKNOWNOBJECT" },
314 { 0x8004CB05, "CBA_E_INVALIDID" },
315 { 0x8004CB09, "CBA_E_INVALIDCOOKIE" },
316 { 0x8004CB0B, "CBA_E_QOSTYPEUNSUPPORTED" },
317 { 0x8004CB0C, "CBA_E_QOSVALUEUNSUPPORTED" },
318 { 0x8004CB0F, "CBA_E_NOTAPPLICABLE" },
319 { 0x8004CB12, "CBA_E_LIMITVIOLATION" },
320 { 0x8004CB13, "CBA_E_QOSTYPENOTAPPLICABLE" },
321 { 0x8004CB18, "CBA_E_OUTOFPARTNERACCOS" },
322 { 0x8004CB1C, "CBA_E_FLAGUNSUPPORTED" },
323 { 0x8004CB23, "CBA_E_FRAMECOUNTUNSUPPORTED" },
324 { 0x8004CB25, "CBA_E_MODECHANGE" },
325 { 0x8007000E, "E_OUTOFMEMORY" },
326 { 0x80070057, "E_INVALIDARG" },
327 { 0x800706d1, "RPC_S_PROCNUM_OUT_OF_RANGE" },
328 { 0x80070776, "OR_INVALID_OXID" },
333 /* we need to keep track of what transport were used, ie what handle we came
334 * in through so we know what kind of pinfo->dce_smb_fid was passed to us.
336 /* Value of -1 is reserved for "not DCE packet" in packet_info.dcetransporttype. */
337 #define DCE_TRANSPORT_UNKNOWN 0
338 #define DCE_CN_TRANSPORT_SMBPIPE 1
341 static int proto_dcerpc = -1;
344 static int hf_dcerpc_request_in = -1;
345 static int hf_dcerpc_time = -1;
346 static int hf_dcerpc_response_in = -1;
347 static int hf_dcerpc_ver = -1;
348 static int hf_dcerpc_ver_minor = -1;
349 static int hf_dcerpc_packet_type = -1;
350 static int hf_dcerpc_cn_flags = -1;
351 static int hf_dcerpc_cn_flags_first_frag = -1;
352 static int hf_dcerpc_cn_flags_last_frag = -1;
353 static int hf_dcerpc_cn_flags_cancel_pending = -1;
354 static int hf_dcerpc_cn_flags_reserved = -1;
355 static int hf_dcerpc_cn_flags_mpx = -1;
356 static int hf_dcerpc_cn_flags_dne = -1;
357 static int hf_dcerpc_cn_flags_maybe = -1;
358 static int hf_dcerpc_cn_flags_object = -1;
359 static int hf_dcerpc_drep = -1;
360 int hf_dcerpc_drep_byteorder = -1;
361 static int hf_dcerpc_drep_character = -1;
362 static int hf_dcerpc_drep_fp = -1;
363 static int hf_dcerpc_cn_frag_len = -1;
364 static int hf_dcerpc_cn_auth_len = -1;
365 static int hf_dcerpc_cn_call_id = -1;
366 static int hf_dcerpc_cn_max_xmit = -1;
367 static int hf_dcerpc_cn_max_recv = -1;
368 static int hf_dcerpc_cn_assoc_group = -1;
369 static int hf_dcerpc_cn_num_ctx_items = -1;
370 static int hf_dcerpc_cn_ctx_item = -1;
371 static int hf_dcerpc_cn_ctx_id = -1;
372 static int hf_dcerpc_cn_num_trans_items = -1;
373 static int hf_dcerpc_cn_bind_abstract_syntax = -1;
374 static int hf_dcerpc_cn_bind_if_id = -1;
375 static int hf_dcerpc_cn_bind_if_ver = -1;
376 static int hf_dcerpc_cn_bind_if_ver_minor = -1;
377 static int hf_dcerpc_cn_bind_trans_syntax = -1;
378 static int hf_dcerpc_cn_bind_trans_id = -1;
379 static int hf_dcerpc_cn_bind_trans_ver = -1;
380 static int hf_dcerpc_cn_alloc_hint = -1;
381 static int hf_dcerpc_cn_sec_addr_len = -1;
382 static int hf_dcerpc_cn_sec_addr = -1;
383 static int hf_dcerpc_cn_num_results = -1;
384 static int hf_dcerpc_cn_ack_result = -1;
385 static int hf_dcerpc_cn_ack_reason = -1;
386 static int hf_dcerpc_cn_ack_trans_id = -1;
387 static int hf_dcerpc_cn_ack_trans_ver = -1;
388 static int hf_dcerpc_cn_reject_reason = -1;
389 static int hf_dcerpc_cn_num_protocols = -1;
390 static int hf_dcerpc_cn_protocol_ver_major = -1;
391 static int hf_dcerpc_cn_protocol_ver_minor = -1;
392 static int hf_dcerpc_cn_cancel_count = -1;
393 static int hf_dcerpc_cn_status = -1;
394 static int hf_dcerpc_cn_deseg_req = -1;
395 static int hf_dcerpc_auth_type = -1;
396 static int hf_dcerpc_auth_level = -1;
397 static int hf_dcerpc_auth_pad_len = -1;
398 static int hf_dcerpc_auth_rsrvd = -1;
399 static int hf_dcerpc_auth_ctx_id = -1;
400 static int hf_dcerpc_dg_flags1 = -1;
401 static int hf_dcerpc_dg_flags1_rsrvd_01 = -1;
402 static int hf_dcerpc_dg_flags1_last_frag = -1;
403 static int hf_dcerpc_dg_flags1_frag = -1;
404 static int hf_dcerpc_dg_flags1_nofack = -1;
405 static int hf_dcerpc_dg_flags1_maybe = -1;
406 static int hf_dcerpc_dg_flags1_idempotent = -1;
407 static int hf_dcerpc_dg_flags1_broadcast = -1;
408 static int hf_dcerpc_dg_flags1_rsrvd_80 = -1;
409 static int hf_dcerpc_dg_flags2 = -1;
410 static int hf_dcerpc_dg_flags2_rsrvd_01 = -1;
411 static int hf_dcerpc_dg_flags2_cancel_pending = -1;
412 static int hf_dcerpc_dg_flags2_rsrvd_04 = -1;
413 static int hf_dcerpc_dg_flags2_rsrvd_08 = -1;
414 static int hf_dcerpc_dg_flags2_rsrvd_10 = -1;
415 static int hf_dcerpc_dg_flags2_rsrvd_20 = -1;
416 static int hf_dcerpc_dg_flags2_rsrvd_40 = -1;
417 static int hf_dcerpc_dg_flags2_rsrvd_80 = -1;
418 static int hf_dcerpc_dg_serial_hi = -1;
419 static int hf_dcerpc_obj_id = -1;
420 static int hf_dcerpc_dg_if_id = -1;
421 static int hf_dcerpc_dg_act_id = -1;
422 static int hf_dcerpc_dg_serial_lo = -1;
423 static int hf_dcerpc_dg_ahint = -1;
424 static int hf_dcerpc_dg_ihint = -1;
425 static int hf_dcerpc_dg_frag_len = -1;
426 static int hf_dcerpc_dg_frag_num = -1;
427 static int hf_dcerpc_dg_auth_proto = -1;
428 static int hf_dcerpc_opnum = -1;
429 static int hf_dcerpc_dg_seqnum = -1;
430 static int hf_dcerpc_dg_server_boot = -1;
431 static int hf_dcerpc_dg_if_ver = -1;
432 static int hf_dcerpc_krb5_av_prot_level = -1;
433 static int hf_dcerpc_krb5_av_key_vers_num = -1;
434 static int hf_dcerpc_krb5_av_key_auth_verifier = -1;
435 static int hf_dcerpc_dg_cancel_vers = -1;
436 static int hf_dcerpc_dg_cancel_id = -1;
437 static int hf_dcerpc_dg_server_accepting_cancels = -1;
438 static int hf_dcerpc_dg_fack_vers = -1;
439 static int hf_dcerpc_dg_fack_window_size = -1;
440 static int hf_dcerpc_dg_fack_max_tsdu = -1;
441 static int hf_dcerpc_dg_fack_max_frag_size = -1;
442 static int hf_dcerpc_dg_fack_serial_num = -1;
443 static int hf_dcerpc_dg_fack_selack_len = -1;
444 static int hf_dcerpc_dg_fack_selack = -1;
445 static int hf_dcerpc_dg_status = -1;
446 static int hf_dcerpc_array_max_count = -1;
447 static int hf_dcerpc_array_offset = -1;
448 static int hf_dcerpc_array_actual_count = -1;
449 static int hf_dcerpc_array_buffer = -1;
450 static int hf_dcerpc_op = -1;
451 static int hf_dcerpc_referent_id = -1;
452 static int hf_dcerpc_fragments = -1;
453 static int hf_dcerpc_fragment = -1;
454 static int hf_dcerpc_fragment_overlap = -1;
455 static int hf_dcerpc_fragment_overlap_conflict = -1;
456 static int hf_dcerpc_fragment_multiple_tails = -1;
457 static int hf_dcerpc_fragment_too_long_fragment = -1;
458 static int hf_dcerpc_fragment_error = -1;
459 static int hf_dcerpc_reassembled_in = -1;
460 static int hf_dcerpc_unknown_if_id = -1;
462 static gint ett_dcerpc = -1;
463 static gint ett_dcerpc_cn_flags = -1;
464 static gint ett_dcerpc_cn_ctx = -1;
465 static gint ett_dcerpc_cn_iface = -1;
466 static gint ett_dcerpc_cn_trans_syntax = -1;
467 static gint ett_dcerpc_drep = -1;
468 static gint ett_dcerpc_dg_flags1 = -1;
469 static gint ett_dcerpc_dg_flags2 = -1;
470 static gint ett_dcerpc_pointer_data = -1;
471 static gint ett_dcerpc_string = -1;
472 static gint ett_dcerpc_fragments = -1;
473 static gint ett_dcerpc_fragment = -1;
474 static gint ett_dcerpc_krb5_auth_verf = -1;
476 static const fragment_items dcerpc_frag_items = {
477 &ett_dcerpc_fragments,
478 &ett_dcerpc_fragment,
480 &hf_dcerpc_fragments,
482 &hf_dcerpc_fragment_overlap,
483 &hf_dcerpc_fragment_overlap_conflict,
484 &hf_dcerpc_fragment_multiple_tails,
485 &hf_dcerpc_fragment_too_long_fragment,
486 &hf_dcerpc_fragment_error,
492 /* list of hooks to be called when init_protocols is done */
493 GHookList dcerpc_hooks_init_protos;
498 static dcerpc_info di[20];
499 static int di_counter=0;
505 return &di[di_counter];
508 /* try to desegment big DCE/RPC packets over TCP? */
509 static gboolean dcerpc_cn_desegment = TRUE;
511 /* reassemble DCE/RPC fragments */
512 /* reassembly of cl dcerpc fragments will not work for the case where ONE frame
513 might contain multiple dcerpc fragments for different PDUs.
514 this case would be so unusual/weird so if you got captures like that:
517 reassembly of co dcerpc fragments will not work for the case where TCP/SMB frames
518 are coming in out of sequence, but that will hurt in a lot of other places as well.
520 static gboolean dcerpc_reassemble = TRUE;
521 static GHashTable *dcerpc_co_fragment_table = NULL;
522 static GHashTable *dcerpc_co_reassemble_table = NULL;
523 static GHashTable *dcerpc_cl_reassemble_table = NULL;
526 dcerpc_reassemble_init(void)
528 fragment_table_init(&dcerpc_co_fragment_table);
529 reassembled_table_init(&dcerpc_co_reassemble_table);
530 dcerpc_fragment_table_init(&dcerpc_cl_reassemble_table);
534 * Authentication subdissectors. Used to dissect authentication blobs in
535 * DCERPC binds, requests and responses.
538 typedef struct _dcerpc_auth_subdissector {
541 dcerpc_auth_subdissector_fns auth_fns;
542 } dcerpc_auth_subdissector;
544 static GSList *dcerpc_auth_subdissector_list;
546 static dcerpc_auth_subdissector_fns *get_auth_subdissector_fns(
547 guint8 auth_level, guint8 auth_type)
552 for (i = 0; (data = g_slist_nth_data(dcerpc_auth_subdissector_list, i)); i++) {
553 dcerpc_auth_subdissector *asd = (dcerpc_auth_subdissector *)data;
554 if (asd->auth_level == auth_level &&
555 asd->auth_type == auth_type)
556 return &asd->auth_fns;
562 void register_dcerpc_auth_subdissector(guint8 auth_level, guint8 auth_type,
563 dcerpc_auth_subdissector_fns *fns)
565 dcerpc_auth_subdissector *d;
567 if (get_auth_subdissector_fns(auth_level, auth_type))
570 d = (dcerpc_auth_subdissector *)g_malloc(sizeof(dcerpc_auth_subdissector));
572 d->auth_level = auth_level;
573 d->auth_type = auth_type;
574 memcpy(&d->auth_fns, fns, sizeof(dcerpc_auth_subdissector_fns));
576 dcerpc_auth_subdissector_list = g_slist_append(dcerpc_auth_subdissector_list, d);
579 /* Hand off verifier data to a registered dissector */
581 static void dissect_auth_verf(tvbuff_t *auth_tvb, packet_info *pinfo,
583 dcerpc_auth_subdissector_fns *auth_fns,
584 e_dce_cn_common_hdr_t *hdr,
585 dcerpc_auth_info *auth_info)
587 dcerpc_dissect_fnct_t *volatile fn = NULL;
589 switch (hdr->ptype) {
592 fn = auth_fns->bind_fn;
596 fn = auth_fns->bind_ack_fn;
599 fn = auth_fns->auth3_fn;
602 fn = auth_fns->req_verf_fn;
605 fn = auth_fns->resp_verf_fn;
608 /* Don't know how to handle authentication data in this
612 g_warning("attempt to dissect %s pdu authentication data",
613 val_to_str(hdr->ptype, pckt_vals, "Unknown (%u)"));
618 fn(auth_tvb, 0, pinfo, tree, hdr->drep);
620 tvb_ensure_bytes_exist(auth_tvb, 0, hdr->auth_len);
621 proto_tree_add_text(tree, auth_tvb, 0, hdr->auth_len,
623 val_to_str(auth_info->auth_type,
629 /* Hand off payload data to a registered dissector */
631 static tvbuff_t *decode_encrypted_data(tvbuff_t *data_tvb,
634 dcerpc_auth_subdissector_fns *auth_fns,
636 dcerpc_auth_info *auth_info)
638 dcerpc_decode_data_fnct_t *fn;
641 fn = auth_fns->req_data_fn;
643 fn = auth_fns->resp_data_fn;
646 return fn(data_tvb, auth_tvb, 0, pinfo, auth_info);
655 /* the registered subdissectors */
656 GHashTable *dcerpc_uuids=NULL;
659 dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2)
661 const dcerpc_uuid_key *key1 = (const dcerpc_uuid_key *)k1;
662 const dcerpc_uuid_key *key2 = (const dcerpc_uuid_key *)k2;
663 return ((memcmp (&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
664 && (key1->ver == key2->ver));
668 dcerpc_uuid_hash (gconstpointer k)
670 const dcerpc_uuid_key *key = (const dcerpc_uuid_key *)k;
671 /* This isn't perfect, but the Data1 part of these is almost always
673 return key->uuid.Data1;
677 dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver,
678 dcerpc_sub_dissector *procs, int opnum_hf)
680 dcerpc_uuid_key *key = g_malloc (sizeof (*key));
681 dcerpc_uuid_value *value = g_malloc (sizeof (*value));
682 header_field_info *hf_info;
683 module_t *samr_module;
684 const char *filter_name = proto_get_protocol_filter_name(proto);
689 value->proto = find_protocol_by_id(proto);
690 value->proto_id = proto;
692 value->name = proto_get_protocol_short_name (value->proto);
693 value->procs = procs;
694 value->opnum_hf = opnum_hf;
696 g_hash_table_insert (dcerpc_uuids, key, value);
698 hf_info = proto_registrar_get_nth(opnum_hf);
699 hf_info->strings = value_string_from_subdissectors(procs);
701 /* add this GUID to the global name resolving */
702 guids_add_uuid(uuid, proto_get_protocol_short_name (value->proto));
704 /* Register the samr.nt_password preference as obsolete */
705 /* This should be in packet-dcerpc-samr.c */
706 if (strcmp(filter_name, "samr") == 0) {
707 samr_module = prefs_register_protocol (proto, NULL);
708 prefs_register_obsolete_preference(samr_module, "nt_password");
712 /* Function to find the name of a registered protocol
713 * or NULL if the protocol/version is not known to wireshark.
716 dcerpc_get_proto_name(e_uuid_t *uuid, guint16 ver)
719 dcerpc_uuid_value *sub_proto;
723 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
726 return sub_proto->name;
729 /* Function to find the opnum hf-field of a registered protocol
730 * or -1 if the protocol/version is not known to wireshark.
733 dcerpc_get_proto_hf_opnum(e_uuid_t *uuid, guint16 ver)
736 dcerpc_uuid_value *sub_proto;
740 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
743 return sub_proto->opnum_hf;
746 /* Create a value_string consisting of DCERPC opnum and name from a
747 subdissector array. */
749 value_string *value_string_from_subdissectors(dcerpc_sub_dissector *sd)
751 value_string *vs = NULL;
755 for (i = 0; sd[i].name; i++) {
757 vs[i].value = sd[i].num;
758 vs[i].strptr = sd[i].name;
764 vs = g_malloc((num_sd + 1) * sizeof(value_string));
768 vs[num_sd].value = 0;
769 vs[num_sd].strptr = NULL;
774 /* Function to find the subdissector table of a registered protocol
775 * or NULL if the protocol/version is not known to wireshark.
777 dcerpc_sub_dissector *
778 dcerpc_get_proto_sub_dissector(e_uuid_t *uuid, guint16 ver)
781 dcerpc_uuid_value *sub_proto;
785 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
788 return sub_proto->procs;
793 * To keep track of ctx_id mappings.
795 * Everytime we see a bind call we update this table.
796 * Note that we always specify a SMB FID. For non-SMB transports this
799 static GHashTable *dcerpc_binds=NULL;
801 typedef struct _dcerpc_bind_key {
802 conversation_t *conv;
807 typedef struct _dcerpc_bind_value {
813 dcerpc_bind_equal (gconstpointer k1, gconstpointer k2)
815 const dcerpc_bind_key *key1 = (const dcerpc_bind_key *)k1;
816 const dcerpc_bind_key *key2 = (const dcerpc_bind_key *)k2;
817 return (key1->conv == key2->conv
818 && key1->ctx_id == key2->ctx_id
819 && key1->smb_fid == key2->smb_fid);
823 dcerpc_bind_hash (gconstpointer k)
825 const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
828 hash=GPOINTER_TO_UINT(key->conv) + key->ctx_id + key->smb_fid;
834 * To keep track of callid mappings. Should really use some generic
835 * conversation support instead.
837 static GHashTable *dcerpc_cn_calls=NULL;
838 static GHashTable *dcerpc_dg_calls=NULL;
840 typedef struct _dcerpc_cn_call_key {
841 conversation_t *conv;
844 } dcerpc_cn_call_key;
846 typedef struct _dcerpc_dg_call_key {
847 conversation_t *conv;
850 } dcerpc_dg_call_key;
854 dcerpc_cn_call_equal (gconstpointer k1, gconstpointer k2)
856 const dcerpc_cn_call_key *key1 = (const dcerpc_cn_call_key *)k1;
857 const dcerpc_cn_call_key *key2 = (const dcerpc_cn_call_key *)k2;
858 return (key1->conv == key2->conv
859 && key1->call_id == key2->call_id
860 && key1->smb_fid == key2->smb_fid);
864 dcerpc_dg_call_equal (gconstpointer k1, gconstpointer k2)
866 const dcerpc_dg_call_key *key1 = (const dcerpc_dg_call_key *)k1;
867 const dcerpc_dg_call_key *key2 = (const dcerpc_dg_call_key *)k2;
868 return (key1->conv == key2->conv
869 && key1->seqnum == key2->seqnum
870 && (memcmp (&key1->act_id, &key2->act_id, sizeof (e_uuid_t)) == 0));
874 dcerpc_cn_call_hash (gconstpointer k)
876 const dcerpc_cn_call_key *key = (const dcerpc_cn_call_key *)k;
877 return GPOINTER_TO_UINT(key->conv) + key->call_id + key->smb_fid;
881 dcerpc_dg_call_hash (gconstpointer k)
883 const dcerpc_dg_call_key *key = (const dcerpc_dg_call_key *)k;
884 return (GPOINTER_TO_UINT(key->conv) + key->seqnum + key->act_id.Data1
885 + (key->act_id.Data2 << 16) + key->act_id.Data3
886 + (key->act_id.Data4[0] << 24) + (key->act_id.Data4[1] << 16)
887 + (key->act_id.Data4[2] << 8) + (key->act_id.Data4[3] << 0)
888 + (key->act_id.Data4[4] << 24) + (key->act_id.Data4[5] << 16)
889 + (key->act_id.Data4[6] << 8) + (key->act_id.Data4[7] << 0));
893 /* to keep track of matched calls/responses
894 this one uses the same value struct as calls, but the key is the frame id
895 and call id; there can be more than one call in a frame.
897 XXX - why not just use the same keys as are used for calls?
900 static GHashTable *dcerpc_matched=NULL;
902 typedef struct _dcerpc_matched_key {
905 } dcerpc_matched_key;
908 dcerpc_matched_equal (gconstpointer k1, gconstpointer k2)
910 const dcerpc_matched_key *key1 = (const dcerpc_matched_key *)k1;
911 const dcerpc_matched_key *key2 = (const dcerpc_matched_key *)k2;
912 return (key1->frame == key2->frame
913 && key1->call_id == key2->call_id);
917 dcerpc_matched_hash (gconstpointer k)
919 const dcerpc_matched_key *key = (const dcerpc_matched_key *)k;
926 * Utility functions. Modeled after packet-rpc.c
930 dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
931 proto_tree *tree, guint8 *drep,
932 int hfindex, guint8 *pdata)
936 data = tvb_get_guint8 (tvb, offset);
938 proto_tree_add_item (tree, hfindex, tvb, offset, 1, (drep[0] & 0x10));
946 dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
947 proto_tree *tree, guint8 *drep,
948 int hfindex, guint16 *pdata)
952 data = ((drep[0] & 0x10)
953 ? tvb_get_letohs (tvb, offset)
954 : tvb_get_ntohs (tvb, offset));
957 proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10));
965 dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
966 proto_tree *tree, guint8 *drep,
967 int hfindex, guint32 *pdata)
971 data = ((drep[0] & 0x10)
972 ? tvb_get_letohl (tvb, offset)
973 : tvb_get_ntohl (tvb, offset));
976 proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10));
983 /* handles 32 bit unix time_t */
985 dissect_dcerpc_time_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
986 proto_tree *tree, guint8 *drep,
987 int hfindex, guint32 *pdata)
992 data = ((drep[0] & 0x10)
993 ? tvb_get_letohl (tvb, offset)
994 : tvb_get_ntohl (tvb, offset));
999 if(data==0xffffffff){
1000 /* special case, no time specified */
1001 proto_tree_add_time_format_value(tree, hfindex, tvb, offset, 4, &tv, "No time specified");
1003 proto_tree_add_time (tree, hfindex, tvb, offset, 4, &tv);
1013 dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1014 proto_tree *tree, guint8 *drep,
1015 int hfindex, guint64 *pdata)
1019 data = ((drep[0] & 0x10)
1020 ? tvb_get_letoh64 (tvb, offset)
1021 : tvb_get_ntoh64 (tvb, offset));
1024 proto_tree_add_item(tree, hfindex, tvb, offset, 8, (drep[0] & 0x10));
1033 dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1034 proto_tree *tree, guint8 *drep,
1035 int hfindex, gfloat *pdata)
1041 case(DCE_RPC_DREP_FP_IEEE):
1042 data = ((drep[0] & 0x10)
1043 ? tvb_get_letohieee_float(tvb, offset)
1044 : tvb_get_ntohieee_float(tvb, offset));
1046 proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
1049 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
1050 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1051 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
1053 /* ToBeDone: non IEEE floating formats */
1054 /* Set data to a negative infinity value */
1057 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep[1]);
1067 dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1068 proto_tree *tree, guint8 *drep,
1069 int hfindex, gdouble *pdata)
1075 case(DCE_RPC_DREP_FP_IEEE):
1076 data = ((drep[0] & 0x10)
1077 ? tvb_get_letohieee_double(tvb, offset)
1078 : tvb_get_ntohieee_double(tvb, offset));
1080 proto_tree_add_double(tree, hfindex, tvb, offset, 8, data);
1083 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
1084 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1085 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
1087 /* ToBeDone: non IEEE double formats */
1088 /* Set data to a negative infinity value */
1089 data = -G_MAXDOUBLE;
1091 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep[1]);
1101 dissect_dcerpc_uuid_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1102 proto_tree *tree, guint8 *drep,
1103 int hfindex, e_uuid_t *pdata)
1108 if (drep[0] & 0x10) {
1109 tvb_get_letohguid (tvb, offset, (e_guid_t *) &uuid);
1111 tvb_get_ntohguid (tvb, offset, (e_guid_t *) &uuid);
1114 proto_tree_add_guid(tree, hfindex, tvb, offset, 16, (e_guid_t *) &uuid);
1124 * a couple simpler things
1127 dcerpc_tvb_get_ntohs (tvbuff_t *tvb, gint offset, guint8 *drep)
1129 if (drep[0] & 0x10) {
1130 return tvb_get_letohs (tvb, offset);
1132 return tvb_get_ntohs (tvb, offset);
1137 dcerpc_tvb_get_ntohl (tvbuff_t *tvb, gint offset, guint8 *drep)
1139 if (drep[0] & 0x10) {
1140 return tvb_get_letohl (tvb, offset);
1142 return tvb_get_ntohl (tvb, offset);
1147 dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, guint8 *drep, e_uuid_t *uuid)
1149 if (drep[0] & 0x10) {
1150 tvb_get_letohguid (tvb, offset, (e_guid_t *) uuid);
1152 tvb_get_ntohguid (tvb, offset, (e_guid_t *) uuid);
1158 /* function to dissect a unidimensional conformant array */
1160 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1161 proto_tree *tree, guint8 *drep,
1162 dcerpc_dissect_fnct_t *fnct)
1168 di=pinfo->private_data;
1169 if(di->conformant_run){
1170 /* conformant run, just dissect the max_count header */
1172 di->conformant_run=0;
1173 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1174 hf_dcerpc_array_max_count, &di->array_max_count);
1175 di->array_max_count_offset=offset-4;
1176 di->conformant_run=1;
1177 di->conformant_eaten=offset-old_offset;
1179 /* we don't remember where in the bytestream this field was */
1180 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1182 /* real run, dissect the elements */
1183 for(i=0;i<di->array_max_count;i++){
1184 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1190 /* function to dissect a unidimensional conformant and varying array */
1192 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1193 proto_tree *tree, guint8 *drep,
1194 dcerpc_dissect_fnct_t *fnct)
1200 di=pinfo->private_data;
1201 if(di->conformant_run){
1202 /* conformant run, just dissect the max_count header */
1204 di->conformant_run=0;
1205 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1206 hf_dcerpc_array_max_count, &di->array_max_count);
1207 di->array_max_count_offset=offset-4;
1208 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1209 hf_dcerpc_array_offset, &di->array_offset);
1210 di->array_offset_offset=offset-4;
1211 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1212 hf_dcerpc_array_actual_count, &di->array_actual_count);
1213 di->array_actual_count_offset=offset-4;
1214 di->conformant_run=1;
1215 di->conformant_eaten=offset-old_offset;
1217 /* we dont dont remember where in the bytestream these fields were */
1218 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1219 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
1220 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
1222 /* real run, dissect the elements */
1223 for(i=0;i<di->array_actual_count;i++){
1224 old_offset = offset;
1225 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1226 if (offset <= old_offset)
1227 THROW(ReportedBoundsError);
1233 /* function to dissect a unidimensional varying array */
1235 dissect_ndr_uvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1236 proto_tree *tree, guint8 *drep,
1237 dcerpc_dissect_fnct_t *fnct)
1243 di=pinfo->private_data;
1244 if(di->conformant_run){
1245 /* conformant run, just dissect the max_count header */
1247 di->conformant_run=0;
1248 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1249 hf_dcerpc_array_offset, &di->array_offset);
1250 di->array_offset_offset=offset-4;
1251 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1252 hf_dcerpc_array_actual_count, &di->array_actual_count);
1253 di->array_actual_count_offset=offset-4;
1254 di->conformant_run=1;
1255 di->conformant_eaten=offset-old_offset;
1257 /* we dont dont remember where in the bytestream these fields were */
1258 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
1259 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
1261 /* real run, dissect the elements */
1262 for(i=0;i<di->array_actual_count;i++){
1263 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1270 /* Dissect an string of bytes. This corresponds to
1271 IDL of the form '[string] byte *foo'.
1273 It can also be used for a conformant varying array of bytes if
1274 the contents of the array should be shown as a big blob, rather
1275 than showing each byte as an individual element.
1277 XXX - which of those is really the IDL type for, for example,
1278 the encrypted data in some MAPI packets? (Microsoft haven't
1281 XXX - does this need to do all the conformant array stuff that
1282 "dissect_ndr_ucvarray()" does? These are presumably for strings
1283 that are conformant and varying - they're stored like conformant
1284 varying arrays of bytes. */
1286 dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo,
1287 proto_tree *tree, guint8 *drep)
1292 di=pinfo->private_data;
1293 if(di->conformant_run){
1294 /* just a run to handle conformant arrays, no scalars to dissect */
1298 /* NDR array header */
1300 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1301 hf_dcerpc_array_max_count, NULL);
1303 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1304 hf_dcerpc_array_offset, NULL);
1306 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1307 hf_dcerpc_array_actual_count, &len);
1310 tvb_ensure_bytes_exist(tvb, offset, len);
1311 proto_tree_add_item(tree, hf_dcerpc_array_buffer,
1312 tvb, offset, len, drep[0] & 0x10);
1320 /* For dissecting arrays that are to be interpreted as strings. */
1322 /* Dissect an NDR conformant varying string of elements.
1323 The length of each element is given by the 'size_is' parameter;
1324 the elements are assumed to be characters or wide characters.
1326 XXX - does this need to do all the conformant array stuff that
1327 "dissect_ndr_ucvarray()" does? */
1329 dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1330 proto_tree *tree, guint8 *drep, int size_is,
1331 int hfindex, gboolean add_subtree, char **data)
1334 proto_item *string_item;
1335 proto_tree *string_tree;
1336 guint32 len, buffer_len, 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.) */
1463 /* This function should be duplicated to handle properly null terminated strings*/
1465 dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1466 proto_tree *tree, guint8 *drep)
1469 di=pinfo->private_data;
1471 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1472 sizeof(guint16), di->hf_index,
1476 /* This function is aimed for PIDL useage and dissects a UNIQUE pointer to
1480 PIDL_dissect_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep, int chsize, int hfindex, guint32 param)
1484 gint levels = CB_STR_ITEM_LEVELS(param);
1486 di=pinfo->private_data;
1488 offset = dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1492 if(!di->conformant_run){
1493 /* Append string to COL_INFO */
1494 if (param & PIDL_SET_COL_INFO) {
1495 if (check_col(pinfo->cinfo, COL_INFO))
1496 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", s);
1498 /* Save string to dcv->private_data */
1499 if((param & PIDL_STR_SAVE)
1500 && (!pinfo->fd->flags.visited)){
1501 dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1502 dcv->private_data = se_strdup(s);
1504 /* Append string to upper-level proto_items */
1505 if (levels > 0 && tree && s && s[0]) {
1506 proto_item_append_text(tree, ": %s", s);
1507 tree = tree->parent;
1510 proto_item_append_text(tree, ": %s", s);
1511 tree = tree->parent;
1513 while (levels > 0) {
1514 proto_item_append_text(tree, " %s", s);
1515 tree = tree->parent;
1527 /* Dissect an NDR varying string of elements.
1528 The length of each element is given by the 'size_is' parameter;
1529 the elements are assumed to be characters or wide characters.
1532 dissect_ndr_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1533 proto_tree *tree, guint8 *drep, int size_is,
1534 int hfindex, gboolean add_subtree, char **data)
1537 proto_item *string_item;
1538 proto_tree *string_tree;
1539 guint32 len, buffer_len;
1541 header_field_info *hfinfo;
1543 di=pinfo->private_data;
1544 if(di->conformant_run){
1545 /* just a run to handle conformant arrays, no scalars to dissect */
1550 string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1551 proto_registrar_get_name(hfindex));
1552 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1558 /* NDR array header */
1559 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1560 hf_dcerpc_array_offset, NULL);
1562 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1563 hf_dcerpc_array_actual_count, &len);
1565 buffer_len = size_is * len;
1568 if (offset % size_is)
1569 offset += size_is - (offset % size_is);
1571 if (size_is == sizeof(guint16)) {
1572 /* XXX - use drep to determine the byte order? */
1573 s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
1575 * XXX - we don't support a string type with Unicode
1576 * characters, so if this is a string item, we make
1577 * its value be the "fake Unicode" string.
1579 if (tree && buffer_len) {
1580 hfinfo = proto_registrar_get_nth(hfindex);
1581 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1582 if (hfinfo->type == FT_STRING) {
1583 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1586 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1587 buffer_len, drep[0] & 0x10);
1592 * "tvb_get_ephemeral_string()" throws an exception if the entire string
1593 * isn't in the tvbuff. If the length is bogus, this should
1594 * keep us from trying to allocate an immensely large buffer.
1595 * (It won't help if the length is *valid* but immensely large,
1596 * but that's another matter; in any case, that would happen only
1597 * if we had an immensely large tvbuff....)
1599 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1600 s = tvb_get_ephemeral_string(tvb, offset, buffer_len);
1601 if (tree && buffer_len)
1602 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1603 buffer_len, drep[0] & 0x10);
1606 if (string_item != NULL)
1607 proto_item_append_text(string_item, ": %s", s);
1612 offset += buffer_len;
1614 proto_item_set_end(string_item, tvb, offset);
1619 /* Dissect an varying string of chars.
1620 This corresponds to IDL of the form '[string] char *foo'.
1622 XXX - at least according to the DCE RPC 1.1 spec, a string has
1623 a null terminator, which isn't necessary as a terminator for
1624 the transfer language (as there's a length), but is presumably
1625 there for the benefit of null-terminated-string languages
1626 such as C. Is this ever used for purely counted strings?
1627 (Not that it matters if it is.) */
1629 dissect_ndr_char_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1630 proto_tree *tree, guint8 *drep)
1633 di=pinfo->private_data;
1635 return dissect_ndr_vstring(tvb, offset, pinfo, tree, drep,
1636 sizeof(guint8), di->hf_index,
1640 /* Dissect a varying string of wchars (wide characters).
1641 This corresponds to IDL of the form '[string] wchar *foo'
1643 XXX - at least according to the DCE RPC 1.1 spec, a string has
1644 a null terminator, which isn't necessary as a terminator for
1645 the transfer language (as there's a length), but is presumably
1646 there for the benefit of null-terminated-string languages
1647 such as C. Is this ever used for purely counted strings?
1648 (Not that it matters if it is.) */
1650 dissect_ndr_wchar_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1651 proto_tree *tree, guint8 *drep)
1654 di=pinfo->private_data;
1656 return dissect_ndr_vstring(tvb, offset, pinfo, tree, drep,
1657 sizeof(guint16), di->hf_index,
1662 /* ndr pointer handling */
1663 /* list of pointers encountered so far */
1664 static GSList *ndr_pointer_list = NULL;
1666 /* position where in the list to insert newly encountered pointers */
1667 static int ndr_pointer_list_pos=0;
1669 /* boolean controlling whether pointers are top-level or embedded */
1670 static gboolean pointers_are_top_level = TRUE;
1672 /* as a kludge, we represent all embedded reference pointers as id==-1
1673 hoping that his will not collide with any non-ref pointers */
1674 typedef struct ndr_pointer_data {
1676 proto_item *item; /* proto_item for pointer */
1677 proto_tree *tree; /* subtree of above item */
1678 dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
1680 dcerpc_callback_fnct_t *callback;
1681 void *callback_args;
1682 } ndr_pointer_data_t;
1685 init_ndr_pointer_list(packet_info *pinfo)
1689 di=pinfo->private_data;
1690 di->conformant_run=0;
1692 while(ndr_pointer_list){
1693 ndr_pointer_data_t *npd;
1695 npd=g_slist_nth_data(ndr_pointer_list, 0);
1696 ndr_pointer_list=g_slist_remove(ndr_pointer_list, npd);
1700 ndr_pointer_list=NULL;
1701 ndr_pointer_list_pos=0;
1702 pointers_are_top_level=TRUE;
1706 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, guint8 *drep)
1708 int found_new_pointer;
1714 di=pinfo->private_data;
1718 found_new_pointer=0;
1719 len=g_slist_length(ndr_pointer_list);
1720 for(i=next_pointer;i<len;i++){
1721 ndr_pointer_data_t *tnpd;
1722 tnpd=g_slist_nth_data(ndr_pointer_list, i);
1724 dcerpc_dissect_fnct_t *fnct;
1727 found_new_pointer=1;
1730 ndr_pointer_list_pos=i+1;
1731 di->hf_index=tnpd->hf_index;
1732 /* first a run to handle any conformant
1734 di->conformant_run=1;
1735 di->conformant_eaten=0;
1736 old_offset = offset;
1737 offset = (*(fnct))(tvb, offset, pinfo, NULL, drep);
1739 DISSECTOR_ASSERT((offset-old_offset)==di->conformant_eaten);
1740 /* This is to check for any bugs in the dissectors.
1742 * Basically, the NDR representation will store all
1743 * arrays in two blocks, one block with the dimension
1744 * discreption, like size, number of elements and such,
1745 * and another block that contains the actual data stored
1747 * If the array is embedded directly inside another,
1748 * encapsulating aggregate type, like a union or struct,
1749 * then these two blocks will be stored at different places
1750 * in the bytestream, with other data between the blocks.
1752 * For this reason, all pointers to types (both aggregate
1753 * and scalar, for simplicity no distinction is made)
1754 * will have its dissector called twice.
1755 * The dissector will first be called with conformant_run==1
1756 * in which mode the dissector MUST NOT consume any data from
1757 * the tvbuff (i.e. may not dissect anything) except the
1758 * initial control block for arrays.
1759 * The second time the dissector is called, with
1760 * conformant_run==0, all other data for the type will be
1763 * All dissect_ndr_<type> dissectors are already prepared
1764 * for this and knows when it should eat data from the tvb
1765 * and when not to, so implementors of dissectors will
1766 * normally not need to worry about this or even know about
1767 * it. However, if a dissector for an aggregate type calls
1768 * a subdissector from outside packet-dcerpc.c, such as
1769 * the dissector in packet-smb.c for NT Security Descriptors
1770 * as an example, then it is VERY important to encapsulate
1771 * this call to an external subdissector with the appropriate
1772 * test for conformant_run, i.e. it will need something like
1776 * di=pinfo->private_data;
1777 * if(di->conformant_run){
1781 * to make sure it makes the right thing.
1782 * This assert will signal when someone has forgotten to
1783 * make the dissector aware of this requirement.
1786 /* now we dissect the actual pointer */
1787 di->conformant_run=0;
1788 old_offset = offset;
1789 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, drep);
1791 tnpd->callback(pinfo, tnpd->tree, tnpd->item, tvb, old_offset, offset, tnpd->callback_args);
1795 } while(found_new_pointer);
1802 add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
1803 dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index,
1804 dcerpc_callback_fnct_t *callback, void *callback_args)
1806 ndr_pointer_data_t *npd;
1808 /* check if this pointer is valid */
1811 dcerpc_call_value *value;
1813 di=pinfo->private_data;
1814 value=di->call_data;
1816 if(di->ptype == PDU_REQ){
1817 if(!(pinfo->fd->flags.visited)){
1818 if(id>value->max_ptr){
1823 /* if we havent seen the request bail out since we cant
1824 know whether this is the first non-NULL instance
1826 if(value->req_frame==0){
1827 /* XXX THROW EXCEPTION */
1830 /* We saw this one in the request frame, nothing to
1832 if(id<=value->max_ptr){
1838 npd=g_malloc(sizeof(ndr_pointer_data_t));
1843 npd->hf_index=hf_index;
1844 npd->callback=callback;
1845 npd->callback_args=callback_args;
1846 ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
1847 ndr_pointer_list_pos);
1848 ndr_pointer_list_pos++;
1853 find_pointer_index(guint32 id)
1855 ndr_pointer_data_t *npd;
1858 len=g_slist_length(ndr_pointer_list);
1860 npd=g_slist_nth_data(ndr_pointer_list, i);
1871 /* This function dissects an NDR pointer and stores the callback for later
1872 * deferred dissection.
1874 * fnct is the callback function for when we have reached this object in
1877 * type is what type of pointer.
1879 * this is text is what text we should put in any created tree node.
1881 * hf_index is what hf value we want to pass to the callback function when
1882 * it is called, the callback can later pich this one up from di->hf_index.
1884 * callback is executed after the pointer has been dereferenced.
1886 * callback_args is passed as an argument to the callback function
1888 * See packet-dcerpc-samr.c for examples
1891 dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1892 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
1893 int type, const char *text, int hf_index,
1894 dcerpc_callback_fnct_t *callback, void *callback_args)
1897 proto_tree *tr = NULL;
1898 gint start_offset = offset;
1900 di=pinfo->private_data;
1901 if(di->conformant_run){
1902 /* this call was only for dissecting the header for any
1903 embedded conformant array. we will not parse any
1904 pointers in this mode.
1908 /*TOP LEVEL REFERENCE POINTER*/
1909 if( pointers_are_top_level
1910 &&(type==NDR_POINTER_REF) ){
1913 /* we must find out a nice way to do the length here */
1914 item=proto_tree_add_text(tree, tvb, offset, 0,
1916 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1918 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1919 hf_index, callback, callback_args);
1923 /*TOP LEVEL FULL POINTER*/
1924 if( pointers_are_top_level
1925 && (type==NDR_POINTER_PTR) ){
1930 /* get the referent id */
1931 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1933 tvb_ensure_bytes_exist(tvb, offset-4, 4);
1934 /* we got a NULL pointer */
1936 proto_tree_add_text(tree, tvb, offset-4, 4,
1937 "(NULL pointer) %s",text);
1941 /* see if we have seen this pointer before */
1942 idx=find_pointer_index(id);
1944 /* we have seen this pointer before */
1946 proto_tree_add_text(tree, tvb, offset-4, 4,
1947 "(duplicate PTR) %s",text);
1952 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1954 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1955 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1956 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
1957 callback, callback_args);
1960 /*TOP LEVEL UNIQUE POINTER*/
1961 if( pointers_are_top_level
1962 && (type==NDR_POINTER_UNIQUE) ){
1966 /* get the referent id */
1967 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1969 tvb_ensure_bytes_exist(tvb, offset-4, 4);
1970 /* we got a NULL pointer */
1972 proto_tree_add_text(tree, tvb, offset-4, 4,
1973 "(NULL pointer) %s",text);
1978 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1980 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1981 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1982 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1983 hf_index, callback, callback_args);
1987 /*EMBEDDED REFERENCE POINTER*/
1988 if( (!pointers_are_top_level)
1989 && (type==NDR_POINTER_REF) ){
1993 /* get the referent id */
1994 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1996 tvb_ensure_bytes_exist(tvb, offset-4, 4);
1998 item=proto_tree_add_text(tree, tvb, offset-4, 4,
2000 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2001 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
2002 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
2003 hf_index, callback, callback_args);
2007 /*EMBEDDED UNIQUE POINTER*/
2008 if( (!pointers_are_top_level)
2009 && (type==NDR_POINTER_UNIQUE) ){
2013 /* get the referent id */
2014 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
2016 tvb_ensure_bytes_exist(tvb, offset-4, 4);
2017 /* we got a NULL pointer */
2019 proto_tree_add_text(tree, tvb, offset-4, 4,
2020 "(NULL pointer) %s", text);
2025 item=proto_tree_add_text(tree, tvb, offset-4, 4,
2027 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2028 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
2029 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
2030 hf_index, callback, callback_args);
2034 /*EMBEDDED FULL POINTER*/
2035 if( (!pointers_are_top_level)
2036 && (type==NDR_POINTER_PTR) ){
2041 /* get the referent id */
2042 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
2043 tvb_ensure_bytes_exist(tvb, offset-4, 4);
2044 /* we got a NULL pointer */
2046 proto_tree_add_text(tree, tvb, offset-4, 4,
2047 "(NULL pointer) %s",text);
2051 /* see if we have seen this pointer before */
2052 idx=find_pointer_index(id);
2054 /* we have seen this pointer before */
2056 proto_tree_add_text(tree, tvb, offset-4, 4,
2057 "(duplicate PTR) %s",text);
2062 item=proto_tree_add_text(tree, tvb, offset-4, 4,
2064 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2065 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
2066 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
2067 callback, callback_args);
2073 /* After each top level pointer we have dissected we have to
2074 dissect all deferrals before we move on to the next top level
2076 if(pointers_are_top_level==TRUE){
2077 pointers_are_top_level=FALSE;
2078 offset = dissect_deferred_pointers(pinfo, tvb, offset, drep);
2079 pointers_are_top_level=TRUE;
2082 /* Set the length for the new subtree */
2084 proto_item_set_len(tr, offset-start_offset);
2090 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2091 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2092 int type, const char *text, int hf_index)
2094 return dissect_ndr_pointer_cb(
2095 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
2099 dissect_ndr_toplevel_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2100 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2101 int type, const char *text, int hf_index)
2105 pointers_are_top_level=TRUE;
2106 ret=dissect_ndr_pointer_cb(
2107 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
2112 dissect_ndr_embedded_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2113 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2114 int type, const char *text, int hf_index)
2118 pointers_are_top_level=FALSE;
2119 ret=dissect_ndr_pointer_cb(
2120 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
2126 show_stub_data (tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
2127 dcerpc_auth_info *auth_info, gboolean is_encrypted)
2129 int length, plain_length, auth_pad_len;
2130 guint auth_pad_offset;
2133 * We don't show stub data unless we have some in the tvbuff;
2134 * however, in the protocol tree, we show, as the number of
2135 * bytes, the reported number of bytes, not the number of bytes
2136 * that happen to be in the tvbuff.
2138 if (tvb_length_remaining (tvb, offset) > 0) {
2139 auth_pad_len = auth_info?auth_info->auth_pad_len:0;
2140 length = tvb_reported_length_remaining (tvb, offset);
2142 /* if auth_pad_len is larger than length then we ignore auth_pad_len totally */
2143 plain_length = length - auth_pad_len;
2144 if (plain_length < 1) {
2145 plain_length = length;
2148 auth_pad_offset = offset + plain_length;
2149 if (auth_info != NULL &&
2150 auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
2152 tvb_ensure_bytes_exist(tvb, offset, length);
2153 proto_tree_add_text(dcerpc_tree, tvb, offset, length,
2154 "Encrypted stub data (%d byte%s)",
2155 length, plurality(length, "", "s"));
2156 /* is the padding is still inside the encrypted blob, don't display it explicit */
2160 tvb_ensure_bytes_exist(tvb, offset, plain_length);
2161 proto_tree_add_text(dcerpc_tree, tvb, offset, plain_length,
2162 "Decrypted stub data (%d byte%s)",
2163 plain_length, plurality(plain_length, "", "s"));
2167 tvb_ensure_bytes_exist(tvb, offset, plain_length);
2168 proto_tree_add_text (dcerpc_tree, tvb, offset, plain_length,
2169 "Stub data (%d byte%s)", plain_length,
2170 plurality(plain_length, "", "s"));
2172 /* If there is auth padding at the end of the stub, display it */
2173 if (auth_pad_len != 0) {
2174 tvb_ensure_bytes_exist(tvb, auth_pad_offset, auth_pad_len);
2175 proto_tree_add_text (dcerpc_tree, tvb, auth_pad_offset,
2176 auth_pad_len, "Auth Padding (%u byte%s)",
2177 auth_pad_len, plurality(auth_pad_len, "", "s"));
2183 dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
2184 proto_tree *dcerpc_tree,
2185 tvbuff_t *volatile tvb, tvbuff_t *decrypted_tvb,
2186 guint8 *drep, dcerpc_info *info,
2187 dcerpc_auth_info *auth_info)
2189 volatile gint offset = 0;
2190 dcerpc_uuid_key key;
2191 dcerpc_uuid_value *sub_proto;
2192 proto_tree *volatile sub_tree = NULL;
2193 dcerpc_sub_dissector *proc;
2194 const gchar *name = NULL;
2195 dcerpc_dissect_fnct_t *volatile sub_dissect;
2196 const char *volatile saved_proto;
2197 void *volatile saved_private_data;
2198 guint length = 0, reported_length = 0;
2199 tvbuff_t *volatile stub_tvb;
2200 volatile guint auth_pad_len;
2201 volatile int auth_pad_offset;
2202 proto_item *sub_item=NULL;
2203 proto_item *pi, *hidden_item;
2205 key.uuid = info->call_data->uuid;
2206 key.ver = info->call_data->ver;
2209 if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == NULL
2210 || !proto_is_protocol_enabled(sub_proto->proto)) {
2212 * We don't have a dissector for this UUID, or the protocol
2213 * for that UUID is disabled.
2216 hidden_item = proto_tree_add_boolean(dcerpc_tree, hf_dcerpc_unknown_if_id,
2217 tvb, offset, 0, TRUE);
2218 PROTO_ITEM_SET_HIDDEN(hidden_item);
2219 if (check_col (pinfo->cinfo, COL_INFO)) {
2220 col_append_fstr (pinfo->cinfo, COL_INFO, " %s V%u",
2221 guids_resolve_uuid_to_str(&info->call_data->uuid), info->call_data->ver);
2224 if (decrypted_tvb != NULL) {
2225 show_stub_data (decrypted_tvb, 0, dcerpc_tree, auth_info,
2228 show_stub_data (tvb, 0, dcerpc_tree, auth_info, TRUE);
2232 for (proc = sub_proto->procs; proc->name; proc++) {
2233 if (proc->num == info->call_data->opnum) {
2242 if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
2243 col_set_str (pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
2246 if (check_col (pinfo->cinfo, COL_INFO)) {
2247 col_add_fstr (pinfo->cinfo, COL_INFO, "%s %s",
2248 name, (info->ptype == PDU_REQ) ? "request" : "response");
2251 sub_dissect = (info->ptype == PDU_REQ) ?
2252 proc->dissect_rqst : proc->dissect_resp;
2255 sub_item = proto_tree_add_item (tree, sub_proto->proto_id,
2256 (decrypted_tvb != NULL)?decrypted_tvb:tvb,
2260 sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
2261 proto_item_append_text(sub_item, ", %s", name);
2265 * Put the operation number into the tree along with
2266 * the operation's name.
2268 if (sub_proto->opnum_hf != -1)
2269 proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
2270 tvb, 0, 0, info->call_data->opnum,
2271 "Operation: %s (%u)",
2272 name, info->call_data->opnum);
2274 proto_tree_add_uint_format(sub_tree, hf_dcerpc_op, tvb,
2275 0, 0, info->call_data->opnum,
2276 "Operation: %s (%u)",
2277 name, info->call_data->opnum);
2279 if(info->ptype == PDU_REQ && info->call_data->rep_frame!=0) {
2280 pi = proto_tree_add_uint(sub_tree, hf_dcerpc_response_in,
2281 tvb, 0, 0, info->call_data->rep_frame);
2282 PROTO_ITEM_SET_GENERATED(pi);
2284 if(info->ptype == PDU_RESP && info->call_data->req_frame!=0) {
2285 pi = proto_tree_add_uint(sub_tree, hf_dcerpc_request_in,
2286 tvb, 0, 0, info->call_data->req_frame);
2287 PROTO_ITEM_SET_GENERATED(pi);
2291 if (decrypted_tvb != NULL) {
2292 /* Either there was no encryption or we successfully decrypted
2293 the encrypted payload. */
2295 /* We have a subdissector - call it. */
2296 saved_proto = pinfo->current_proto;
2297 saved_private_data = pinfo->private_data;
2298 pinfo->current_proto = sub_proto->name;
2299 pinfo->private_data = (void *)info;
2301 init_ndr_pointer_list(pinfo);
2303 length = tvb_length(decrypted_tvb);
2304 reported_length = tvb_reported_length(decrypted_tvb);
2307 * Remove the authentication padding from the stub data.
2309 if (auth_info != NULL && auth_info->auth_pad_len != 0) {
2310 if (reported_length >= auth_info->auth_pad_len) {
2312 * OK, the padding length isn't so big that it
2313 * exceeds the stub length. Trim the reported
2314 * length of the tvbuff.
2316 reported_length -= auth_info->auth_pad_len;
2319 * If that exceeds the actual amount of data in
2320 * the tvbuff (which means we have at least one
2321 * byte of authentication padding in the tvbuff),
2322 * trim the actual amount.
2324 if (length > reported_length)
2325 length = reported_length;
2327 stub_tvb = tvb_new_subset(decrypted_tvb, 0, length, reported_length);
2328 auth_pad_len = auth_info->auth_pad_len;
2329 auth_pad_offset = reported_length;
2332 * The padding length exceeds the stub length.
2333 * Don't bother dissecting the stub, trim the padding
2334 * length to what's in the stub data, and show the
2335 * entire stub as authentication padding.
2338 auth_pad_len = reported_length;
2339 auth_pad_offset = 0;
2341 reported_length = 0;
2345 * No authentication padding.
2347 stub_tvb = decrypted_tvb;
2349 auth_pad_offset = 0;
2353 proto_item_set_len(sub_item, length);
2356 if (stub_tvb != NULL) {
2358 * Catch all exceptions other than BoundsError, so that even
2359 * if the stub data is bad, we still show the authentication
2362 * If we get BoundsError, it means the frame was cut short
2363 * by a snapshot length, so there's nothing more to
2364 * dissect; just re-throw that exception.
2369 offset = sub_dissect (stub_tvb, 0, pinfo, sub_tree,
2372 /* If we have a subdissector and it didn't dissect all
2373 data in the tvb, make a note of it. */
2374 remaining = tvb_reported_length_remaining(stub_tvb, offset);
2375 if (remaining > 0) {
2376 proto_tree_add_text(sub_tree, stub_tvb, offset,
2378 "[Long frame (%d byte%s)]",
2380 plurality(remaining, "", "s"));
2381 if (check_col(pinfo->cinfo, COL_INFO))
2382 col_append_fstr(pinfo->cinfo, COL_INFO,
2383 "[Long frame (%d byte%s)]",
2385 plurality(remaining, "", "s"));
2388 } CATCH(BoundsError) {
2391 show_exception(stub_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
2395 /* If there is auth padding at the end of the stub, display it */
2396 if (auth_pad_len != 0) {
2397 tvb_ensure_bytes_exist(tvb, auth_pad_offset, auth_pad_len);
2398 proto_tree_add_text (sub_tree, decrypted_tvb, auth_pad_offset,
2400 "Auth Padding (%u byte%s)",
2402 plurality(auth_pad_len, "", "s"));
2405 pinfo->current_proto = saved_proto;
2406 pinfo->private_data = saved_private_data;
2408 /* No subdissector - show it as stub data. */
2410 show_stub_data (decrypted_tvb, 0, sub_tree, auth_info, FALSE);
2412 show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
2416 show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
2418 tap_queue_packet(dcerpc_tap, pinfo, info);
2423 dissect_dcerpc_verifier (tvbuff_t *tvb, packet_info *pinfo,
2424 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
2425 dcerpc_auth_info *auth_info)
2429 auth_info->auth_data = NULL;
2431 if (auth_info->auth_size != 0) {
2432 dcerpc_auth_subdissector_fns *auth_fns;
2435 auth_offset = hdr->frag_len - hdr->auth_len;
2437 auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
2440 auth_info->auth_data = auth_tvb;
2442 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
2443 auth_info->auth_type))) {
2445 * Catch all exceptions, so that even if the verifier is bad
2446 * or we don't have all of it, we still show the stub data.
2449 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
2452 show_exception(auth_tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
2455 tvb_ensure_bytes_exist(tvb, 0, hdr->auth_len);
2456 proto_tree_add_text (dcerpc_tree, auth_tvb, 0, hdr->auth_len,
2461 return hdr->auth_len;
2465 dissect_dcerpc_cn_auth (tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
2466 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
2467 gboolean are_credentials, dcerpc_auth_info *auth_info)
2469 volatile int offset;
2472 * Initially set auth_level and auth_type to zero to indicate that we
2473 * haven't yet seen any authentication level information.
2475 auth_info->auth_level = 0;
2476 auth_info->auth_type = 0;
2477 auth_info->auth_size = 0;
2478 auth_info->auth_pad_len = 0;
2481 * The authentication information is at the *end* of the PDU; in
2482 * request and response PDUs, the request and response stub data
2485 * Is there any authentication data (i.e., is the authentication length
2486 * non-zero), and is the authentication length valid (i.e., is it, plus
2487 * 8 bytes for the type/level/pad length/reserved/context id, less than
2488 * or equal to the fragment length minus the starting offset of the
2493 && (hdr->auth_len + 8 <= hdr->frag_len - stub_offset)) {
2496 * Yes, there is authentication data, and the length is valid.
2497 * Do we have all the bytes of stub data?
2498 * (If not, we'd throw an exception dissecting *that*, so don't
2499 * bother trying to dissect the authentication information and
2500 * throwing another exception there.)
2502 offset = hdr->frag_len - (hdr->auth_len + 8);
2503 if (offset == 0 || tvb_offset_exists(tvb, offset - 1)) {
2505 * Either there's no stub data, or the last byte of the stub
2506 * data is present in the captured data, so we shouldn't
2507 * get a BoundsError dissecting the stub data.
2509 * Try dissecting the authentication data.
2510 * Catch all exceptions, so that even if the auth info is bad
2511 * or we don't have all of it, we still show the stuff we
2512 * dissect after this, such as stub data.
2515 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2516 hf_dcerpc_auth_type,
2517 &auth_info->auth_type);
2518 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2519 hf_dcerpc_auth_level,
2520 &auth_info->auth_level);
2522 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2523 hf_dcerpc_auth_pad_len,
2524 &auth_info->auth_pad_len);
2525 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2526 hf_dcerpc_auth_rsrvd, NULL);
2527 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2528 hf_dcerpc_auth_ctx_id, NULL);
2531 * Dissect the authentication data.
2533 if (are_credentials) {
2535 dcerpc_auth_subdissector_fns *auth_fns;
2537 auth_tvb = tvb_new_subset(tvb, offset,
2538 MIN(hdr->auth_len,tvb_length_remaining(tvb, offset)),
2541 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
2542 auth_info->auth_type)))
2543 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
2546 proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len,
2547 "Auth Credentials");
2550 /* Compute the size of the auth block. Note that this should not
2551 include auth padding, since when NTLMSSP encryption is used, the
2552 padding is actually inside the encrypted stub */
2553 auth_info->auth_size = hdr->auth_len + 8;
2555 show_exception(tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
2562 /* We need to hash in the SMB fid number to generate a unique hash table
2563 * key as DCERPC over SMB allows several pipes over the same TCP/IP
2565 * We pass this function the transport type here to make sure we only look
2566 * at this function if it came across an SMB pipe.
2567 * Other transports might need to mix in their own extra multiplexing data
2568 * as well in the future.
2571 guint16 dcerpc_get_transport_salt (packet_info *pinfo)
2573 switch(pinfo->dcetransporttype){
2574 case DCE_CN_TRANSPORT_SMBPIPE:
2575 /* DCERPC over smb */
2576 return pinfo->dcetransportsalt;
2579 /* Some other transport... */
2584 * Connection oriented packet types
2588 dissect_dcerpc_cn_bind (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2589 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2591 conversation_t *conv = NULL;
2592 guint8 num_ctx_items = 0;
2594 gboolean saw_ctx_item = FALSE;
2596 guint8 num_trans_items;
2601 guint16 if_ver, if_ver_minor;
2602 dcerpc_auth_info auth_info;
2604 const char *uuid_name = NULL;
2605 proto_item *iface_item = NULL;
2607 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2608 hf_dcerpc_cn_max_xmit, NULL);
2610 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2611 hf_dcerpc_cn_max_recv, NULL);
2613 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2614 hf_dcerpc_cn_assoc_group, NULL);
2616 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2617 hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
2622 for (i = 0; i < num_ctx_items; i++) {
2623 proto_item *ctx_item = NULL;
2624 proto_tree *ctx_tree = NULL, *iface_tree = NULL;
2625 gint ctx_offset = offset;
2627 dissect_dcerpc_uint16 (tvb, offset, pinfo, NULL, hdr->drep,
2628 hf_dcerpc_cn_ctx_id, &ctx_id);
2630 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
2631 /* (if we have multiple contexts, this might cause "decode as"
2632 * to behave unpredictably) */
2633 pinfo->dcectxid = ctx_id;
2636 ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_item,
2638 hdr->drep[0] & 0x10);
2639 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
2642 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, ctx_tree, hdr->drep,
2643 hf_dcerpc_cn_ctx_id, &ctx_id);
2644 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, ctx_tree, hdr->drep,
2645 hf_dcerpc_cn_num_trans_items, &num_trans_items);
2648 proto_item_append_text(ctx_item, "[%u]: ID:%u", i+1, ctx_id);
2654 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
2657 iface_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_abstract_syntax, tvb, offset, 0, FALSE);
2658 iface_tree = proto_item_add_subtree(iface_item, ett_dcerpc_cn_iface);
2660 uuid_str = guid_to_str((e_guid_t*)&if_id);
2661 uuid_name = guids_get_uuid_name(&if_id);
2663 proto_tree_add_guid_format (iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
2664 offset, 16, (e_guid_t *) &if_id, "Interface: %s UUID: %s", uuid_name, uuid_str);
2665 proto_item_append_text(iface_item, ": %s", uuid_name);
2667 proto_tree_add_guid_format (iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
2668 offset, 16, (e_guid_t *) &if_id, "Interface UUID: %s", uuid_str);
2669 proto_item_append_text(iface_item, ": %s", uuid_str);
2674 if (hdr->drep[0] & 0x10) {
2675 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2676 hf_dcerpc_cn_bind_if_ver, &if_ver);
2677 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2678 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2680 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2681 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2682 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2683 hf_dcerpc_cn_bind_if_ver, &if_ver);
2687 proto_item_append_text(iface_item, " V%u.%u", if_ver, if_ver_minor);
2688 proto_item_set_len(iface_item, 20);
2691 if (!saw_ctx_item) {
2692 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
2693 pinfo->srcport, pinfo->destport, 0);
2695 fprintf(stderr,"Creating a new conv on packet %d\n",pinfo->fd->num);
2696 conv = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
2697 pinfo->srcport, pinfo->destport, 0);
2701 /* if this is the first time we see this packet, we need to
2702 update the dcerpc_binds table so that any later calls can
2703 match to the interface.
2704 XXX We assume that BINDs will NEVER be fragmented.
2706 if(!(pinfo->fd->flags.visited)){
2707 dcerpc_bind_key *key;
2708 dcerpc_bind_value *value;
2710 key = se_alloc (sizeof (dcerpc_bind_key));
2712 key->ctx_id = ctx_id;
2713 key->smb_fid = dcerpc_get_transport_salt(pinfo);
2715 value = se_alloc (sizeof (dcerpc_bind_value));
2716 value->uuid = if_id;
2717 value->ver = if_ver;
2719 /* add this entry to the bind table, first removing any
2720 previous ones that are identical
2722 if(g_hash_table_lookup(dcerpc_binds, key)){
2723 g_hash_table_remove(dcerpc_binds, key);
2725 g_hash_table_insert (dcerpc_binds, key, value);
2728 if (check_col (pinfo->cinfo, COL_INFO)) {
2729 if (num_ctx_items > 1)
2730 col_append_fstr(pinfo->cinfo, COL_INFO, ", %u context items, 1st", num_ctx_items);
2732 col_append_fstr(pinfo->cinfo, COL_INFO, " %s V%u.%u",
2733 guids_resolve_uuid_to_str(&if_id), if_ver, if_ver_minor);
2735 saw_ctx_item = TRUE;
2738 for (j = 0; j < num_trans_items; j++) {
2739 proto_tree *trans_tree = NULL;
2740 proto_item *trans_item = NULL;
2742 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2745 trans_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_trans_syntax, tvb, offset, 0, FALSE);
2746 trans_tree = proto_item_add_subtree(trans_item, ett_dcerpc_cn_trans_syntax);
2748 uuid_str = guid_to_str((e_guid_t *) &trans_id);
2749 proto_tree_add_guid_format (trans_tree, hf_dcerpc_cn_bind_trans_id, tvb,
2750 offset, 16, (e_guid_t *) &trans_id, "Transfer Syntax: %s", uuid_str);
2751 proto_item_append_text(trans_item, "[%u]: %s", j+1, uuid_str);
2755 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, trans_tree, hdr->drep,
2756 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
2758 proto_item_set_len(trans_item, 20);
2759 proto_item_append_text(trans_item, " V%u", trans_ver);
2764 proto_item_set_len(ctx_item, offset - ctx_offset);
2769 * XXX - we should save the authentication type *if* we have
2770 * an authentication header, and associate it with an authentication
2771 * context, so subsequent PDUs can use that context.
2773 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2777 dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2778 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2780 guint16 max_xmit, max_recv;
2781 guint16 sec_addr_len;
2788 dcerpc_auth_info auth_info;
2790 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2791 hf_dcerpc_cn_max_xmit, &max_xmit);
2793 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2794 hf_dcerpc_cn_max_recv, &max_recv);
2796 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2797 hf_dcerpc_cn_assoc_group, NULL);
2799 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2800 hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
2801 if (sec_addr_len != 0) {
2802 tvb_ensure_bytes_exist(tvb, offset, sec_addr_len);
2803 proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
2804 sec_addr_len, FALSE);
2805 offset += sec_addr_len;
2809 offset += 4 - offset % 4;
2812 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2813 hf_dcerpc_cn_num_results, &num_results);
2818 for (i = 0; i < num_results; i++) {
2819 proto_tree *ctx_tree = NULL;
2822 proto_item *ctx_item;
2823 ctx_item = proto_tree_add_text(dcerpc_tree, tvb, offset, 24, "Context ID[%u]", i+1);
2824 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
2827 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, ctx_tree,
2828 hdr->drep, hf_dcerpc_cn_ack_result,
2831 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, ctx_tree,
2832 hdr->drep, hf_dcerpc_cn_ack_reason,
2836 * The reason for rejection isn't meaningful, and often isn't
2837 * set, when the syntax was accepted.
2842 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2844 proto_tree_add_guid_format (ctx_tree, hf_dcerpc_cn_ack_trans_id, tvb,
2845 offset, 16, (e_guid_t *) &trans_id, "Transfer Syntax: %s",
2846 guid_to_str((e_guid_t *) &trans_id));
2850 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, ctx_tree, hdr->drep,
2851 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
2855 * XXX - do we need to do anything with the authentication level
2856 * we get back from this?
2858 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2860 if (check_col (pinfo->cinfo, COL_INFO)) {
2861 if (num_results != 0) {
2863 /* XXX - only checks the last result */
2864 col_append_fstr (pinfo->cinfo, COL_INFO,
2865 " accept max_xmit: %u max_recv: %u",
2866 max_xmit, max_recv);
2868 /* XXX - only shows the last result and reason */
2869 col_append_fstr (pinfo->cinfo, COL_INFO, " %s, reason: %s",
2870 val_to_str(result, p_cont_result_vals,
2871 "Unknown result (%u)"),
2872 val_to_str(reason, p_provider_reason_vals,
2880 dissect_dcerpc_cn_bind_nak (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2881 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2884 guint8 num_protocols;
2887 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2888 hdr->drep, hf_dcerpc_cn_reject_reason,
2891 if (check_col (pinfo->cinfo, COL_INFO)) {
2892 col_append_fstr (pinfo->cinfo, COL_INFO, " reason: %s",
2893 val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
2896 if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
2897 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2898 hf_dcerpc_cn_num_protocols,
2901 for (i = 0; i < num_protocols; i++) {
2902 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2903 hdr->drep, hf_dcerpc_cn_protocol_ver_major,
2905 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2906 hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
2912 /* Return a string describing a DCE/RPC fragment as first, middle, or end
2915 #define PFC_FRAG_MASK 0x03
2918 fragment_type(guint8 flags)
2920 flags = flags & PFC_FRAG_MASK;
2922 if (flags == PFC_FIRST_FRAG)
2928 if (flags == PFC_LAST_FRAG)
2931 if (flags == (PFC_FIRST_FRAG | PFC_LAST_FRAG))
2937 /* Dissect stub data (payload) of a DCERPC packet. */
2940 dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
2941 proto_tree *dcerpc_tree, proto_tree *tree,
2942 e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
2943 dcerpc_auth_info *auth_info, guint32 alloc_hint _U_,
2946 gint length, reported_length;
2947 gboolean save_fragmented;
2948 fragment_data *fd_head=NULL;
2950 tvbuff_t *auth_tvb, *payload_tvb, *decrypted_tvb;
2952 proto_item *parent_pi;
2953 proto_item *dcerpc_tree_item;
2955 save_fragmented = pinfo->fragmented;
2956 length = tvb_length_remaining(tvb, offset);
2957 reported_length = tvb_reported_length_remaining(tvb, offset);
2958 if (reported_length < 0 ||
2959 (guint32)reported_length < auth_info->auth_size) {
2960 /* We don't even have enough bytes for the authentication
2964 reported_length -= auth_info->auth_size;
2965 if (length > reported_length)
2966 length = reported_length;
2967 payload_tvb = tvb_new_subset(tvb, offset, length, reported_length);
2970 /*dont bother if we dont have the entire tvb */
2971 /*XXX we should really make sure we calculate auth_info->auth_data
2972 *and use that one instead of this auth_tvb hack
2974 if(tvb_length(tvb)==tvb_reported_length(tvb)){
2975 if(tvb_length_remaining(tvb, offset+length)>8){
2976 auth_tvb = tvb_new_subset_remaining(tvb, offset+length+8);
2980 /* Decrypt the PDU if it is encrypted */
2982 if (auth_info->auth_type &&
2983 auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
2985 * We know the authentication type, and the authentication
2986 * level is "Packet privacy", meaning the payload is
2987 * encrypted; attempt to decrypt it.
2989 dcerpc_auth_subdissector_fns *auth_fns;
2991 /* Start out assuming we won't succeed in decrypting. */
2992 decrypted_tvb = NULL;
2993 /* Schannel needs informations into the footer (verifier) in order to setup decryptions keys
2994 * so we call it in order to have a chance to decypher the data
2996 if (DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN == auth_info->auth_type) {
2997 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, auth_info);
3000 if ((auth_fns = get_auth_subdissector_fns(
3001 auth_info->auth_level, auth_info->auth_type))) {
3003 result = decode_encrypted_data( payload_tvb, auth_tvb, pinfo, auth_fns,
3004 hdr->ptype == PDU_REQ, auth_info);
3007 proto_tree_add_text(dcerpc_tree, payload_tvb, 0, -1,
3008 "Encrypted stub data (%d byte%s)",
3009 tvb_reported_length(payload_tvb),
3010 plurality(tvb_length(payload_tvb), "", "s"));
3012 add_new_data_source(pinfo, result, "Decrypted stub data");
3014 decrypted_tvb = result;
3019 decrypted_tvb = payload_tvb;
3021 /* if this packet is not fragmented, just dissect it and exit */
3022 if(PFC_NOT_FRAGMENTED(hdr)) {
3023 pinfo->fragmented = FALSE;
3025 dcerpc_try_handoff( pinfo, tree, dcerpc_tree, payload_tvb,
3026 decrypted_tvb, hdr->drep, di, auth_info);
3028 pinfo->fragmented = save_fragmented;
3032 /* The packet is fragmented. */
3033 pinfo->fragmented = TRUE;
3035 /* debug output of essential fragment data. */
3036 /* leave it here for future debugging sessions */
3037 /*printf("DCE num:%u offset:%u frag_len:%u tvb_len:%u\n",
3038 pinfo->fd->num, offset, hdr->frag_len, tvb_length(decrypted_tvb));*/
3040 /* if we are not doing reassembly and this is the first fragment
3041 then just dissect it and exit
3042 XXX - if we're not doing reassembly, can we decrypt an
3045 if( (!dcerpc_reassemble) && hdr->flags&PFC_FIRST_FRAG ){
3048 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
3049 hdr->drep, di, auth_info);
3051 if (check_col(pinfo->cinfo, COL_INFO)) {
3052 col_append_fstr(pinfo->cinfo, COL_INFO,
3053 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
3055 expert_add_info_format(pinfo, NULL, PI_REASSEMBLE, PI_CHAT,
3056 "%s fragment", fragment_type(hdr->flags));
3057 pinfo->fragmented = save_fragmented;
3061 /* if we have already seen this packet, see if it was reassembled
3062 and if so dissect the full pdu.
3065 if(pinfo->fd->flags.visited){
3066 fd_head=fragment_get_reassembled(pinfo, frame, dcerpc_co_reassemble_table);
3070 /* if we are not doing reassembly and it was neither a complete PDU
3071 nor the first fragment then there is nothing more we can do
3072 so we just have to exit
3074 if( !dcerpc_reassemble || (tvb_length(tvb)!=tvb_reported_length(tvb)) )
3077 /* if we didnt get 'frame' we dont know where the PDU started and thus
3078 it is pointless to continue
3083 /* from now on we must attempt to reassemble the PDU
3086 /* if we get here we know it is the first time we see the packet
3087 and we also know it is only a fragment and not a full PDU,
3088 thus we must reassemble it.
3091 /* Do we have any non-encrypted data to reassemble? */
3092 if (decrypted_tvb == NULL) {
3093 /* No. We can't even try to reassemble. */
3097 /* defragmentation is a bit tricky, as there's no offset of the fragment
3098 * in the protocol data.
3100 * just use fragment_add_seq_next() and hope that TCP/SMB segments coming
3101 * in with the correct sequence.
3103 fd_head = fragment_add_seq_next(decrypted_tvb, 0, pinfo, frame,
3104 dcerpc_co_fragment_table, dcerpc_co_reassemble_table,
3105 tvb_length(decrypted_tvb),
3106 hdr->flags&PFC_LAST_FRAG ? FALSE : TRUE /* more_frags */);
3110 /* if reassembly is complete and this is the last fragment
3111 * (multiple fragments in one PDU are possible!)
3112 * dissect the full PDU
3114 if(fd_head && (fd_head->flags&FD_DEFRAGMENTED) ){
3116 if(pinfo->fd->num==fd_head->reassembled_in && (hdr->flags&PFC_LAST_FRAG) ){
3118 proto_item *frag_tree_item;
3120 next_tvb = tvb_new_child_real_data((decrypted_tvb)?decrypted_tvb:payload_tvb,
3121 fd_head->data, fd_head->len, fd_head->len);
3123 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3124 show_fragment_tree(fd_head, &dcerpc_frag_items,
3125 tree, pinfo, next_tvb, &frag_tree_item);
3126 /* the toplevel fragment subtree is now behind all desegmented data,
3127 * move it right behind the DCE/RPC tree */
3128 dcerpc_tree_item = proto_tree_get_parent(dcerpc_tree);
3129 if(frag_tree_item && dcerpc_tree_item) {
3130 proto_tree_move_item(tree, dcerpc_tree_item, frag_tree_item);
3133 pinfo->fragmented = FALSE;
3135 expert_add_info_format(pinfo, frag_tree_item, PI_REASSEMBLE, PI_CHAT,
3136 "%s fragment, reassembled",
3137 fragment_type(hdr->flags));
3139 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
3140 next_tvb, hdr->drep, di, auth_info);
3144 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
3145 decrypted_tvb, 0, 0, fd_head->reassembled_in);
3147 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
3148 payload_tvb, 0, 0, fd_head->reassembled_in);
3150 PROTO_ITEM_SET_GENERATED(pi);
3151 parent_pi = proto_tree_get_parent(dcerpc_tree);
3152 if(parent_pi != NULL) {
3153 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
3155 if (check_col(pinfo->cinfo, COL_INFO)) {
3156 col_append_fstr(pinfo->cinfo, COL_INFO,
3157 " [DCE/RPC %s fragment, reas: #%u]", fragment_type(hdr->flags), fd_head->reassembled_in);
3159 expert_add_info_format(pinfo, NULL, PI_REASSEMBLE, PI_CHAT,
3160 "%s fragment, reassembled in #%u", fragment_type(hdr->flags), fd_head->reassembled_in);
3163 /* Reassembly not complete - some fragments
3164 are missing. Just show the stub data. */
3165 if (check_col(pinfo->cinfo, COL_INFO)) {
3166 col_append_fstr(pinfo->cinfo, COL_INFO,
3167 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
3169 expert_add_info_format(pinfo, NULL, PI_REASSEMBLE, PI_CHAT,
3170 "%s fragment", fragment_type(hdr->flags));
3173 show_stub_data (decrypted_tvb, 0, tree, auth_info, FALSE);
3175 show_stub_data (payload_tvb, 0, tree, auth_info, TRUE);
3179 pinfo->fragmented = save_fragmented;
3183 * Registers a conversation/UUID binding association, so that
3184 * we can invoke the proper sub-dissector for a given DCERPC
3187 * @param binding all values needed to create and bind a new conversation
3189 * @return Pointer to newly-added UUID/conversation binding.
3191 struct _dcerpc_bind_value *
3192 dcerpc_add_conv_to_bind_table(decode_dcerpc_bind_values_t *binding)
3194 dcerpc_bind_value *bind_value;
3195 dcerpc_bind_key *key;
3196 conversation_t *conv;
3198 conv = find_conversation (
3208 fprintf(stderr,"Creating a new conv on this bind packet \n");
3209 conv = conversation_new (
3219 bind_value = se_alloc (sizeof (dcerpc_bind_value));
3220 bind_value->uuid = binding->uuid;
3221 bind_value->ver = binding->ver;
3223 key = se_alloc(sizeof (dcerpc_bind_key));
3225 key->ctx_id = binding->ctx_id;
3226 key->smb_fid = binding->smb_fid;
3228 /* add this entry to the bind table, first removing any
3229 previous ones that are identical
3231 if(g_hash_table_lookup(dcerpc_binds, key)){
3232 g_hash_table_remove(dcerpc_binds, key);
3234 g_hash_table_insert(dcerpc_binds, key, bind_value);
3241 dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3242 proto_tree *dcerpc_tree, proto_tree *tree,
3243 e_dce_cn_common_hdr_t *hdr)
3245 conversation_t *conv;
3248 e_uuid_t obj_id = DCERPC_UUID_NULL;
3249 dcerpc_auth_info auth_info;
3252 proto_item *parent_pi;
3253 dcerpc_matched_key matched_key, *new_matched_key;
3254 dcerpc_call_value *value;
3256 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3257 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3259 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3260 hf_dcerpc_cn_ctx_id, &ctx_id);
3261 parent_pi = proto_tree_get_parent(dcerpc_tree);
3262 if(parent_pi != NULL) {
3263 proto_item_append_text(parent_pi, " Ctx: %u", ctx_id);
3266 if (check_col (pinfo->cinfo, COL_DCE_CTX)) {
3267 if(pinfo->dcectxid == 0) {
3268 col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "%u", ctx_id);
3270 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
3271 * prepend a delimiter */
3272 col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "#%u", ctx_id);
3276 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3277 hf_dcerpc_opnum, &opnum);
3279 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3280 pinfo->dcectxid = ctx_id;
3282 if (check_col (pinfo->cinfo, COL_INFO)) {
3283 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u ctx_id: %u",
3287 if (hdr->flags & PFC_OBJECT_UUID) {
3288 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id);
3290 proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
3291 offset, 16, (e_guid_t *) &obj_id, "Object UUID: %s",
3292 guid_to_str((e_guid_t *) &obj_id));
3298 * XXX - what if this was set when the connection was set up,
3299 * and we just have a security context?
3301 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3302 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3303 pinfo->srcport, pinfo->destport, 0);
3305 /*conv = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3306 pinfo->srcport, pinfo->destport, 0);*/
3307 fprintf(stderr,"No conv showing raw stuf %d \n",pinfo->fd->num);
3308 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3311 /* !!! we can NOT check flags.visited here since this will interact
3312 badly with when SMB handles (i.e. calls the subdissector)
3313 and desegmented pdu's .
3314 Instead we check if this pdu is already in the matched table or not
3316 matched_key.frame = pinfo->fd->num;
3317 matched_key.call_id = hdr->call_id;
3318 value = g_hash_table_lookup(dcerpc_matched, &matched_key);
3320 dcerpc_bind_key bind_key;
3321 dcerpc_bind_value *bind_value;
3324 bind_key.ctx_id=ctx_id;
3325 bind_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3326 if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key)) ){
3327 if(!(hdr->flags&PFC_FIRST_FRAG)){
3328 dcerpc_cn_call_key call_key;
3329 dcerpc_call_value *call_value;
3332 call_key.call_id=hdr->call_id;
3333 call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3334 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3335 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
3336 *new_matched_key = matched_key;
3337 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3342 dcerpc_cn_call_key *call_key;
3343 dcerpc_call_value *call_value;
3345 /* We found the binding and it is the first fragment
3346 (or a complete PDU) of a dcerpc pdu so just add
3347 the call to both the call table and the
3350 call_key=se_alloc (sizeof (dcerpc_cn_call_key));
3351 call_key->conv=conv;
3352 call_key->call_id=hdr->call_id;
3353 call_key->smb_fid=dcerpc_get_transport_salt(pinfo);
3355 /* if there is already a matching call in the table
3356 remove it so it is replaced with the new one */
3357 if(g_hash_table_lookup(dcerpc_cn_calls, call_key)){
3358 g_hash_table_remove(dcerpc_cn_calls, call_key);
3361 call_value=se_alloc (sizeof (dcerpc_call_value));
3362 call_value->uuid = bind_value->uuid;
3363 call_value->ver = bind_value->ver;
3364 call_value->object_uuid = obj_id;
3365 call_value->opnum = opnum;
3366 call_value->req_frame=pinfo->fd->num;
3367 call_value->req_time=pinfo->fd->abs_ts;
3368 call_value->rep_frame=0;
3369 call_value->max_ptr=0;
3370 call_value->se_data = NULL;
3371 call_value->private_data = NULL;
3372 call_value->pol = NULL;
3373 g_hash_table_insert (dcerpc_cn_calls, call_key, call_value);
3375 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
3376 *new_matched_key = matched_key;
3377 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3385 /* handoff this call */
3387 di->call_id = hdr->call_id;
3388 di->smb_fid = dcerpc_get_transport_salt(pinfo);
3389 di->ptype = PDU_REQ;
3390 di->call_data = value;
3393 if(value->rep_frame!=0){
3394 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
3395 tvb, 0, 0, value->rep_frame);
3396 PROTO_ITEM_SET_GENERATED(pi);
3397 if(parent_pi != NULL) {
3398 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
3401 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
3402 hdr, di, &auth_info, alloc_hint,
3406 /* no bind information, simply show stub data */
3407 pi = proto_tree_add_text(dcerpc_tree, tvb, offset, 0, "No bind info for this interface Context ID - capture start too late?");
3408 PROTO_ITEM_SET_GENERATED(pi);
3409 expert_add_info_format(pinfo, pi, PI_UNDECODED, PI_NOTE, "No bind info for interface Context ID:%u",
3411 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3414 /* Dissect the verifier */
3415 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
3420 dissect_dcerpc_cn_resp (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3421 proto_tree *dcerpc_tree, proto_tree *tree,
3422 e_dce_cn_common_hdr_t *hdr)
3424 dcerpc_call_value *value = NULL;
3425 conversation_t *conv;
3427 dcerpc_auth_info auth_info;
3430 proto_item *parent_pi;
3431 e_uuid_t obj_id_null = DCERPC_UUID_NULL;
3433 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3434 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3436 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3437 hf_dcerpc_cn_ctx_id, &ctx_id);
3438 parent_pi = proto_tree_get_parent(dcerpc_tree);
3439 if(parent_pi != NULL) {
3440 proto_item_append_text(parent_pi, " Ctx: %u", ctx_id);
3443 if (check_col (pinfo->cinfo, COL_DCE_CTX)) {
3444 if(pinfo->dcectxid == 0) {
3445 col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "%u", ctx_id);
3447 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
3448 * prepend a delimiter */
3449 col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "#%u", ctx_id);
3453 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3454 pinfo->dcectxid = ctx_id;
3456 if (check_col (pinfo->cinfo, COL_INFO)) {
3457 col_append_fstr (pinfo->cinfo, COL_INFO, " ctx_id: %u", ctx_id);
3460 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3461 hf_dcerpc_cn_cancel_count, NULL);
3466 * XXX - what if this was set when the connection was set up,
3467 * and we just have a security context?
3469 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3471 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3472 pinfo->srcport, pinfo->destport, 0);
3475 /* no point in creating one here, really */
3476 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3478 dcerpc_matched_key matched_key, *new_matched_key;
3480 /* !!! we can NOT check flags.visited here since this will interact
3481 badly with when SMB handles (i.e. calls the subdissector)
3482 and desegmented pdu's .
3483 Instead we check if this pdu is already in the matched table or not
3485 matched_key.frame = pinfo->fd->num;
3486 matched_key.call_id = hdr->call_id;
3487 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3489 dcerpc_cn_call_key call_key;
3490 dcerpc_call_value *call_value;
3493 call_key.call_id=hdr->call_id;
3494 call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3496 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3497 /* extra sanity check, only match them if the reply
3498 came after the request */
3499 if(call_value->req_frame<pinfo->fd->num){
3500 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
3501 *new_matched_key = matched_key;
3502 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3504 if(call_value->rep_frame==0) {
3505 call_value->rep_frame=pinfo->fd->num;
3515 /* handoff this call */
3517 di->call_id = hdr->call_id;
3518 di->smb_fid = dcerpc_get_transport_salt(pinfo);
3519 di->ptype = PDU_RESP;
3520 di->call_data = value;
3522 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
3524 /* (optional) "Object UUID" from request */
3525 if (value && dcerpc_tree && memcmp(&value->object_uuid, &obj_id_null, sizeof(obj_id_null)) != 0) {
3526 pi = proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
3527 offset, 0, (e_guid_t *) &value->object_uuid, "Object UUID: %s",
3528 guid_to_str((e_guid_t *) &value->object_uuid));
3529 PROTO_ITEM_SET_GENERATED(pi);
3533 if(value->req_frame!=0) {
3535 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3536 tvb, 0, 0, value->req_frame);
3537 PROTO_ITEM_SET_GENERATED(pi);
3538 if(parent_pi != NULL) {
3539 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
3541 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
3542 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
3543 PROTO_ITEM_SET_GENERATED(pi);
3545 pi = proto_tree_add_text(dcerpc_tree,
3546 tvb, 0, 0, "No request to this DCE/RPC call found");
3547 expert_add_info_format(pinfo, pi, PI_SEQUENCE, PI_NOTE,
3548 "No request to this DCE/RPC call found");
3551 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
3552 hdr, di, &auth_info, alloc_hint,value->rep_frame);
3554 /* no bind information, simply show stub data */
3555 pi = proto_tree_add_text(dcerpc_tree, tvb, offset, 0, "No bind info for this interface Context ID - capture start too late?");
3556 PROTO_ITEM_SET_GENERATED(pi);
3557 expert_add_info_format(pinfo, pi, PI_UNDECODED, PI_NOTE, "No bind info for interface Context ID:%u",ctx_id);
3558 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3561 /* Dissect the verifier */
3562 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
3566 dissect_dcerpc_cn_fault (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3567 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
3569 dcerpc_call_value *value = NULL;
3570 conversation_t *conv;
3574 dcerpc_auth_info auth_info;
3575 proto_item *pi = NULL;
3577 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3578 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3580 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3581 hf_dcerpc_cn_ctx_id, &ctx_id);
3583 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3584 hf_dcerpc_cn_cancel_count, NULL);
3588 /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3589 hf_dcerpc_cn_status, &status);*/
3590 status = ((hdr->drep[0] & 0x10)
3591 ? tvb_get_letohl (tvb, offset)
3592 : tvb_get_ntohl (tvb, offset));
3595 pi = proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_status, tvb, offset, 4, (hdr->drep[0] & 0x10));
3599 expert_add_info_format(pinfo, pi, PI_RESPONSE_CODE, PI_NOTE, "Fault: %s",
3600 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
3602 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3603 pinfo->dcectxid = ctx_id;
3605 if (check_col (pinfo->cinfo, COL_INFO)) {
3606 col_append_fstr (pinfo->cinfo, COL_INFO,
3607 " ctx_id: %u status: %s", ctx_id,
3608 val_to_str(status, reject_status_vals,
3609 "Unknown (0x%08x)"));
3616 * XXX - what if this was set when the connection was set up,
3617 * and we just have a security context?
3619 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3621 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3622 pinfo->srcport, pinfo->destport, 0);
3624 /* no point in creating one here, really */
3626 dcerpc_matched_key matched_key, *new_matched_key;
3628 /* !!! we can NOT check flags.visited here since this will interact
3629 badly with when SMB handles (i.e. calls the subdissector)
3630 and desegmented pdu's .
3631 Instead we check if this pdu is already in the matched table or not
3633 matched_key.frame = pinfo->fd->num;
3634 matched_key.call_id = hdr->call_id;
3635 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3637 dcerpc_cn_call_key call_key;
3638 dcerpc_call_value *call_value;
3641 call_key.call_id=hdr->call_id;
3642 call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3644 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3645 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
3646 *new_matched_key = matched_key;
3647 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3649 if(call_value->rep_frame==0){
3650 call_value->rep_frame=pinfo->fd->num;
3657 int length, reported_length, stub_length;
3659 proto_item *parent_pi;
3662 /* handoff this call */
3664 di->call_id = hdr->call_id;
3665 di->smb_fid = dcerpc_get_transport_salt(pinfo);
3666 di->ptype = PDU_FAULT;
3667 di->call_data = value;
3669 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
3670 if(value->req_frame!=0){
3672 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3673 tvb, 0, 0, value->req_frame);
3674 PROTO_ITEM_SET_GENERATED(pi);
3675 parent_pi = proto_tree_get_parent(dcerpc_tree);
3676 if(parent_pi != NULL) {
3677 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
3679 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
3680 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
3681 PROTO_ITEM_SET_GENERATED(pi);
3683 pi = proto_tree_add_text(dcerpc_tree,
3684 tvb, 0, 0, "No request to this DCE/RPC call found");
3685 expert_add_info_format(pinfo, pi, PI_SEQUENCE, PI_NOTE,
3686 "No request to this DCE/RPC call found");
3689 length = tvb_length_remaining(tvb, offset);
3690 reported_length = tvb_reported_length_remaining(tvb, offset);
3691 /* as we now create a tvb in dissect_dcerpc_cn() containing only the
3692 * stub_data, the following calculation is no longer valid:
3693 * stub_length = hdr->frag_len - offset - auth_info.auth_size;
3694 * simply use the remaining length of the tvb instead.
3695 * XXX - or better use the reported_length?!?
3697 stub_length = length;
3698 if (length > stub_length)
3699 length = stub_length;
3700 if (reported_length > stub_length)
3701 reported_length = stub_length;
3703 /* If we don't have reassembly enabled, or this packet contains
3704 the entire PDU, or if we don't have all the data in this
3705 fragment, just call the handoff directly if this is the
3706 first fragment or the PDU isn't fragmented. */
3707 if( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
3708 !tvb_bytes_exist(tvb, offset, stub_length) ){
3709 if(hdr->flags&PFC_FIRST_FRAG){
3710 /* First fragment, possibly the only fragment */
3712 * XXX - should there be a third routine for each
3713 * function in an RPC subdissector, to handle
3714 * fault responses? The DCE RPC 1.1 spec says
3715 * three's "stub data" here, which I infer means
3716 * that it's protocol-specific and call-specific.
3718 * It should probably get passed the status code
3719 * as well, as that might be protocol-specific.
3722 if (stub_length > 0) {
3723 tvb_ensure_bytes_exist(tvb, offset, stub_length);
3724 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3725 "Fault stub data (%d byte%s)",
3727 plurality(stub_length, "", "s"));
3731 /* PDU is fragmented and this isn't the first fragment */
3732 col_append_str(pinfo->cinfo, COL_INFO,
3733 " [DCE/RPC fragment]");
3735 if (stub_length > 0) {
3736 tvb_ensure_bytes_exist(tvb, offset, stub_length);
3737 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3738 "Fragment data (%d byte%s)",
3740 plurality(stub_length, "", "s"));
3745 /* Reassembly is enabled, the PDU is fragmented, and
3746 we have all the data in the fragment; the first two
3747 of those mean we should attempt reassembly, and the
3748 third means we can attempt reassembly. */
3751 tvb_ensure_bytes_exist(tvb, offset, stub_length);
3752 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3753 "Fragment data (%d byte%s)",
3755 plurality(stub_length, "", "s"));
3758 if(hdr->flags&PFC_FIRST_FRAG){ /* FIRST fragment */
3759 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
3760 fragment_add_seq_next(tvb, offset, pinfo, value->rep_frame,
3761 dcerpc_co_fragment_table, dcerpc_co_reassemble_table,
3765 col_append_str(pinfo->cinfo, COL_INFO,
3766 " [DCE/RPC fragment]");
3767 } else if(hdr->flags&PFC_LAST_FRAG){ /* LAST fragment */
3768 if( value->rep_frame ){
3769 fragment_data *fd_head;
3771 fd_head = fragment_add_seq_next(tvb, offset, pinfo,
3773 dcerpc_co_fragment_table, dcerpc_co_reassemble_table,
3778 /* We completed reassembly */
3780 proto_item *frag_tree_item;
3782 next_tvb = tvb_new_child_real_data(tvb, fd_head->data, fd_head->len, fd_head->len);
3783 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3784 show_fragment_tree(fd_head, &dcerpc_frag_items,
3785 dcerpc_tree, pinfo, next_tvb, &frag_tree_item);
3788 * XXX - should there be a third routine for each
3789 * function in an RPC subdissector, to handle
3790 * fault responses? The DCE RPC 1.1 spec says
3791 * three's "stub data" here, which I infer means
3792 * that it's protocol-specific and call-specific.
3794 * It should probably get passed the status code
3795 * as well, as that might be protocol-specific.
3799 tvb_ensure_bytes_exist(tvb, offset, stub_length);
3800 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3801 "Fault stub data (%d byte%s)",
3803 plurality(stub_length, "", "s"));
3807 /* Reassembly not complete - some fragments
3809 col_append_str(pinfo->cinfo, COL_INFO,
3810 " [DCE/RPC fragment]");
3813 } else { /* MIDDLE fragment(s) */
3814 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
3815 fragment_add_seq_next(tvb, offset, pinfo, value->rep_frame,
3816 dcerpc_co_fragment_table, dcerpc_co_reassemble_table,
3820 col_append_str(pinfo->cinfo, COL_INFO,
3821 " [DCE/RPC fragment]");
3829 * DCERPC dissector for connection oriented calls.
3830 * We use transport type to later multiplex between what kind of
3831 * pinfo->private_data structure to expect.
3834 dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
3835 proto_tree *tree, gboolean can_desegment, int *pkt_len)
3837 static const guint8 nulls[4] = { 0 };
3840 proto_item *ti = NULL;
3841 proto_item *tf = NULL;
3842 proto_tree *dcerpc_tree = NULL;
3843 proto_tree *cn_flags_tree = NULL;
3844 proto_tree *drep_tree = NULL;
3845 e_dce_cn_common_hdr_t hdr;
3846 dcerpc_auth_info auth_info;
3847 tvbuff_t *fragment_tvb;
3850 * when done over nbt, dcerpc requests are padded with 4 bytes of null
3851 * data for some reason.
3853 * XXX - if that's always the case, the right way to do this would
3854 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
3855 * the 4 bytes of null padding, and make that the dissector
3856 * used for "netbios".
3858 if (tvb_memeql (tvb, offset, nulls, 4) == 0) {
3867 * Check if this looks like a C/O DCERPC call
3869 if (!tvb_bytes_exist (tvb, offset, sizeof (hdr))) {
3870 return FALSE; /* not enough information to check */
3872 start_offset = offset;
3873 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
3874 if (hdr.rpc_ver != 5)
3876 hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
3877 if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
3879 hdr.ptype = tvb_get_guint8 (tvb, offset++);
3883 hdr.flags = tvb_get_guint8 (tvb, offset++);
3884 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
3885 offset += sizeof (hdr.drep);
3887 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3889 hdr.auth_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3891 hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3894 if (check_col (pinfo->cinfo, COL_DCE_CALL)) {
3895 if(pinfo->dcectxid == 0) {
3896 col_append_fstr (pinfo->cinfo, COL_DCE_CALL, "%u", hdr.call_id);
3898 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
3899 * prepend a delimiter */
3900 col_append_fstr (pinfo->cinfo, COL_DCE_CALL, "#%u", hdr.call_id);
3904 if (can_desegment && pinfo->can_desegment
3905 && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
3906 pinfo->desegment_offset = start_offset;
3907 pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, start_offset);
3908 *pkt_len = 0; /* desegmentation required */
3912 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
3914 if (check_col (pinfo->cinfo, COL_INFO)) {
3915 if(pinfo->dcectxid != 0) {
3916 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
3917 * append a delimiter and set a column fence */
3918 col_append_str (pinfo->cinfo, COL_INFO, " # ");
3919 col_set_fence(pinfo->cinfo,COL_INFO);
3921 col_add_fstr (pinfo->cinfo, COL_INFO, "%s: call_id: %u",
3922 pckt_vals[hdr.ptype].strptr, hdr.call_id);
3925 if(pinfo->dcectxid != 0) {
3926 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU */
3927 expert_add_info_format(pinfo, NULL, PI_SEQUENCE, PI_CHAT, "Multiple DCE/RPC fragments/PDU's in one packet");
3930 offset = start_offset;
3931 tvb_ensure_bytes_exist(tvb, offset, 16);
3933 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE);
3934 dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
3937 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
3940 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset, 1, hdr.rpc_ver_minor);
3943 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
3946 /* XXX - too much "output noise", removed for now
3947 if(hdr.ptype == PDU_BIND || hdr.ptype == PDU_ALTER ||
3948 hdr.ptype == PDU_BIND_ACK || hdr.ptype == PDU_ALTER_ACK)
3949 expert_add_info_format(pinfo, tf, PI_SEQUENCE, PI_CHAT, "Context change: %s",
3950 val_to_str(hdr.ptype, pckt_vals, "(0x%x)"));*/
3951 if(hdr.ptype == PDU_BIND_NAK)
3952 expert_add_info_format(pinfo, tf, PI_SEQUENCE, PI_WARN, "Bind not acknowledged");
3955 proto_item_append_text(ti, " %s, Fragment:", val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"));
3957 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
3958 cn_flags_tree = proto_item_add_subtree (tf, ett_dcerpc_cn_flags);
3960 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
3961 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
3962 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
3963 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
3964 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
3965 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
3966 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
3967 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
3968 if( (hdr.flags & PFC_FIRST_FRAG) && (hdr.flags & PFC_LAST_FRAG) ) {
3969 proto_item_append_text(ti, " Single");
3971 if(hdr.flags & PFC_FIRST_FRAG) {
3972 proto_item_append_text(ti, " 1st");
3974 if(hdr.flags & PFC_LAST_FRAG) {
3975 proto_item_append_text(ti, " Last");
3977 if( !(hdr.flags & PFC_FIRST_FRAG) && !(hdr.flags & PFC_LAST_FRAG) ) {
3978 proto_item_append_text(ti, " Mid");
3984 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
3985 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
3987 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
3988 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
3989 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
3990 offset += sizeof (hdr.drep);
3992 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
3995 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
3998 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
4002 proto_item_append_text(ti, ", FragLen: %u, Call: %u", hdr.frag_len, hdr.call_id);
4006 * None of the stuff done above should throw an exception, because
4007 * we would have rejected this as "not DCE RPC" if we didn't have all
4008 * of it. (XXX - perhaps we should request reassembly if we have
4009 * enough of the header to consider it DCE RPC but not enough to
4010 * get the fragment length; in that case the stuff still wouldn't
4011 * throw an exception.)
4013 * The rest of the stuff might, so return the PDU length to our caller.
4014 * XXX - should we construct a tvbuff containing only the PDU and
4015 * use that? Or should we have separate "is this a DCE RPC PDU",
4016 * "how long is it", and "dissect it" routines - which might let us
4017 * do most of the work in "tcp_dissect_pdus()"?
4019 if (pkt_len != NULL)
4020 *pkt_len = hdr.frag_len + padding;
4022 /* The remaining bytes in the current tvb might contain multiple
4023 * DCE/RPC fragments, so create a new tvb subset for this fragment.
4024 * Only limit the end of the fragment, but not the offset start,
4025 * as the authentication function dissect_dcerpc_cn_auth() will fail
4026 * (and other functions might fail as well) computing the right start
4029 fragment_tvb = tvb_new_subset(tvb, 0,
4030 MIN((hdr.frag_len + (guint) start_offset), tvb_length(tvb)) /* length */,
4031 hdr.frag_len + start_offset /* reported_length */);
4034 * Packet type specific stuff is next.
4036 switch (hdr.ptype) {
4039 dissect_dcerpc_cn_bind (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr);
4044 dissect_dcerpc_cn_bind_ack (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr);
4049 * Nothing after the common header other than credentials.
4051 dissect_dcerpc_cn_auth (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr, TRUE,
4056 dissect_dcerpc_cn_rqst (fragment_tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
4060 dissect_dcerpc_cn_resp (fragment_tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
4064 dissect_dcerpc_cn_fault (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr);
4068 dissect_dcerpc_cn_bind_nak (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr);
4074 * Nothing after the common header other than an authentication
4077 dissect_dcerpc_cn_auth (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
4083 * Nothing after the common header, not even an authentication
4089 /* might as well dissect the auth info */
4090 dissect_dcerpc_cn_auth (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
4098 * DCERPC dissector for connection oriented calls over packet-oriented
4102 dissect_dcerpc_cn_pk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4105 * Only one PDU per transport packet, and only one transport
4108 pinfo->dcetransporttype=DCE_TRANSPORT_UNKNOWN;
4109 if (!dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE, NULL)) {
4111 * It wasn't a DCERPC PDU.
4123 * DCERPC dissector for connection oriented calls over byte-stream
4125 * we need to distinguish here between SMB and non-TCP (more in the future?)
4126 * to be able to know what kind of private_data structure to expect.
4129 dissect_dcerpc_cn_bs_body (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4131 volatile int offset = 0;
4133 volatile gboolean dcerpc_pdus = 0;
4134 volatile gboolean ret = FALSE;
4137 * There may be multiple PDUs per transport packet; keep
4140 while (tvb_reported_length_remaining(tvb, offset) != 0) {
4142 * Catch ReportedBoundsError, so that even if the stub data is bad,
4143 * we don't abort the full DCE RPC dissection - there might be more
4144 * than one DCE RPC PDU in the data being dissected.
4146 * If we get BoundsError, it means the frame was cut short by a
4147 * snapshot length, so there's nothing more to dissect; just
4148 * re-throw that exception.
4152 if(dissect_dcerpc_cn (tvb, offset, pinfo, tree,
4153 dcerpc_cn_desegment, &pdu_len)) {
4156 } CATCH(BoundsError) {
4158 } CATCH(ReportedBoundsError) {
4159 show_reported_bounds_error(tvb, pinfo, tree);
4161 * Presumably it looked enough like a DCE RPC PDU that we
4162 * dissected enough of it to throw an exception.
4175 * Well, we've seen at least one DCERPC PDU.
4179 /* if we had more than one Req/Resp in this PDU change the protocol column */
4180 /* this will formerly contain the last interface name, which may not be the same for all Req/Resp */
4181 if (dcerpc_pdus >= 2 && check_col (pinfo->cinfo, COL_PROTOCOL))
4182 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "%u*DCERPC", dcerpc_pdus);
4186 * Desegmentation required - bail now, but give the user a hint that desegmentation might be done later.
4188 proto_tree_add_uint_format(tree, hf_dcerpc_cn_deseg_req, tvb, offset,
4190 tvb_reported_length_remaining(tvb, offset),
4191 "[DCE RPC: %u byte%s left, desegmentation might follow]",
4192 tvb_reported_length_remaining(tvb, offset),
4193 plurality(tvb_reported_length_remaining(tvb, offset), "", "s"));
4198 * Step to the next PDU.
4206 dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4208 pinfo->dcetransporttype=DCE_TRANSPORT_UNKNOWN;
4209 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
4213 dissect_dcerpc_cn_smbpipe (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4215 pinfo->dcetransporttype=DCE_CN_TRANSPORT_SMBPIPE;
4216 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
4220 dissect_dcerpc_cn_smb2 (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4222 pinfo->dcetransporttype=DCE_TRANSPORT_UNKNOWN;
4223 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
4229 dissect_dcerpc_dg_auth (tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
4230 e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
4232 proto_item *ti = NULL;
4233 proto_tree *auth_tree = NULL;
4234 guint8 protection_level;
4237 * Initially set "*auth_level_p" to -1 to indicate that we haven't
4238 * yet seen any authentication level information.
4240 if (auth_level_p != NULL)
4244 * The authentication information is at the *end* of the PDU; in
4245 * request and response PDUs, the request and response stub data
4248 * If the full packet is here, and there's data past the end of the
4249 * packet body, then dissect the auth info.
4251 offset += hdr->frag_len;
4252 if (tvb_length_remaining(tvb, offset) > 0) {
4253 switch (hdr->auth_proto) {
4255 case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
4256 ti = proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Kerberos authentication verifier");
4257 auth_tree = proto_item_add_subtree (ti, ett_dcerpc_krb5_auth_verf);
4258 protection_level = tvb_get_guint8 (tvb, offset);
4259 if (auth_level_p != NULL)
4260 *auth_level_p = protection_level;
4261 proto_tree_add_uint (auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
4263 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, FALSE);
4265 if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
4266 offset += 6; /* 6 bytes of padding */
4268 offset += 2; /* 6 bytes of padding */
4269 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, FALSE);
4274 proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Authentication verifier");
4281 dissect_dcerpc_dg_cancel_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
4282 proto_tree *dcerpc_tree,
4283 e_dce_dg_common_hdr_t *hdr)
4287 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4288 hdr->drep, hf_dcerpc_dg_cancel_vers,
4294 /* The only version we know about */
4295 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4296 hdr->drep, hf_dcerpc_dg_cancel_id,
4298 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
4299 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
4306 dissect_dcerpc_dg_cancel (tvbuff_t *tvb, int offset, packet_info *pinfo,
4307 proto_tree *dcerpc_tree,
4308 e_dce_dg_common_hdr_t *hdr)
4312 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4313 hdr->drep, hf_dcerpc_dg_cancel_vers,
4319 /* The only version we know about */
4320 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4321 hdr->drep, hf_dcerpc_dg_cancel_id,
4323 /* XXX - are NDR booleans 32 bits? */
4325 /* XXX - the RPC reference in chapter: "the cancel PDU" doesn't mention
4326 the accepting_cancels field (it's only in the cancel_ack PDU)! */
4327 /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4328 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
4335 dissect_dcerpc_dg_fack (tvbuff_t *tvb, int offset, packet_info *pinfo,
4336 proto_tree *dcerpc_tree,
4337 e_dce_dg_common_hdr_t *hdr)
4344 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
4345 hdr->drep, hf_dcerpc_dg_fack_vers,
4352 case 0: /* The only version documented in the DCE RPC 1.1 spec */
4353 case 1: /* This appears to be the same */
4354 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
4355 hdr->drep, hf_dcerpc_dg_fack_window_size,
4357 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4358 hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
4360 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4361 hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
4363 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
4364 hdr->drep, hf_dcerpc_dg_fack_serial_num,
4366 if (check_col (pinfo->cinfo, COL_INFO)) {
4367 col_append_fstr (pinfo->cinfo, COL_INFO, " serial: %u",
4370 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
4371 hdr->drep, hf_dcerpc_dg_fack_selack_len,
4373 for (i = 0; i < selack_len; i++) {
4374 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4375 hdr->drep, hf_dcerpc_dg_fack_selack,
4384 dissect_dcerpc_dg_reject_fault (tvbuff_t *tvb, int offset, packet_info *pinfo,
4385 proto_tree *dcerpc_tree,
4386 e_dce_dg_common_hdr_t *hdr)
4390 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4391 hdr->drep, hf_dcerpc_dg_status,
4394 if (check_col (pinfo->cinfo, COL_INFO)) {
4395 col_append_fstr (pinfo->cinfo, COL_INFO,
4397 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
4402 dissect_dcerpc_dg_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
4403 proto_tree *dcerpc_tree, proto_tree *tree,
4404 e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
4406 int length, reported_length, stub_length;
4407 gboolean save_fragmented;
4408 fragment_data *fd_head;
4411 proto_item *parent_pi;
4413 if (check_col (pinfo->cinfo, COL_INFO))
4414 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u len: %u",
4415 di->call_data->opnum, hdr->frag_len );
4417 length = tvb_length_remaining (tvb, offset);
4418 reported_length = tvb_reported_length_remaining (tvb, offset);
4419 stub_length = hdr->frag_len;
4420 if (length > stub_length)
4421 length = stub_length;
4422 if (reported_length > stub_length)
4423 reported_length = stub_length;
4425 save_fragmented = pinfo->fragmented;
4427 /* If we don't have reassembly enabled, or this packet contains
4428 the entire PDU, or if this is a short frame (or a frame
4429 not reassembled at a lower layer) that doesn't include all
4430 the data in the fragment, just call the handoff directly if
4431 this is the first fragment or the PDU isn't fragmented. */
4432 if( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
4433 !tvb_bytes_exist(tvb, offset, stub_length) ){
4434 if(hdr->frag_num == 0) {
4437 /* First fragment, possibly the only fragment */
4440 * XXX - authentication info?
4442 pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
4443 next_tvb = tvb_new_subset (tvb, offset, length,
4445 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
4446 next_tvb, hdr->drep, di, NULL);
4448 /* PDU is fragmented and this isn't the first fragment */
4449 col_append_str(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
4452 tvb_ensure_bytes_exist(tvb, offset, stub_length);
4453 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
4454 "Fragment data (%d byte%s)",
4456 plurality(stub_length, "", "s"));
4461 /* Reassembly is enabled, the PDU is fragmented, and
4462 we have all the data in the fragment; the first two
4463 of those mean we should attempt reassembly, and the
4464 third means we can attempt reassembly. */
4467 tvb_ensure_bytes_exist(tvb, offset, stub_length);
4468 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
4469 "Fragment data (%d byte%s)", stub_length,
4470 plurality(stub_length, "", "s"));
4474 fd_head = fragment_add_dcerpc_dg(tvb, offset, pinfo,
4475 hdr->seqnum, &hdr->act_id, dcerpc_cl_reassemble_table,
4476 hdr->frag_num, stub_length,
4477 !(hdr->flags1 & PFCL1_LASTFRAG));
4478 if (fd_head != NULL) {
4479 /* We completed reassembly... */
4480 if(pinfo->fd->num==fd_head->reassembled_in) {
4481 /* ...and this is the reassembled RPC PDU */
4482 next_tvb = tvb_new_child_real_data(tvb, fd_head->data, fd_head->len, fd_head->len);
4483 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
4484 show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
4485 tree, pinfo, next_tvb, &pi);
4488 * XXX - authentication info?
4490 pinfo->fragmented = FALSE;
4491 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
4492 next_tvb, hdr->drep, di, NULL);
4494 /* ...and this isn't the reassembled RPC PDU */
4495 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
4496 tvb, 0, 0, fd_head->reassembled_in);
4497 PROTO_ITEM_SET_GENERATED(pi);
4498 parent_pi = proto_tree_get_parent(dcerpc_tree);
4499 if(parent_pi != NULL) {
4500 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
4502 if (check_col(pinfo->cinfo, COL_INFO)) {
4503 col_append_fstr(pinfo->cinfo, COL_INFO,
4504 " [DCE/RPC fragment, reas: #%u]", fd_head->reassembled_in);
4508 /* Reassembly isn't completed yet */
4509 col_append_str(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
4512 pinfo->fragmented = save_fragmented;
4516 dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo,
4517 proto_tree *dcerpc_tree, proto_tree *tree,
4518 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4521 dcerpc_call_value *value, v;
4522 dcerpc_matched_key matched_key, *new_matched_key;
4524 proto_item *parent_pi;
4527 if(!(pinfo->fd->flags.visited)){
4528 dcerpc_call_value *call_value;
4529 dcerpc_dg_call_key *call_key;
4531 call_key=se_alloc (sizeof (dcerpc_dg_call_key));
4532 call_key->conv=conv;
4533 call_key->seqnum=hdr->seqnum;
4534 call_key->act_id=hdr->act_id;
4536 call_value=se_alloc (sizeof (dcerpc_call_value));
4537 call_value->uuid = hdr->if_id;
4538 call_value->ver = hdr->if_ver;
4539 call_value->object_uuid = hdr->obj_id;
4540 call_value->opnum = hdr->opnum;
4541 call_value->req_frame=pinfo->fd->num;
4542 call_value->req_time=pinfo->fd->abs_ts;
4543 call_value->rep_frame=0;
4544 call_value->max_ptr=0;
4545 call_value->se_data = NULL;
4546 call_value->private_data = NULL;
4547 call_value->pol = NULL;
4548 g_hash_table_insert (dcerpc_dg_calls, call_key, call_value);
4550 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
4551 new_matched_key->frame = pinfo->fd->num;
4552 new_matched_key->call_id = hdr->seqnum;
4553 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
4556 matched_key.frame = pinfo->fd->num;
4557 matched_key.call_id = hdr->seqnum;
4558 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
4560 v.uuid = hdr->if_id;
4561 v.ver = hdr->if_ver;
4562 v.object_uuid = hdr->obj_id;
4563 v.opnum = hdr->opnum;
4564 v.req_frame = pinfo->fd->num;
4568 v.private_data=NULL;
4573 di->call_id = hdr->seqnum;
4575 di->ptype = PDU_REQ;
4576 di->call_data = value;
4578 if(value->rep_frame!=0){
4579 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
4580 tvb, 0, 0, value->rep_frame);
4581 PROTO_ITEM_SET_GENERATED(pi);
4582 parent_pi = proto_tree_get_parent(dcerpc_tree);
4583 if(parent_pi != NULL) {
4584 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
4587 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
4591 dissect_dcerpc_dg_resp (tvbuff_t *tvb, int offset, packet_info *pinfo,
4592 proto_tree *dcerpc_tree, proto_tree *tree,
4593 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4596 dcerpc_call_value *value, v;
4597 dcerpc_matched_key matched_key, *new_matched_key;
4599 proto_item *parent_pi;
4602 if(!(pinfo->fd->flags.visited)){
4603 dcerpc_call_value *call_value;
4604 dcerpc_dg_call_key call_key;
4607 call_key.seqnum=hdr->seqnum;
4608 call_key.act_id=hdr->act_id;
4610 if((call_value=g_hash_table_lookup(dcerpc_dg_calls, &call_key))){
4611 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
4612 new_matched_key->frame = pinfo->fd->num;
4613 new_matched_key->call_id = hdr->seqnum;
4614 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
4615 if(call_value->rep_frame==0){
4616 call_value->rep_frame=pinfo->fd->num;
4621 matched_key.frame = pinfo->fd->num;
4622 matched_key.call_id = hdr->seqnum;
4623 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
4625 v.uuid = hdr->if_id;
4626 v.ver = hdr->if_ver;
4627 v.object_uuid = hdr->obj_id;
4628 v.opnum = hdr->opnum;
4630 v.rep_frame=pinfo->fd->num;
4632 v.private_data=NULL;
4639 di->ptype = PDU_RESP;
4640 di->call_data = value;
4642 if(value->req_frame!=0){
4644 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4645 tvb, 0, 0, value->req_frame);
4646 PROTO_ITEM_SET_GENERATED(pi);
4647 parent_pi = proto_tree_get_parent(dcerpc_tree);
4648 if(parent_pi != NULL) {
4649 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
4651 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
4652 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
4653 PROTO_ITEM_SET_GENERATED(pi);
4655 pi = proto_tree_add_text(dcerpc_tree,
4656 tvb, 0, 0, "No request to this DCE/RPC call found");
4657 expert_add_info_format(pinfo, pi, PI_SEQUENCE, PI_NOTE,
4658 "No request to this DCE/RPC call found");
4660 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
4664 dissect_dcerpc_dg_ping_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
4665 proto_tree *dcerpc_tree,
4666 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4668 proto_item *parent_pi;
4669 /* if(!(pinfo->fd->flags.visited)){*/
4670 dcerpc_call_value *call_value;
4671 dcerpc_dg_call_key call_key;
4674 call_key.seqnum=hdr->seqnum;
4675 call_key.act_id=hdr->act_id;
4677 if((call_value=g_hash_table_lookup(dcerpc_dg_calls, &call_key))){
4681 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4682 tvb, 0, 0, call_value->req_frame);
4683 PROTO_ITEM_SET_GENERATED(pi);
4684 parent_pi = proto_tree_get_parent(dcerpc_tree);
4685 if(parent_pi != NULL) {
4686 proto_item_append_text(parent_pi, ", [Req: #%u]", call_value->req_frame);
4689 if (check_col (pinfo->cinfo, COL_INFO))
4690 col_append_fstr(pinfo->cinfo, COL_INFO, " [req: #%u]", call_value->req_frame);
4692 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &call_value->req_time);
4693 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
4694 PROTO_ITEM_SET_GENERATED(pi);
4700 * DCERPC dissector for connectionless calls
4703 dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4705 proto_item *ti = NULL;
4706 proto_item *tf = NULL;
4707 proto_tree *dcerpc_tree = NULL;
4708 proto_tree *dg_flags1_tree = NULL;
4709 proto_tree *dg_flags2_tree = NULL;
4710 proto_tree *drep_tree = NULL;
4711 e_dce_dg_common_hdr_t hdr;
4713 conversation_t *conv;
4716 const char *uuid_name = NULL;
4719 * Check if this looks like a CL DCERPC call. All dg packets
4720 * have an 80 byte header on them. Which starts with
4721 * version (4), pkt_type.
4723 if (tvb_length (tvb) < sizeof (hdr)) {
4727 /* Version must be 4 */
4728 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
4729 if (hdr.rpc_ver != 4)
4732 /* Type must be <=19 or its not DCE/RPC */
4733 hdr.ptype = tvb_get_guint8 (tvb, offset++);
4737 /* flags1 has bit 1 and 8 as reserved so if any of them are set, it is
4738 probably not a DCE/RPC packet
4740 hdr.flags1 = tvb_get_guint8 (tvb, offset++);
4744 /* flags2 has all bits except bit 2 as reserved so if any of them are set
4745 it is probably not DCE/RPC.
4747 hdr.flags2 = tvb_get_guint8 (tvb, offset++);
4752 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
4753 if (check_col (pinfo->cinfo, COL_INFO))
4754 col_add_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
4756 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
4757 offset += sizeof (hdr.drep);
4758 hdr.serial_hi = tvb_get_guint8 (tvb, offset++);
4759 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.obj_id);
4761 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.if_id);
4763 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.act_id);
4765 hdr.server_boot = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4767 hdr.if_ver = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4769 hdr.seqnum = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4771 hdr.opnum = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4773 hdr.ihint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4775 hdr.ahint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4777 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4779 hdr.frag_num = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4781 hdr.auth_proto = tvb_get_guint8 (tvb, offset++);
4782 hdr.serial_lo = tvb_get_guint8 (tvb, offset++);
4785 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, -1, FALSE);
4787 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
4788 proto_item_append_text(ti, " %s, Seq: %u, Serial: %u, Frag: %u, FragLen: %u",
4789 val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"),
4790 hdr.seqnum, hdr.serial_hi*256+hdr.serial_lo,
4791 hdr.frag_num, hdr.frag_len);
4797 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
4801 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
4805 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
4806 dg_flags1_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags1);
4807 if (dg_flags1_tree) {
4808 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
4809 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
4810 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
4811 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
4812 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
4813 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
4814 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
4815 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
4817 proto_item_append_text(tf, " %s%s%s%s%s%s",
4818 (hdr.flags1 & PFCL1_BROADCAST) ? "\"Broadcast\" " : "",
4819 (hdr.flags1 & PFCL1_IDEMPOTENT) ? "\"Idempotent\" " : "",
4820 (hdr.flags1 & PFCL1_MAYBE) ? "\"Maybe\" " : "",
4821 (hdr.flags1 & PFCL1_NOFACK) ? "\"No Fack\" " : "",
4822 (hdr.flags1 & PFCL1_FRAG) ? "\"Fragment\" " : "",
4823 (hdr.flags1 & PFCL1_LASTFRAG) ? "\"Last Fragment\" " : "");
4830 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
4831 dg_flags2_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags2);
4832 if (dg_flags2_tree) {
4833 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
4834 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
4835 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
4836 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
4837 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
4838 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
4839 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
4840 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
4842 proto_item_append_text(tf, " %s",
4843 (hdr.flags2 & PFCL2_CANCEL_PENDING) ? "\"Cancel Pending\" " : "");
4850 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
4851 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
4853 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
4854 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
4855 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
4856 proto_item_append_text(tf, " (Order: %s, Char: %s, Float: %s)",
4857 val_to_str(hdr.drep[0] >> 4, drep_byteorder_vals, "Unknown"),
4858 val_to_str(hdr.drep[0] & 0x0f, drep_character_vals, "Unknown"),
4859 val_to_str(hdr.drep[1], drep_fp_vals, "Unknown"));
4862 offset += sizeof (hdr.drep);
4865 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
4869 proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
4870 offset, 16, (e_guid_t *) &hdr.obj_id, "Object UUID: %s",
4871 guid_to_str((e_guid_t *) &hdr.obj_id));
4876 uuid_str = guid_to_str((e_guid_t*)&hdr.if_id);
4877 uuid_name = guids_get_uuid_name(&hdr.if_id);
4879 proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
4880 offset, 16, (e_guid_t *) &hdr.if_id, "Interface: %s UUID: %s", uuid_name, uuid_str);
4882 proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
4883 offset, 16, (e_guid_t *) &hdr.if_id, "Interface UUID: %s", uuid_str);
4889 proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
4890 offset, 16, (e_guid_t *) &hdr.act_id, "Activity: %s",
4891 guid_to_str((e_guid_t *) &hdr.act_id));
4896 nstime_t server_boot;
4898 server_boot.secs = hdr.server_boot;
4899 server_boot.nsecs = 0;
4901 if (hdr.server_boot == 0)
4902 proto_tree_add_time_format (dcerpc_tree, hf_dcerpc_dg_server_boot,
4903 tvb, offset, 4, &server_boot,
4904 "Server boot time: Unknown (0)");
4906 proto_tree_add_time (dcerpc_tree, hf_dcerpc_dg_server_boot,
4907 tvb, offset, 4, &server_boot);
4912 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
4916 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
4917 if (check_col (pinfo->cinfo, COL_INFO)) {
4918 col_append_fstr (pinfo->cinfo, COL_INFO, ": seq: %u", hdr.seqnum);
4920 if (check_col (pinfo->cinfo, COL_DCE_CALL)) {
4921 col_append_fstr (pinfo->cinfo, COL_DCE_CALL, "%u", hdr.seqnum);
4926 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
4930 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
4934 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
4938 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
4942 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
4943 if (check_col (pinfo->cinfo, COL_INFO)) {
4944 if (hdr.flags1 & PFCL1_FRAG) {
4945 /* Fragmented - put the fragment number into the Info column */
4946 col_append_fstr (pinfo->cinfo, COL_INFO, " frag: %u",
4953 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
4957 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
4958 if (check_col (pinfo->cinfo, COL_INFO)) {
4959 if (hdr.flags1 & PFCL1_FRAG) {
4960 /* Fragmented - put the serial number into the Info column */
4961 col_append_fstr (pinfo->cinfo, COL_INFO, " serial: %u",
4962 (hdr.serial_hi << 8) | hdr.serial_lo);
4969 * XXX - for Kerberos, we get a protection level; if it's
4970 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
4973 dissect_dcerpc_dg_auth (tvb, offset, dcerpc_tree, &hdr,
4978 * keeping track of the conversation shouldn't really be necessary
4979 * for connectionless packets, because everything we need to know
4980 * to dissect is in the header for each packet. Unfortunately,
4981 * Microsoft's implementation is buggy and often puts the
4982 * completely wrong if_id in the header. go figure. So, keep
4983 * track of the seqnum and use that if possible. Note: that's not
4984 * completely correct. It should really be done based on both the
4985 * activity_id and seqnum. I haven't seen anywhere that it would
4986 * make a difference, but for future reference...
4988 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
4989 pinfo->srcport, pinfo->destport, 0);
4991 fprintf(stderr,"Creating a new conv on packet %d\n",pinfo->fd->num);
4992 conv = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
4993 pinfo->srcport, pinfo->destport, 0);
4997 * Packet type specific stuff is next.
5000 switch (hdr.ptype) {
5002 case PDU_CANCEL_ACK:
5003 /* Body is optional */
5004 /* XXX - we assume "frag_len" is the length of the body */
5005 if (hdr.frag_len != 0)
5006 dissect_dcerpc_dg_cancel_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
5011 * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
5012 * but in at least one capture none of the Cl_cancel PDUs had a
5015 /* XXX - we assume "frag_len" is the length of the body */
5016 if (hdr.frag_len != 0)
5017 dissect_dcerpc_dg_cancel (tvb, offset, pinfo, dcerpc_tree, &hdr);
5021 /* Body is optional; if present, it's the same as PDU_FACK */
5022 /* XXX - we assume "frag_len" is the length of the body */
5023 if (hdr.frag_len != 0)
5024 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
5028 /* Body is optional */
5029 /* XXX - we assume "frag_len" is the length of the body */
5030 if (hdr.frag_len != 0)
5031 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
5036 dissect_dcerpc_dg_reject_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
5040 dissect_dcerpc_dg_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
5044 dissect_dcerpc_dg_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
5047 /* these requests have no body */
5050 dissect_dcerpc_dg_ping_ack (tvb, offset, pinfo, dcerpc_tree, &hdr, conv);
5061 dcerpc_init_protocol (void)
5063 /* structures and data for BIND */
5065 g_hash_table_destroy (dcerpc_binds);
5069 dcerpc_binds = g_hash_table_new (dcerpc_bind_hash, dcerpc_bind_equal);
5072 /* structures and data for CALL */
5073 if (dcerpc_cn_calls){
5074 g_hash_table_destroy (dcerpc_cn_calls);
5076 dcerpc_cn_calls = g_hash_table_new (dcerpc_cn_call_hash, dcerpc_cn_call_equal);
5077 if (dcerpc_dg_calls){
5078 g_hash_table_destroy (dcerpc_dg_calls);
5080 dcerpc_dg_calls = g_hash_table_new (dcerpc_dg_call_hash, dcerpc_dg_call_equal);
5082 /* structure and data for MATCHED */
5083 if (dcerpc_matched){
5084 g_hash_table_destroy (dcerpc_matched);
5086 dcerpc_matched = g_hash_table_new (dcerpc_matched_hash, dcerpc_matched_equal);
5088 /* call the registered hooks */
5089 g_hook_list_invoke(&dcerpc_hooks_init_protos, FALSE /* not may_recurse */);
5093 proto_register_dcerpc (void)
5095 static hf_register_info hf[] = {
5096 { &hf_dcerpc_request_in,
5097 { "Request in frame", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE,
5098 NULL, 0, "This packet is a response to the packet with this number", HFILL }},
5099 { &hf_dcerpc_response_in,
5100 { "Response in frame", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
5101 NULL, 0, "This packet will be responded in the packet with this number", HFILL }},
5102 { &hf_dcerpc_referent_id,
5103 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
5104 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
5106 { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5107 { &hf_dcerpc_ver_minor,
5108 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5109 { &hf_dcerpc_packet_type,
5110 { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS (pckt_vals), 0x0, NULL, HFILL }},
5111 { &hf_dcerpc_cn_flags,
5112 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5113 { &hf_dcerpc_cn_flags_first_frag,
5114 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFC_FIRST_FRAG, NULL, HFILL }},
5115 { &hf_dcerpc_cn_flags_last_frag,
5116 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFC_LAST_FRAG, NULL, HFILL }},
5117 { &hf_dcerpc_cn_flags_cancel_pending,
5118 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFC_PENDING_CANCEL, NULL, HFILL }},
5119 { &hf_dcerpc_cn_flags_reserved,
5120 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFC_RESERVED_1, NULL, HFILL }},
5121 { &hf_dcerpc_cn_flags_mpx,
5122 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFC_CONC_MPX, NULL, HFILL }},
5123 { &hf_dcerpc_cn_flags_dne,
5124 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFC_DID_NOT_EXECUTE, NULL, HFILL }},
5125 { &hf_dcerpc_cn_flags_maybe,
5126 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFC_MAYBE, NULL, HFILL }},
5127 { &hf_dcerpc_cn_flags_object,
5128 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFC_OBJECT_UUID, NULL, HFILL }},
5130 { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5131 { &hf_dcerpc_drep_byteorder,
5132 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS (drep_byteorder_vals), 0x0, NULL, HFILL }},
5133 { &hf_dcerpc_drep_character,
5134 { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS (drep_character_vals), 0x0, NULL, HFILL }},
5135 { &hf_dcerpc_drep_fp,
5136 { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS (drep_fp_vals), 0x0, NULL, HFILL }},
5137 { &hf_dcerpc_cn_frag_len,
5138 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5139 { &hf_dcerpc_cn_auth_len,
5140 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5141 { &hf_dcerpc_cn_call_id,
5142 { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5143 { &hf_dcerpc_cn_max_xmit,
5144 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5145 { &hf_dcerpc_cn_max_recv,
5146 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5147 { &hf_dcerpc_cn_assoc_group,
5148 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5149 { &hf_dcerpc_cn_num_ctx_items,
5150 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5151 { &hf_dcerpc_cn_ctx_item,
5152 { "Ctx Item", "dcerpc.cn_ctx_item", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5153 { &hf_dcerpc_cn_ctx_id,
5154 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5155 { &hf_dcerpc_cn_num_trans_items,
5156 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5157 { &hf_dcerpc_cn_bind_abstract_syntax,
5158 { "Abstract Syntax", "dcerpc.cn_bind_abstract_syntax", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5159 { &hf_dcerpc_cn_bind_if_id,
5160 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5161 { &hf_dcerpc_cn_bind_if_ver,
5162 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5163 { &hf_dcerpc_cn_bind_if_ver_minor,
5164 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5165 { &hf_dcerpc_cn_bind_trans_syntax,
5166 { "Transfer Syntax", "dcerpc.cn_bind_trans", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5167 { &hf_dcerpc_cn_bind_trans_id,
5168 { "ID", "dcerpc.cn_bind_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5169 { &hf_dcerpc_cn_bind_trans_ver,
5170 { "ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5171 { &hf_dcerpc_cn_alloc_hint,
5172 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5173 { &hf_dcerpc_cn_sec_addr_len,
5174 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5175 { &hf_dcerpc_cn_sec_addr,
5176 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5177 { &hf_dcerpc_cn_num_results,
5178 { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5179 { &hf_dcerpc_cn_ack_result,
5180 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, NULL, HFILL }},
5181 { &hf_dcerpc_cn_ack_reason,
5182 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, NULL, HFILL }},
5183 { &hf_dcerpc_cn_ack_trans_id,
5184 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5185 { &hf_dcerpc_cn_ack_trans_ver,
5186 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5187 { &hf_dcerpc_cn_reject_reason,
5188 { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, NULL, HFILL }},
5189 { &hf_dcerpc_cn_num_protocols,
5190 { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5191 { &hf_dcerpc_cn_protocol_ver_major,
5192 { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5193 { &hf_dcerpc_cn_protocol_ver_minor,
5194 { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5195 { &hf_dcerpc_cn_cancel_count,
5196 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5197 { &hf_dcerpc_cn_status,
5198 { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, NULL, HFILL }},
5199 { &hf_dcerpc_cn_deseg_req,
5200 { "Desegmentation Required", "dcerpc.cn_deseg_req", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5201 { &hf_dcerpc_auth_type,
5202 { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, NULL, HFILL }},
5203 { &hf_dcerpc_auth_level,
5204 { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS (authn_level_vals), 0x0, NULL, HFILL }},
5205 { &hf_dcerpc_auth_pad_len,
5206 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5207 { &hf_dcerpc_auth_rsrvd,
5208 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5209 { &hf_dcerpc_auth_ctx_id,
5210 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5211 { &hf_dcerpc_dg_flags1,
5212 { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5213 { &hf_dcerpc_dg_flags1_rsrvd_01,
5214 { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL1_RESERVED_01, NULL, HFILL }},
5215 { &hf_dcerpc_dg_flags1_last_frag,
5216 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL1_LASTFRAG, NULL, HFILL }},
5217 { &hf_dcerpc_dg_flags1_frag,
5218 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL1_FRAG, NULL, HFILL }},
5219 { &hf_dcerpc_dg_flags1_nofack,
5220 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL1_NOFACK, NULL, HFILL }},
5221 { &hf_dcerpc_dg_flags1_maybe,
5222 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL1_MAYBE, NULL, HFILL }},
5223 { &hf_dcerpc_dg_flags1_idempotent,
5224 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL1_IDEMPOTENT, NULL, HFILL }},
5225 { &hf_dcerpc_dg_flags1_broadcast,
5226 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL1_BROADCAST, NULL, HFILL }},
5227 { &hf_dcerpc_dg_flags1_rsrvd_80,
5228 { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL1_RESERVED_80, NULL, HFILL }},
5229 { &hf_dcerpc_dg_flags2,
5230 { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5231 { &hf_dcerpc_dg_flags2_rsrvd_01,
5232 { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL2_RESERVED_01, NULL, HFILL }},
5233 { &hf_dcerpc_dg_flags2_cancel_pending,
5234 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL2_CANCEL_PENDING, NULL, HFILL }},
5235 { &hf_dcerpc_dg_flags2_rsrvd_04,
5236 { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL2_RESERVED_04, NULL, HFILL }},
5237 { &hf_dcerpc_dg_flags2_rsrvd_08,
5238 { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL2_RESERVED_08, NULL, HFILL }},
5239 { &hf_dcerpc_dg_flags2_rsrvd_10,
5240 { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL2_RESERVED_10, NULL, HFILL }},
5241 { &hf_dcerpc_dg_flags2_rsrvd_20,
5242 { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL2_RESERVED_20, NULL, HFILL }},
5243 { &hf_dcerpc_dg_flags2_rsrvd_40,
5244 { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL2_RESERVED_40, NULL, HFILL }},
5245 { &hf_dcerpc_dg_flags2_rsrvd_80,
5246 { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL2_RESERVED_80, NULL, HFILL }},
5247 { &hf_dcerpc_dg_serial_lo,
5248 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5249 { &hf_dcerpc_dg_serial_hi,
5250 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5251 { &hf_dcerpc_dg_ahint,
5252 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5253 { &hf_dcerpc_dg_ihint,
5254 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5255 { &hf_dcerpc_dg_frag_len,
5256 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5257 { &hf_dcerpc_dg_frag_num,
5258 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5259 { &hf_dcerpc_dg_auth_proto,
5260 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, NULL, HFILL }},
5261 { &hf_dcerpc_dg_seqnum,
5262 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5263 { &hf_dcerpc_dg_server_boot,
5264 { "Server boot time", "dcerpc.dg_server_boot", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5265 { &hf_dcerpc_dg_if_ver,
5266 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5267 { &hf_dcerpc_krb5_av_prot_level,
5268 { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, NULL, HFILL }},
5269 { &hf_dcerpc_krb5_av_key_vers_num,
5270 { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5271 { &hf_dcerpc_krb5_av_key_auth_verifier,
5272 { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5273 { &hf_dcerpc_obj_id,
5274 { "Object", "dcerpc.obj_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5275 { &hf_dcerpc_dg_if_id,
5276 { "Interface", "dcerpc.dg_if_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5277 { &hf_dcerpc_dg_act_id,
5278 { "Activity", "dcerpc.dg_act_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5280 { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5282 { &hf_dcerpc_dg_cancel_vers,
5283 { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5285 { &hf_dcerpc_dg_cancel_id,
5286 { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5288 { &hf_dcerpc_dg_server_accepting_cancels,
5289 { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5291 { &hf_dcerpc_dg_fack_vers,
5292 { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5294 { &hf_dcerpc_dg_fack_window_size,
5295 { "Window Size", "dcerpc.fack_window_size", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5297 { &hf_dcerpc_dg_fack_max_tsdu,
5298 { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5300 { &hf_dcerpc_dg_fack_max_frag_size,
5301 { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5303 { &hf_dcerpc_dg_fack_serial_num,
5304 { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5306 { &hf_dcerpc_dg_fack_selack_len,
5307 { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5309 { &hf_dcerpc_dg_fack_selack,
5310 { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5312 { &hf_dcerpc_dg_status,
5313 { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, NULL, HFILL }},
5315 { &hf_dcerpc_array_max_count,
5316 { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
5318 { &hf_dcerpc_array_offset,
5319 { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
5321 { &hf_dcerpc_array_actual_count,
5322 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
5324 { &hf_dcerpc_array_buffer,
5325 { "Buffer", "dcerpc.array.buffer", FT_BYTES, BASE_NONE, NULL, 0x0, "Buffer: Buffer containing elements of the array", HFILL }},
5328 { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5330 { &hf_dcerpc_fragments,
5331 { "Reassembled DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
5332 NULL, 0x0, "DCE/RPC Fragments", HFILL }},
5334 { &hf_dcerpc_fragment,
5335 { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM, BASE_NONE,
5336 NULL, 0x0, NULL, HFILL }},
5338 { &hf_dcerpc_fragment_overlap,
5339 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE,
5340 NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
5342 { &hf_dcerpc_fragment_overlap_conflict,
5343 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE,
5344 NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
5346 { &hf_dcerpc_fragment_multiple_tails,
5347 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE,
5348 NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
5350 { &hf_dcerpc_fragment_too_long_fragment,
5351 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE,
5352 NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
5354 { &hf_dcerpc_fragment_error,
5355 { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE,
5356 NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
5359 { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE,
5360 NULL, 0, "Time between Request and Response for DCE-RPC calls", HFILL }},
5362 { &hf_dcerpc_reassembled_in,
5363 { "Reassembled PDU in frame", "dcerpc.reassembled_in", FT_FRAMENUM, BASE_NONE,
5364 NULL, 0x0, "The DCE/RPC PDU is completely reassembled in the packet with this number", HFILL }},
5366 { &hf_dcerpc_unknown_if_id,
5367 { "Unknown DCERPC interface id", "dcerpc.unknown_if_id", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5369 static gint *ett[] = {
5371 &ett_dcerpc_cn_flags,
5373 &ett_dcerpc_cn_iface,
5374 &ett_dcerpc_cn_trans_syntax,
5376 &ett_dcerpc_dg_flags1,
5377 &ett_dcerpc_dg_flags2,
5378 &ett_dcerpc_pointer_data,
5380 &ett_dcerpc_fragments,
5381 &ett_dcerpc_fragment,
5382 &ett_dcerpc_krb5_auth_verf,
5384 module_t *dcerpc_module;
5386 proto_dcerpc = proto_register_protocol ("DCE RPC", "DCERPC", "dcerpc");
5387 proto_register_field_array (proto_dcerpc, hf, array_length (hf));
5388 proto_register_subtree_array (ett, array_length (ett));
5389 register_init_routine (dcerpc_init_protocol);
5390 dcerpc_module = prefs_register_protocol (proto_dcerpc, NULL);
5391 prefs_register_bool_preference (dcerpc_module,
5393 "Reassemble DCE/RPC messages spanning multiple TCP segments",
5394 "Whether the DCE/RPC dissector should reassemble messages spanning multiple TCP segments."
5395 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
5396 &dcerpc_cn_desegment);
5397 prefs_register_bool_preference (dcerpc_module,
5398 "reassemble_dcerpc",
5399 "Reassemble DCE/RPC fragments",
5400 "Whether the DCE/RPC dissector should reassemble fragmented DCE/RPC PDUs",
5401 &dcerpc_reassemble);
5402 register_init_routine(dcerpc_reassemble_init);
5403 dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
5404 dcerpc_tap=register_tap("dcerpc");
5406 g_hook_list_init(&dcerpc_hooks_init_protos, sizeof(GHook));
5410 proto_reg_handoff_dcerpc (void)
5412 heur_dissector_add ("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
5413 heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
5414 heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
5415 heur_dissector_add ("smb_transact", dissect_dcerpc_cn_smbpipe, proto_dcerpc);
5416 heur_dissector_add ("smb2_heur_subdissectors", dissect_dcerpc_cn_smb2, proto_dcerpc);
5417 heur_dissector_add ("http", dissect_dcerpc_cn_bs, proto_dcerpc);
5418 dcerpc_smb_init(proto_dcerpc);