2 * Routines for DCERPC packet disassembly
3 * Copyright 2001, Todd Sabin <tas[AT]webspan.net>
4 * Copyright 2003, Tim Potter <tpot[AT]samba.org>
5 * Copyright 2010, Julien Kerihuel <j.kerihuel[AT]openchange.org>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * SPDX-License-Identifier: GPL-2.0-or-later
14 /* The DCE RPC 1.1 specification can be found at:
16 * https://publications.opengroup.org/c706
17 * https://pubs.opengroup.org/onlinepubs/009629399/
18 * https://pubs.opengroup.org/onlinepubs/009629399/toc.htm
19 * https://pubs.opengroup.org/onlinepubs/009629399/toc.pdf
21 * Microsoft extensions can be found at:
23 * MS-WPO section 7.3.1 "RPC":
24 * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wpo/7d2df784-557e-4fde-9281-9509653a0f17
29 #include <guid-utils.h>
30 #include <stdio.h> /* for sscanf() */
31 #include <epan/packet.h>
32 #include <epan/exceptions.h>
33 #include <epan/prefs.h>
34 #include <epan/reassemble.h>
36 #include <epan/srt_table.h>
37 #include <epan/expert.h>
38 #include <epan/addr_resolv.h>
39 #include <epan/show_exception.h>
40 #include <epan/decode_as.h>
41 #include <epan/proto_data.h>
44 #include <wsutil/str_util.h>
45 #include "packet-tcp.h"
46 #include "packet-dcerpc.h"
47 #include "packet-dcerpc-nt.h"
49 void proto_register_dcerpc(void);
50 void proto_reg_handoff_dcerpc(void);
52 static dissector_handle_t dcerpc_tcp_handle
;
54 static int dcerpc_tap
;
56 /* 32bit Network Data Representation, see DCE/RPC Appendix I */
57 static e_guid_t uuid_data_repr_proto
= { 0x8a885d04, 0x1ceb, 0x11c9,
58 { 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60 } };
60 /* 64bit Network Data Representation, introduced in Windows Server 2008 */
61 static e_guid_t uuid_ndr64
= { 0x71710533, 0xbeba, 0x4937,
62 { 0x83, 0x19, 0xb5, 0xdb, 0xef, 0x9c, 0xcc, 0x36 } };
64 /* see [MS-OXRPC] Appendix A: Full IDL, https://docs.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-oxcrpc/70adbb71-85a1-4023-bfdb-41e32ff37bf1 */
65 static e_guid_t uuid_asyncemsmdb
= { 0x5261574a, 0x4572, 0x206e,
66 { 0xb2, 0x68, 0x6b, 0x19, 0x92, 0x13, 0xb4, 0xe4 } };
68 static const value_string pckt_vals
[] = {
69 { PDU_REQ
, "Request"},
71 { PDU_RESP
, "Response"},
72 { PDU_FAULT
, "Fault"},
73 { PDU_WORKING
, "Working"},
74 { PDU_NOCALL
, "Nocall"},
75 { PDU_REJECT
, "Reject"},
77 { PDU_CL_CANCEL
, "Cl_cancel"},
79 { PDU_CANCEL_ACK
, "Cancel_ack"},
81 { PDU_BIND_ACK
, "Bind_ack"},
82 { PDU_BIND_NAK
, "Bind_nak"},
83 { PDU_ALTER
, "Alter_context"},
84 { PDU_ALTER_ACK
, "Alter_context_resp"},
85 { PDU_AUTH3
, "AUTH3"},
86 { PDU_SHUTDOWN
, "Shutdown"},
87 { PDU_CO_CANCEL
, "Co_cancel"},
88 { PDU_ORPHANED
, "Orphaned"},
89 { PDU_RTS
, "RPC-over-HTTP RTS"},
93 static const value_string drep_byteorder_vals
[] = {
95 { 1, "Little-endian" },
99 static const value_string drep_character_vals
[] = {
105 #define DCE_RPC_DREP_FP_IEEE 0
106 #define DCE_RPC_DREP_FP_VAX 1
107 #define DCE_RPC_DREP_FP_CRAY 2
108 #define DCE_RPC_DREP_FP_IBM 3
110 static const value_string drep_fp_vals
[] = {
111 { DCE_RPC_DREP_FP_IEEE
, "IEEE" },
112 { DCE_RPC_DREP_FP_VAX
, "VAX" },
113 { DCE_RPC_DREP_FP_CRAY
, "Cray" },
114 { DCE_RPC_DREP_FP_IBM
, "IBM" },
119 * Authentication services.
121 static const value_string authn_protocol_vals
[] = {
122 { DCE_C_RPC_AUTHN_PROTOCOL_NONE
, "None" },
123 { DCE_C_RPC_AUTHN_PROTOCOL_KRB5
, "Kerberos 5" },
124 { DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO
, "SPNEGO" },
125 { DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP
, "NTLMSSP" },
126 { DCE_C_RPC_AUTHN_PROTOCOL_GSS_SCHANNEL
, "SCHANNEL SSP" },
127 { DCE_C_RPC_AUTHN_PROTOCOL_GSS_KERBEROS
, "Kerberos SSP" },
128 { DCE_C_RPC_AUTHN_PROTOCOL_DPA
,
129 "Distributed Password Authentication SSP"},
130 { DCE_C_RPC_AUTHN_PROTOCOL_MSN
, "MSN SSP"},
131 { DCE_C_RPC_AUTHN_PROTOCOL_DIGEST
, "Digest SSP"},
132 { DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN
, "NETLOGON Secure Channel" },
133 { DCE_C_RPC_AUTHN_PROTOCOL_MQ
, "MSMQ SSP"},
140 static const value_string authn_level_vals
[] = {
141 { DCE_C_AUTHN_LEVEL_NONE
, "None" },
142 { DCE_C_AUTHN_LEVEL_CONNECT
, "Connect" },
143 { DCE_C_AUTHN_LEVEL_CALL
, "Call" },
144 { DCE_C_AUTHN_LEVEL_PKT
, "Packet" },
145 { DCE_C_AUTHN_LEVEL_PKT_INTEGRITY
, "Packet integrity" },
146 { DCE_C_AUTHN_LEVEL_PKT_PRIVACY
, "Packet privacy" },
151 * Flag bits in first flag field in connectionless PDU header.
153 #define PFCL1_RESERVED_01 0x01 /* Reserved for use by implementations */
154 #define PFCL1_LASTFRAG 0x02 /* If set, the PDU is the last
155 * fragment of a multi-PDU
157 #define PFCL1_FRAG 0x04 /* If set, the PDU is a fragment of
158 a multi-PDU transmission */
159 #define PFCL1_NOFACK 0x08 /* If set, the receiver is not
160 * requested to send a `fack' PDU
161 * for the fragment */
162 #define PFCL1_MAYBE 0x10 /* If set, the PDU is for a `maybe'
164 #define PFCL1_IDEMPOTENT 0x20 /* If set, the PDU is for an idempotent
166 #define PFCL1_BROADCAST 0x40 /* If set, the PDU is for a broadcast
168 #define PFCL1_RESERVED_80 0x80 /* Reserved for use by implementations */
171 * Flag bits in second flag field in connectionless PDU header.
173 #define PFCL2_RESERVED_01 0x01 /* Reserved for use by implementations */
174 #define PFCL2_CANCEL_PENDING 0x02 /* Cancel pending at the call end */
175 #define PFCL2_RESERVED_04 0x04 /* Reserved for future use */
176 #define PFCL2_RESERVED_08 0x08 /* Reserved for future use */
177 #define PFCL2_RESERVED_10 0x10 /* Reserved for future use */
178 #define PFCL2_RESERVED_20 0x20 /* Reserved for future use */
179 #define PFCL2_RESERVED_40 0x40 /* Reserved for future use */
180 #define PFCL2_RESERVED_80 0x80 /* Reserved for future use */
183 * Flag bits in connection-oriented PDU header.
185 #define PFC_FIRST_FRAG 0x01 /* First fragment */
186 #define PFC_LAST_FRAG 0x02 /* Last fragment */
187 #define PFC_PENDING_CANCEL 0x04 /* Cancel was pending at sender */
188 #define PFC_HDR_SIGNING PFC_PENDING_CANCEL /* on bind and alter req */
189 #define PFC_RESERVED_1 0x08
190 #define PFC_CONC_MPX 0x10 /* supports concurrent multiplexing
191 * of a single connection. */
192 #define PFC_DID_NOT_EXECUTE 0x20 /* only meaningful on `fault' packet;
193 * if true, guaranteed call did not
195 #define PFC_MAYBE 0x40 /* `maybe' call semantics requested */
196 #define PFC_OBJECT_UUID 0x80 /* if true, a non-nil object UUID
197 * was specified in the handle, and
198 * is present in the optional object
199 * field. If false, the object field
203 * Tests whether a connection-oriented PDU is fragmented; returns true if
204 * it's not fragmented (i.e., this is both the first *and* last fragment),
205 * and false otherwise.
207 #define PFC_NOT_FRAGMENTED(hdr) \
208 ((hdr->flags&(PFC_FIRST_FRAG|PFC_LAST_FRAG)) == (PFC_FIRST_FRAG|PFC_LAST_FRAG))
211 * Presentation context negotiation result.
213 static const value_string p_cont_result_vals
[] = {
215 { 1, "User rejection" },
216 { 2, "Provider rejection" },
217 { 3, "Negotiate ACK" }, /* [MS-RPCE] 2.2.2.4 */
222 * Presentation context negotiation rejection reasons.
224 static const value_string p_provider_reason_vals
[] = {
225 { 0, "Reason not specified" },
226 { 1, "Abstract syntax not supported" },
227 { 2, "Proposed transfer syntaxes not supported" },
228 { 3, "Local limit exceeded" },
235 #define REASON_NOT_SPECIFIED 0
236 #define TEMPORARY_CONGESTION 1
237 #define LOCAL_LIMIT_EXCEEDED 2
238 #define CALLED_PADDR_UNKNOWN 3 /* not used */
239 #define PROTOCOL_VERSION_NOT_SUPPORTED 4
240 #define DEFAULT_CONTEXT_NOT_SUPPORTED 5 /* not used */
241 #define USER_DATA_NOT_READABLE 6 /* not used */
242 #define NO_PSAP_AVAILABLE 7 /* not used */
243 #define AUTH_TYPE_NOT_RECOGNIZED 8 /* [MS-RPCE] 2.2.2.5 */
244 #define INVALID_CHECKSUM 9 /* [MS-RPCE] 2.2.2.5 */
246 static const value_string reject_reason_vals
[] = {
247 { REASON_NOT_SPECIFIED
, "Reason not specified" },
248 { TEMPORARY_CONGESTION
, "Temporary congestion" },
249 { LOCAL_LIMIT_EXCEEDED
, "Local limit exceeded" },
250 { CALLED_PADDR_UNKNOWN
, "Called paddr unknown" },
251 { PROTOCOL_VERSION_NOT_SUPPORTED
, "Protocol version not supported" },
252 { DEFAULT_CONTEXT_NOT_SUPPORTED
, "Default context not supported" },
253 { USER_DATA_NOT_READABLE
, "User data not readable" },
254 { NO_PSAP_AVAILABLE
, "No PSAP available" },
255 { AUTH_TYPE_NOT_RECOGNIZED
, "Authentication type not recognized" },
256 { INVALID_CHECKSUM
, "Invalid checksum" },
261 * Reject status codes.
263 static const value_string reject_status_vals
[] = {
264 { 0, "Stub-defined exception" },
265 { 0x00000001, "nca_s_fault_other" },
266 { 0x00000005, "nca_s_fault_access_denied" },
267 { 0x000006f7, "nca_s_fault_ndr" },
268 { 0x000006d8, "nca_s_fault_cant_perform" },
269 { 0x00000721, "nca_s_fault_sec_pkg_error" },
270 { 0x1c000001, "nca_s_fault_int_div_by_zero" },
271 { 0x1c000002, "nca_s_fault_addr_error" },
272 { 0x1c000003, "nca_s_fault_fp_div_zero" },
273 { 0x1c000004, "nca_s_fault_fp_underflow" },
274 { 0x1c000005, "nca_s_fault_fp_overflow" },
275 { 0x1c000006, "nca_s_fault_invalid_tag" },
276 { 0x1c000007, "nca_s_fault_invalid_bound" },
277 { 0x1c000008, "nca_rpc_version_mismatch" },
278 { 0x1c000009, "nca_unspec_reject" },
279 { 0x1c00000a, "nca_s_bad_actid" },
280 { 0x1c00000b, "nca_who_are_you_failed" },
281 { 0x1c00000c, "nca_manager_not_entered" },
282 { 0x1c00000d, "nca_s_fault_cancel" },
283 { 0x1c00000e, "nca_s_fault_ill_inst" },
284 { 0x1c00000f, "nca_s_fault_fp_error" },
285 { 0x1c000010, "nca_s_fault_int_overflow" },
286 { 0x1c000014, "nca_s_fault_pipe_empty" },
287 { 0x1c000015, "nca_s_fault_pipe_closed" },
288 { 0x1c000016, "nca_s_fault_pipe_order" },
289 { 0x1c000017, "nca_s_fault_pipe_discipline" },
290 { 0x1c000018, "nca_s_fault_pipe_comm_error" },
291 { 0x1c000019, "nca_s_fault_pipe_memory" },
292 { 0x1c00001a, "nca_s_fault_context_mismatch" },
293 { 0x1c00001b, "nca_s_fault_remote_no_memory" },
294 { 0x1c00001c, "nca_invalid_pres_context_id" },
295 { 0x1c00001d, "nca_unsupported_authn_level" },
296 { 0x1c00001f, "nca_invalid_checksum" },
297 { 0x1c000020, "nca_invalid_crc" },
298 { 0x1c000021, "ncs_s_fault_user_defined" },
299 { 0x1c000022, "nca_s_fault_tx_open_failed" },
300 { 0x1c000023, "nca_s_fault_codeset_conv_error" },
301 { 0x1c000024, "nca_s_fault_object_not_found" },
302 { 0x1c000025, "nca_s_fault_no_client_stub" },
303 { 0x1c010002, "nca_op_rng_error" },
304 { 0x1c010003, "nca_unk_if"},
305 { 0x1c010006, "nca_wrong_boot_time" },
306 { 0x1c010009, "nca_s_you_crashed" },
307 { 0x1c01000b, "nca_proto_error" },
308 { 0x1c010013, "nca_out_args_too_big" },
309 { 0x1c010014, "nca_server_too_busy" },
310 { 0x1c010017, "nca_unsupported_type" },
311 /* MS Windows specific values
312 * see: https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes--1700-3999-
313 * and: https://docs.microsoft.com/en-us/windows/win32/seccrypto/common-hresult-values
314 * and: https://web.archive.org/web/20150825015741/http://www.megos.ch/support/doserrors.txt
316 * XXX - we might need a way to dynamically add entries here, as higher layer protocols use these values too,
317 * at least MS protocols (like DCOM) do it that way ... */
318 { 0x80004001, "E_NOTIMPL" },
319 { 0x80004003, "E_POINTER" },
320 { 0x80004004, "E_ABORT" },
321 { 0x8000FFFF, "E_UNEXPECTED" },
322 { 0x80010105, "RPC_E_SERVERFAULT" },
323 { 0x80010108, "RPC_E_DISCONNECTED" },
324 { 0x80010113, "RPC_E_INVALID_IPID" },
325 { 0x8001011F, "RPC_E_TIMEOUT" },
326 { 0x80020003, "DISP_E_MEMBERNOTFOUND" },
327 { 0x80020006, "DISP_E_UNKNOWNNAME" },
328 { 0x8002000E, "DISP_E_BADPARAMCOUNT" },
329 { 0x8004CB00, "CBA_E_MALFORMED" },
330 { 0x8004CB01, "CBA_E_UNKNOWNOBJECT" },
331 { 0x8004CB05, "CBA_E_INVALIDID" },
332 { 0x8004CB09, "CBA_E_INVALIDCOOKIE" },
333 { 0x8004CB0B, "CBA_E_QOSTYPEUNSUPPORTED" },
334 { 0x8004CB0C, "CBA_E_QOSVALUEUNSUPPORTED" },
335 { 0x8004CB0F, "CBA_E_NOTAPPLICABLE" },
336 { 0x8004CB12, "CBA_E_LIMITVIOLATION" },
337 { 0x8004CB13, "CBA_E_QOSTYPENOTAPPLICABLE" },
338 { 0x8004CB18, "CBA_E_OUTOFPARTNERACCOS" },
339 { 0x8004CB1C, "CBA_E_FLAGUNSUPPORTED" },
340 { 0x8004CB23, "CBA_E_FRAMECOUNTUNSUPPORTED" },
341 { 0x8004CB25, "CBA_E_MODECHANGE" },
342 { 0x8007000E, "E_OUTOFMEMORY" },
343 { 0x80070057, "E_INVALIDARG" },
344 { 0x800706d1, "RPC_S_PROCNUM_OUT_OF_RANGE" },
345 { 0x80070776, "OR_INVALID_OXID" },
353 #define RTS_FLAG_NONE 0x0000
354 #define RTS_FLAG_PING 0x0001
355 #define RTS_FLAG_OTHER_CMD 0x0002
356 #define RTS_FLAG_RECYCLE_CHANNEL 0x0004
357 #define RTS_FLAG_IN_CHANNEL 0x0008
358 #define RTS_FLAG_OUT_CHANNEL 0x0010
359 #define RTS_FLAG_EOF 0x0020
360 #define RTS_FLAG_ECHO 0x0040
366 #define RTS_CMD_RECEIVEWINDOWSIZE 0x0
367 #define RTS_CMD_FLOWCONTROLACK 0x1
368 #define RTS_CMD_CONNECTIONTIMEOUT 0x2
369 #define RTS_CMD_COOKIE 0x3
370 #define RTS_CMD_CHANNELLIFETIME 0x4
371 #define RTS_CMD_CLIENTKEEPALIVE 0x5
372 #define RTS_CMD_VERSION 0x6
373 #define RTS_CMD_EMPTY 0x7
374 #define RTS_CMD_PADDING 0x8
375 #define RTS_CMD_NEGATIVEANCE 0x9
376 #define RTS_CMD_ANCE 0xA
377 #define RTS_CMD_CLIENTADDRESS 0xB
378 #define RTS_CMD_ASSOCIATIONGROUPID 0xC
379 #define RTS_CMD_DESTINATION 0xD
380 #define RTS_CMD_PINGTRAFFICSENTNOTIFY 0xE
382 static const value_string rts_command_vals
[] = {
383 { RTS_CMD_RECEIVEWINDOWSIZE
, "ReceiveWindowSize" },
384 { RTS_CMD_FLOWCONTROLACK
, "FlowControlAck" },
385 { RTS_CMD_CONNECTIONTIMEOUT
, "ConnectionTimeOut" },
386 { RTS_CMD_COOKIE
, "Cookie" },
387 { RTS_CMD_CHANNELLIFETIME
, "ChannelLifetime" },
388 { RTS_CMD_CLIENTKEEPALIVE
, "ClientKeepalive" },
389 { RTS_CMD_VERSION
, "Version" },
390 { RTS_CMD_EMPTY
, "Empty" },
391 { RTS_CMD_PADDING
, "Padding" },
392 { RTS_CMD_NEGATIVEANCE
, "NegativeANCE" },
393 { RTS_CMD_ANCE
, "ANCE" },
394 { RTS_CMD_CLIENTADDRESS
, "ClientAddress" },
395 { RTS_CMD_ASSOCIATIONGROUPID
, "AssociationGroupId" },
396 { RTS_CMD_DESTINATION
, "Destination" },
397 { RTS_CMD_PINGTRAFFICSENTNOTIFY
, "PingTrafficSentNotify" },
402 * RTS client address type
407 static const value_string rts_addresstype_vals
[] = {
408 { RTS_IPV4
, "IPV4" },
409 { RTS_IPV6
, "IPV6" },
414 * RTS Forward destination
417 static const value_string rts_forward_destination_vals
[] = {
419 { 0x1, "FDInProxy" },
421 { 0x3, "FDOutProxy" },
425 /* we need to keep track of what transport were used, ie what handle we came
426 * in through so we know what kind of pinfo->dce_smb_fid was passed to us.
428 /* Value of -1 is reserved for "not DCE packet" in packet_info.dcetransporttype. */
429 #define DCE_TRANSPORT_UNKNOWN 0
430 #define DCE_CN_TRANSPORT_SMBPIPE 1
433 static int proto_dcerpc
;
436 static int hf_dcerpc_request_in
;
437 static int hf_dcerpc_time
;
438 static int hf_dcerpc_response_in
;
439 static int hf_dcerpc_ver
;
440 static int hf_dcerpc_ver_minor
;
441 static int hf_dcerpc_packet_type
;
442 static int hf_dcerpc_cn_flags
;
443 static int hf_dcerpc_cn_flags_first_frag
;
444 static int hf_dcerpc_cn_flags_last_frag
;
445 static int hf_dcerpc_cn_flags_cancel_pending
;
446 static int hf_dcerpc_cn_flags_reserved
;
447 static int hf_dcerpc_cn_flags_mpx
;
448 static int hf_dcerpc_cn_flags_dne
;
449 static int hf_dcerpc_cn_flags_maybe
;
450 static int hf_dcerpc_cn_flags_object
;
451 static int hf_dcerpc_drep
;
452 int hf_dcerpc_drep_byteorder
;
453 int hf_dcerpc_ndr_padding
;
454 static int hf_dcerpc_drep_character
;
455 static int hf_dcerpc_drep_fp
;
456 static int hf_dcerpc_cn_frag_len
;
457 static int hf_dcerpc_cn_auth_len
;
458 static int hf_dcerpc_cn_call_id
;
459 static int hf_dcerpc_cn_max_xmit
;
460 static int hf_dcerpc_cn_max_recv
;
461 static int hf_dcerpc_cn_assoc_group
;
462 static int hf_dcerpc_cn_num_ctx_items
;
463 static int hf_dcerpc_cn_ctx_item
;
464 static int hf_dcerpc_cn_ctx_id
;
465 static int hf_dcerpc_cn_num_trans_items
;
466 static int hf_dcerpc_cn_bind_abstract_syntax
;
467 static int hf_dcerpc_cn_bind_if_id
;
468 static int hf_dcerpc_cn_bind_if_ver
;
469 static int hf_dcerpc_cn_bind_if_ver_minor
;
470 static int hf_dcerpc_cn_bind_trans_syntax
;
471 static int hf_dcerpc_cn_bind_trans_id
;
472 static int hf_dcerpc_cn_bind_trans_ver
;
473 static int hf_dcerpc_cn_bind_trans_btfn
;
474 static int hf_dcerpc_cn_bind_trans_btfn_01
;
475 static int hf_dcerpc_cn_bind_trans_btfn_02
;
476 static int hf_dcerpc_cn_bind_trans_btfn_04
;
477 static int hf_dcerpc_cn_bind_trans_btfn_08
;
478 static int hf_dcerpc_cn_alloc_hint
;
479 static int hf_dcerpc_cn_sec_addr_len
;
480 static int hf_dcerpc_cn_sec_addr
;
481 static int hf_dcerpc_cn_num_results
;
482 static int hf_dcerpc_cn_ack_result
;
483 static int hf_dcerpc_cn_ack_reason
;
484 static int hf_dcerpc_cn_ack_trans_id
;
485 static int hf_dcerpc_cn_ack_trans_ver
;
486 static int hf_dcerpc_cn_reject_reason
;
487 static int hf_dcerpc_cn_num_protocols
;
488 static int hf_dcerpc_cn_protocol_ver_major
;
489 static int hf_dcerpc_cn_protocol_ver_minor
;
490 static int hf_dcerpc_cn_cancel_count
;
491 static int hf_dcerpc_cn_fault_flags
;
492 static int hf_dcerpc_cn_fault_flags_extended_error_info
;
493 static int hf_dcerpc_cn_status
;
494 static int hf_dcerpc_cn_deseg_req
;
495 static int hf_dcerpc_cn_rts_flags
;
496 static int hf_dcerpc_cn_rts_flags_ping
;
497 static int hf_dcerpc_cn_rts_flags_other_cmd
;
498 static int hf_dcerpc_cn_rts_flags_recycle_channel
;
499 static int hf_dcerpc_cn_rts_flags_in_channel
;
500 static int hf_dcerpc_cn_rts_flags_out_channel
;
501 static int hf_dcerpc_cn_rts_flags_eof
;
502 static int hf_dcerpc_cn_rts_commands_nb
;
503 static int hf_dcerpc_cn_rts_command
;
504 static int hf_dcerpc_cn_rts_command_receivewindowsize
;
505 static int hf_dcerpc_cn_rts_command_fack_bytesreceived
;
506 static int hf_dcerpc_cn_rts_command_fack_availablewindow
;
507 static int hf_dcerpc_cn_rts_command_fack_channelcookie
;
508 static int hf_dcerpc_cn_rts_command_connectiontimeout
;
509 static int hf_dcerpc_cn_rts_command_cookie
;
510 static int hf_dcerpc_cn_rts_command_channellifetime
;
511 static int hf_dcerpc_cn_rts_command_clientkeepalive
;
512 static int hf_dcerpc_cn_rts_command_version
;
513 static int hf_dcerpc_cn_rts_command_conformancecount
;
514 static int hf_dcerpc_cn_rts_command_padding
;
515 static int hf_dcerpc_cn_rts_command_addrtype
;
516 static int hf_dcerpc_cn_rts_command_associationgroupid
;
517 static int hf_dcerpc_cn_rts_command_forwarddestination
;
518 static int hf_dcerpc_cn_rts_command_pingtrafficsentnotify
;
519 static int hf_dcerpc_auth_type
;
520 static int hf_dcerpc_auth_level
;
521 static int hf_dcerpc_auth_pad_len
;
522 static int hf_dcerpc_auth_rsrvd
;
523 static int hf_dcerpc_auth_ctx_id
;
524 static int hf_dcerpc_dg_flags1
;
525 static int hf_dcerpc_dg_flags1_rsrvd_01
;
526 static int hf_dcerpc_dg_flags1_last_frag
;
527 static int hf_dcerpc_dg_flags1_frag
;
528 static int hf_dcerpc_dg_flags1_nofack
;
529 static int hf_dcerpc_dg_flags1_maybe
;
530 static int hf_dcerpc_dg_flags1_idempotent
;
531 static int hf_dcerpc_dg_flags1_broadcast
;
532 static int hf_dcerpc_dg_flags1_rsrvd_80
;
533 static int hf_dcerpc_dg_flags2
;
534 static int hf_dcerpc_dg_flags2_rsrvd_01
;
535 static int hf_dcerpc_dg_flags2_cancel_pending
;
536 static int hf_dcerpc_dg_flags2_rsrvd_04
;
537 static int hf_dcerpc_dg_flags2_rsrvd_08
;
538 static int hf_dcerpc_dg_flags2_rsrvd_10
;
539 static int hf_dcerpc_dg_flags2_rsrvd_20
;
540 static int hf_dcerpc_dg_flags2_rsrvd_40
;
541 static int hf_dcerpc_dg_flags2_rsrvd_80
;
542 static int hf_dcerpc_dg_serial_hi
;
543 static int hf_dcerpc_obj_id
;
544 static int hf_dcerpc_dg_if_id
;
545 static int hf_dcerpc_dg_act_id
;
546 static int hf_dcerpc_dg_serial_lo
;
547 static int hf_dcerpc_dg_ahint
;
548 static int hf_dcerpc_dg_ihint
;
549 static int hf_dcerpc_dg_frag_len
;
550 static int hf_dcerpc_dg_frag_num
;
551 static int hf_dcerpc_dg_auth_proto
;
552 static int hf_dcerpc_opnum
;
553 static int hf_dcerpc_dg_seqnum
;
554 static int hf_dcerpc_dg_server_boot
;
555 static int hf_dcerpc_dg_if_ver
;
556 static int hf_dcerpc_krb5_av_prot_level
;
557 static int hf_dcerpc_krb5_av_key_vers_num
;
558 static int hf_dcerpc_krb5_av_key_auth_verifier
;
559 static int hf_dcerpc_dg_cancel_vers
;
560 static int hf_dcerpc_dg_cancel_id
;
561 static int hf_dcerpc_dg_server_accepting_cancels
;
562 static int hf_dcerpc_dg_fack_vers
;
563 static int hf_dcerpc_dg_fack_window_size
;
564 static int hf_dcerpc_dg_fack_max_tsdu
;
565 static int hf_dcerpc_dg_fack_max_frag_size
;
566 static int hf_dcerpc_dg_fack_serial_num
;
567 static int hf_dcerpc_dg_fack_selack_len
;
568 static int hf_dcerpc_dg_fack_selack
;
569 static int hf_dcerpc_dg_status
;
570 static int hf_dcerpc_array_max_count
;
571 static int hf_dcerpc_array_offset
;
572 static int hf_dcerpc_array_actual_count
;
573 static int hf_dcerpc_op
;
574 static int hf_dcerpc_referent_id32
;
575 static int hf_dcerpc_referent_id64
;
576 static int hf_dcerpc_null_pointer
;
577 static int hf_dcerpc_fragments
;
578 static int hf_dcerpc_fragment
;
579 static int hf_dcerpc_fragment_overlap
;
580 static int hf_dcerpc_fragment_overlap_conflict
;
581 static int hf_dcerpc_fragment_multiple_tails
;
582 static int hf_dcerpc_fragment_too_long_fragment
;
583 static int hf_dcerpc_fragment_error
;
584 static int hf_dcerpc_fragment_count
;
585 static int hf_dcerpc_reassembled_in
;
586 static int hf_dcerpc_reassembled_length
;
587 static int hf_dcerpc_unknown_if_id
;
588 static int hf_dcerpc_sec_vt_signature
;
589 static int hf_dcerpc_sec_vt_command
;
590 static int hf_dcerpc_sec_vt_command_cmd
;
591 static int hf_dcerpc_sec_vt_command_end
;
592 static int hf_dcerpc_sec_vt_command_must
;
593 static int hf_dcerpc_sec_vt_command_length
;
594 static int hf_dcerpc_sec_vt_bitmask
;
595 static int hf_dcerpc_sec_vt_bitmask_sign
;
596 static int hf_dcerpc_sec_vt_pcontext_uuid
;
597 static int hf_dcerpc_sec_vt_pcontext_ver
;
598 static int hf_dcerpc_sec_vt_preauth_salt
;
599 static int hf_dcerpc_sec_vt_preauth_sha512
;
601 static int * const sec_vt_command_fields
[] = {
602 &hf_dcerpc_sec_vt_command_cmd
,
603 &hf_dcerpc_sec_vt_command_end
,
604 &hf_dcerpc_sec_vt_command_must
,
607 static int hf_dcerpc_reserved
;
608 static int hf_dcerpc_unknown
;
609 static int hf_dcerpc_missalign
;
611 /* Generated from convert_proto_tree_add_text.pl */
612 static int hf_dcerpc_duplicate_ptr
;
613 static int hf_dcerpc_encrypted_stub_data
;
614 static int hf_dcerpc_decrypted_stub_data
;
615 static int hf_dcerpc_payload_stub_data
;
616 static int hf_dcerpc_stub_data_with_sec_vt
;
617 static int hf_dcerpc_stub_data
;
618 static int hf_dcerpc_auth_padding
;
619 static int hf_dcerpc_auth_info
;
620 static int hf_dcerpc_auth_credentials
;
621 static int hf_dcerpc_fault_stub_data
;
622 static int hf_dcerpc_fragment_data
;
623 static int hf_dcerpc_cmd_client_ipv4
;
624 static int hf_dcerpc_cmd_client_ipv6
;
625 static int hf_dcerpc_authentication_verifier
;
627 static int * const dcerpc_cn_bind_trans_btfn_fields
[] = {
628 &hf_dcerpc_cn_bind_trans_btfn_01
,
629 &hf_dcerpc_cn_bind_trans_btfn_02
,
630 &hf_dcerpc_cn_bind_trans_btfn_04
,
631 &hf_dcerpc_cn_bind_trans_btfn_08
,
635 static int * const sec_vt_bitmask_fields
[] = {
636 &hf_dcerpc_sec_vt_bitmask_sign
,
640 static int * const dcerpc_cn_fault_flags_fields
[] = {
641 &hf_dcerpc_cn_fault_flags_extended_error_info
,
645 static const value_string sec_vt_command_cmd_vals
[] = {
653 static int ett_dcerpc
;
654 static int ett_dcerpc_cn_flags
;
655 static int ett_dcerpc_cn_ctx
;
656 static int ett_dcerpc_cn_iface
;
657 static int ett_dcerpc_cn_trans_syntax
;
658 static int ett_dcerpc_cn_trans_btfn
;
659 static int ett_dcerpc_cn_bind_trans_btfn
;
660 static int ett_dcerpc_cn_rts_flags
;
661 static int ett_dcerpc_cn_rts_command
;
662 static int ett_dcerpc_cn_rts_pdu
;
663 static int ett_dcerpc_drep
;
664 static int ett_dcerpc_dg_flags1
;
665 static int ett_dcerpc_dg_flags2
;
666 static int ett_dcerpc_pointer_data
;
667 static int ett_dcerpc_string
;
668 static int ett_dcerpc_fragments
;
669 static int ett_dcerpc_fragment
;
670 static int ett_dcerpc_krb5_auth_verf
;
671 static int ett_dcerpc_auth_info
;
672 static int ett_dcerpc_verification_trailer
;
673 static int ett_dcerpc_sec_vt_command
;
674 static int ett_dcerpc_sec_vt_bitmask
;
675 static int ett_dcerpc_sec_vt_pcontext
;
676 static int ett_dcerpc_sec_vt_header
;
677 static int ett_dcerpc_sec_vt_preauth
;
678 static int ett_dcerpc_complete_stub_data
;
679 static int ett_dcerpc_fault_flags
;
680 static int ett_dcerpc_fault_stub_data
;
682 static expert_field ei_dcerpc_fragment_multiple
;
683 static expert_field ei_dcerpc_cn_status
;
684 static expert_field ei_dcerpc_fragment_reassembled
;
685 static expert_field ei_dcerpc_fragment
;
686 static expert_field ei_dcerpc_no_request_found
;
687 /* static expert_field ei_dcerpc_context_change; */
688 static expert_field ei_dcerpc_cn_ctx_id_no_bind
;
689 static expert_field ei_dcerpc_bind_not_acknowledged
;
690 static expert_field ei_dcerpc_verifier_unavailable
;
691 static expert_field ei_dcerpc_invalid_pdu_authentication_attempt
;
692 /* Generated from convert_proto_tree_add_text.pl */
693 static expert_field ei_dcerpc_long_frame
;
694 static expert_field ei_dcerpc_cn_rts_command
;
695 static expert_field ei_dcerpc_not_implemented
;
697 static const uint8_t TRAILER_SIGNATURE
[] = {0x8a, 0xe3, 0x13, 0x71, 0x02, 0xf4, 0x36, 0x71};
698 static tvbuff_t
*tvb_trailer_signature
;
700 static GSList
*decode_dcerpc_bindings
;
702 static wmem_map_t
*dcerpc_connections
;
704 typedef struct _dcerpc_connection
{
705 conversation_t
*conv
;
706 uint64_t transport_salt
;
707 uint32_t first_frame
;
708 bool hdr_signing_negotiated
;
712 * To keep track of ctx_id mappings.
714 * Every time we see a bind call we update this table.
715 * Note that we always specify a SMB FID. For non-SMB transports this
718 static wmem_map_t
*dcerpc_binds
;
720 typedef struct _dcerpc_bind_key
{
721 conversation_t
*conv
;
723 uint64_t transport_salt
;
726 typedef struct _dcerpc_bind_value
{
732 static wmem_map_t
*dcerpc_auths
;
734 typedef struct _dcerpc_auth_context
{
735 conversation_t
*conv
;
736 uint64_t transport_salt
;
739 uint32_t auth_context_id
;
740 uint32_t first_frame
;
742 } dcerpc_auth_context
;
744 /* Extra data for DCERPC handling and tracking of context ids */
745 typedef struct _dcerpc_decode_as_data
{
746 uint16_t dcectxid
; /**< Context ID (DCERPC-specific) */
747 int dcetransporttype
; /**< Transport type
748 * Value -1 means "not a DCERPC packet"
750 uint64_t dcetransportsalt
; /**< fid: if transporttype==DCE_CN_TRANSPORT_SMBPIPE */
751 } dcerpc_decode_as_data
;
753 static dcerpc_decode_as_data
*
754 dcerpc_get_decode_data(packet_info
* pinfo
)
756 dcerpc_decode_as_data
* data
= (dcerpc_decode_as_data
*)p_get_proto_data(pinfo
->pool
, pinfo
, proto_dcerpc
, 0);
759 data
= wmem_new0(pinfo
->pool
, dcerpc_decode_as_data
);
760 data
->dcetransporttype
= -1;
761 p_add_proto_data(pinfo
->pool
, pinfo
, proto_dcerpc
, 0, data
);
768 * Registers a conversation/UUID binding association, so that
769 * we can invoke the proper sub-dissector for a given DCERPC
772 * @param binding all values needed to create and bind a new conversation
774 * @return Pointer to newly-added UUID/conversation binding.
776 static struct _dcerpc_bind_value
*
777 dcerpc_add_conv_to_bind_table(decode_dcerpc_bind_values_t
*binding
)
779 dcerpc_bind_value
*bind_value
;
780 dcerpc_bind_key
*key
;
781 conversation_t
*conv
;
783 conv
= find_conversation(
787 conversation_pt_to_conversation_type(binding
->ptype
),
793 conv
= conversation_new(
797 conversation_pt_to_conversation_type(binding
->ptype
),
803 bind_value
= wmem_new(wmem_file_scope(), dcerpc_bind_value
);
804 bind_value
->uuid
= binding
->uuid
;
805 bind_value
->ver
= binding
->ver
;
806 /* For now, assume all DCE/RPC we pick from "decode as" is using
807 standard ndr and not ndr64.
808 We should make this selectable from the dialog in the future
810 bind_value
->transport
= uuid_data_repr_proto
;
812 key
= wmem_new(wmem_file_scope(), dcerpc_bind_key
);
814 key
->ctx_id
= binding
->ctx_id
;
815 key
->transport_salt
= binding
->transport_salt
;
817 /* add this entry to the bind table */
818 wmem_map_insert(dcerpc_binds
, key
, bind_value
);
824 /* inject one of our bindings into the dcerpc binding table */
826 decode_dcerpc_inject_binding(void *data
, void *user_data _U_
)
828 dcerpc_add_conv_to_bind_table((decode_dcerpc_bind_values_t
*) data
);
831 /* inject all of our bindings into the dcerpc binding table */
833 decode_dcerpc_inject_bindings(void) {
834 g_slist_foreach(decode_dcerpc_bindings
, decode_dcerpc_inject_binding
, NULL
/* user_data */);
839 decode_dcerpc_binding_free(void *binding_in
)
841 decode_dcerpc_bind_values_t
*binding
= (decode_dcerpc_bind_values_t
*)binding_in
;
843 free_address(&binding
->addr_a
);
844 free_address(&binding
->addr_b
);
846 g_string_free(binding
->ifname
, true);
851 dcerpc_decode_as_free(void *value
)
853 decode_dcerpc_bind_values_t
*binding
= (decode_dcerpc_bind_values_t
*)value
;
855 decode_dcerpc_binding_free(binding
);
858 /* removes all bindings */
860 decode_dcerpc_reset_all(void)
862 decode_dcerpc_bind_values_t
*binding
;
864 while (decode_dcerpc_bindings
) {
865 binding
= (decode_dcerpc_bind_values_t
*)decode_dcerpc_bindings
->data
;
867 decode_dcerpc_bindings
= g_slist_remove(
868 decode_dcerpc_bindings
,
869 decode_dcerpc_bindings
->data
);
870 decode_dcerpc_binding_free(binding
);
876 decode_dcerpc_add_show_list(decode_add_show_list_func func
, void *user_data
)
878 g_slist_foreach(decode_dcerpc_bindings
, func
, user_data
);
882 dcerpc_prompt(packet_info
*pinfo
, char* result
)
884 GString
*str
= g_string_new("Replace binding between:\r\n"),
885 *address_str
= g_string_new("");
886 dcerpc_decode_as_data
* decode_data
= dcerpc_get_decode_data(pinfo
);
888 switch (pinfo
->ptype
) {
890 g_string_append(address_str
, "Address: ToBeDone TCP port");
893 g_string_append(address_str
, "Address: ToBeDone UDP port");
896 g_string_append(address_str
, "Address: ToBeDone Unknown port type");
899 g_string_append_printf(str
, "%s: %u\r\n", address_str
->str
, pinfo
->srcport
);
900 g_string_append(str
, "&\r\n");
901 g_string_append_printf(str
, "%s: %u\r\n", address_str
->str
, pinfo
->destport
);
902 g_string_append_printf(str
, "&\r\nContext ID: %u\r\n", decode_data
->dcectxid
);
903 g_string_append_printf(str
, "&\r\nSMB FID: %"PRIu64
"\r\n",
904 dcerpc_get_transport_salt(pinfo
));
905 g_string_append(str
, "with:\r\n");
907 (void) g_strlcpy(result
, str
->str
, MAX_DECODE_AS_PROMPT_LEN
);
908 g_string_free(str
, true);
909 g_string_free(address_str
, true);
913 dcerpc_value(packet_info
*pinfo
)
915 decode_dcerpc_bind_values_t
*binding
;
916 dcerpc_decode_as_data
* decode_data
= dcerpc_get_decode_data(pinfo
);
919 binding
= g_new(decode_dcerpc_bind_values_t
,1);
920 copy_address(&binding
->addr_a
, &pinfo
->src
);
921 copy_address(&binding
->addr_b
, &pinfo
->dst
);
922 binding
->ptype
= pinfo
->ptype
;
923 binding
->port_a
= pinfo
->srcport
;
924 binding
->port_b
= pinfo
->destport
;
925 binding
->ctx_id
= decode_data
->dcectxid
;
926 binding
->transport_salt
= dcerpc_get_transport_salt(pinfo
);
927 binding
->ifname
= NULL
;
928 /*binding->uuid = NULL;*/
934 struct dcerpc_decode_as_populate
936 decode_as_add_to_list_func add_to_list
;
941 decode_dcerpc_add_to_list(void *key
, void *value
, void *user_data
)
943 struct dcerpc_decode_as_populate
* populate
= (struct dcerpc_decode_as_populate
*)user_data
;
945 /*guid_key *k = key;*/
946 dcerpc_uuid_value
*v
= (dcerpc_uuid_value
*)value
;
948 if (strcmp(v
->name
, "(none)"))
949 populate
->add_to_list("DCE-RPC", v
->name
, key
, populate
->ui_element
);
953 dcerpc_populate_list(const char *table_name _U_
, decode_as_add_to_list_func add_to_list
, void *ui_element
)
955 struct dcerpc_decode_as_populate populate
;
957 populate
.add_to_list
= add_to_list
;
958 populate
.ui_element
= ui_element
;
960 g_hash_table_foreach(dcerpc_uuids
, decode_dcerpc_add_to_list
, &populate
);
963 /* compare two bindings (except the interface related things, e.g. uuid) */
965 decode_dcerpc_binding_cmp(const void *a
, const void *b
)
967 const decode_dcerpc_bind_values_t
*binding_a
= (const decode_dcerpc_bind_values_t
*)a
;
968 const decode_dcerpc_bind_values_t
*binding_b
= (const decode_dcerpc_bind_values_t
*)b
;
971 /* don't compare uuid and ver! */
973 addresses_equal(&binding_a
->addr_a
, &binding_b
->addr_a
) &&
974 addresses_equal(&binding_a
->addr_b
, &binding_b
->addr_b
) &&
975 binding_a
->ptype
== binding_b
->ptype
&&
976 binding_a
->port_a
== binding_b
->port_a
&&
977 binding_a
->port_b
== binding_b
->port_b
&&
978 binding_a
->ctx_id
== binding_b
->ctx_id
&&
979 binding_a
->transport_salt
== binding_b
->transport_salt
)
989 /* remove a binding (looking the same way as the given one) */
991 decode_dcerpc_binding_reset(const char *name _U_
, const void *pattern
)
993 const decode_dcerpc_bind_values_t
*binding
= (const decode_dcerpc_bind_values_t
*)pattern
;
995 decode_dcerpc_bind_values_t
*old_binding
;
997 /* find the old binding (if it exists) */
998 le
= g_slist_find_custom(decode_dcerpc_bindings
,
1000 decode_dcerpc_binding_cmp
);
1004 old_binding
= (decode_dcerpc_bind_values_t
*)le
->data
;
1006 decode_dcerpc_bindings
= g_slist_remove(decode_dcerpc_bindings
, le
->data
);
1008 free_address(&old_binding
->addr_a
);
1009 free_address(&old_binding
->addr_b
);
1010 g_string_free(old_binding
->ifname
, true);
1011 g_free(old_binding
);
1016 dcerpc_decode_as_change(const char *name
, const void *pattern
, const void *handle
, const char* list_name
)
1018 const decode_dcerpc_bind_values_t
*binding
= (const decode_dcerpc_bind_values_t
*)pattern
;
1019 decode_dcerpc_bind_values_t
*stored_binding
;
1020 const guid_key
*key
= (const guid_key
*)handle
;
1022 /* remove a probably existing old binding */
1023 decode_dcerpc_binding_reset(name
, binding
);
1026 * Clone the new binding, update the changing parts, and append it
1029 stored_binding
= g_new(decode_dcerpc_bind_values_t
,1);
1030 *stored_binding
= *binding
;
1031 copy_address(&stored_binding
->addr_a
, &binding
->addr_a
);
1032 copy_address(&stored_binding
->addr_b
, &binding
->addr_b
);
1033 stored_binding
->ifname
= g_string_new(list_name
);
1034 stored_binding
->uuid
= key
->guid
;
1035 stored_binding
->ver
= key
->ver
;
1037 decode_dcerpc_bindings
= g_slist_append (decode_dcerpc_bindings
, stored_binding
);
1042 static const fragment_items dcerpc_frag_items
= {
1043 &ett_dcerpc_fragments
,
1044 &ett_dcerpc_fragment
,
1046 &hf_dcerpc_fragments
,
1047 &hf_dcerpc_fragment
,
1048 &hf_dcerpc_fragment_overlap
,
1049 &hf_dcerpc_fragment_overlap_conflict
,
1050 &hf_dcerpc_fragment_multiple_tails
,
1051 &hf_dcerpc_fragment_too_long_fragment
,
1052 &hf_dcerpc_fragment_error
,
1053 &hf_dcerpc_fragment_count
,
1055 &hf_dcerpc_reassembled_length
,
1056 /* Reassembled data field */
1061 /* try to desegment big DCE/RPC packets over TCP? */
1062 static bool dcerpc_cn_desegment
= true;
1064 /* reassemble DCE/RPC fragments */
1065 /* reassembly of cl dcerpc fragments will not work for the case where ONE frame
1066 might contain multiple dcerpc fragments for different PDUs.
1067 this case would be so unusual/weird so if you got captures like that:
1070 reassembly of co dcerpc fragments will not work for the case where TCP/SMB frames
1071 are coming in out of sequence, but that will hurt in a lot of other places as well.
1073 static bool dcerpc_reassemble
= true;
1074 static reassembly_table dcerpc_co_reassembly_table
;
1075 static reassembly_table dcerpc_cl_reassembly_table
;
1077 typedef struct _dcerpc_fragment_key
{
1082 } dcerpc_fragment_key
;
1085 dcerpc_fragment_hash(const void *k
)
1087 const dcerpc_fragment_key
* key
= (const dcerpc_fragment_key
*) k
;
1092 hash_val
+= key
->id
;
1093 hash_val
+= key
->act_id
.data1
;
1094 hash_val
+= key
->act_id
.data2
<< 16;
1095 hash_val
+= key
->act_id
.data3
;
1101 dcerpc_fragment_equal(const void *k1
, const void *k2
)
1103 const dcerpc_fragment_key
* key1
= (const dcerpc_fragment_key
*) k1
;
1104 const dcerpc_fragment_key
* key2
= (const dcerpc_fragment_key
*) k2
;
1106 /*key.id is the first item to compare since item is most
1107 likely to differ between sessions, thus shortcircuiting
1108 the comparison of addresses.
1110 return (((key1
->id
== key2
->id
)
1111 && (addresses_equal(&key1
->src
, &key2
->src
))
1112 && (addresses_equal(&key1
->dst
, &key2
->dst
))
1113 && (memcmp (&key1
->act_id
, &key2
->act_id
, sizeof (e_guid_t
)) == 0))
1117 /* allocate a persistent dcerpc fragment key to insert in the hash */
1119 dcerpc_fragment_temporary_key(const packet_info
*pinfo
, const uint32_t id
,
1122 dcerpc_fragment_key
*key
= g_slice_new(dcerpc_fragment_key
);
1123 const e_dce_dg_common_hdr_t
*hdr
= (const e_dce_dg_common_hdr_t
*)data
;
1125 copy_address_shallow(&key
->src
, &pinfo
->src
);
1126 copy_address_shallow(&key
->dst
, &pinfo
->dst
);
1128 key
->act_id
= hdr
->act_id
;
1133 /* allocate a persistent dcerpc fragment key to insert in the hash */
1135 dcerpc_fragment_persistent_key(const packet_info
*pinfo
, const uint32_t id
,
1138 dcerpc_fragment_key
*key
= g_slice_new(dcerpc_fragment_key
);
1139 const e_dce_dg_common_hdr_t
*hdr
= (const e_dce_dg_common_hdr_t
*)data
;
1141 copy_address(&key
->src
, &pinfo
->src
);
1142 copy_address(&key
->dst
, &pinfo
->dst
);
1144 key
->act_id
= hdr
->act_id
;
1150 dcerpc_fragment_free_temporary_key(void *ptr
)
1152 dcerpc_fragment_key
*key
= (dcerpc_fragment_key
*)ptr
;
1154 g_slice_free(dcerpc_fragment_key
, key
);
1158 dcerpc_fragment_free_persistent_key(void *ptr
)
1160 dcerpc_fragment_key
*key
= (dcerpc_fragment_key
*)ptr
;
1164 * Free up the copies of the addresses from the old key.
1166 free_address(&key
->src
);
1167 free_address(&key
->dst
);
1169 g_slice_free(dcerpc_fragment_key
, key
);
1173 static const reassembly_table_functions dcerpc_cl_reassembly_table_functions
= {
1174 dcerpc_fragment_hash
,
1175 dcerpc_fragment_equal
,
1176 dcerpc_fragment_temporary_key
,
1177 dcerpc_fragment_persistent_key
,
1178 dcerpc_fragment_free_temporary_key
,
1179 dcerpc_fragment_free_persistent_key
1183 * Authentication subdissectors. Used to dissect authentication blobs in
1184 * DCERPC binds, requests and responses.
1187 typedef struct _dcerpc_auth_subdissector
{
1190 dcerpc_auth_subdissector_fns auth_fns
;
1191 } dcerpc_auth_subdissector
;
1193 static GSList
*dcerpc_auth_subdissector_list
;
1195 static dcerpc_auth_subdissector_fns
*get_auth_subdissector_fns(
1196 uint8_t auth_level
, uint8_t auth_type
)
1201 for (i
= 0; (data
= g_slist_nth_data(dcerpc_auth_subdissector_list
, i
)); i
++) {
1202 dcerpc_auth_subdissector
*asd
= (dcerpc_auth_subdissector
*)data
;
1204 if ((asd
->auth_level
== auth_level
) &&
1205 (asd
->auth_type
== auth_type
))
1206 return &asd
->auth_fns
;
1212 void register_dcerpc_auth_subdissector(uint8_t auth_level
, uint8_t auth_type
,
1213 dcerpc_auth_subdissector_fns
*fns
)
1215 dcerpc_auth_subdissector
*d
;
1217 if (get_auth_subdissector_fns(auth_level
, auth_type
))
1220 d
= g_new(dcerpc_auth_subdissector
, 1);
1222 d
->auth_level
= auth_level
;
1223 d
->auth_type
= auth_type
;
1226 dcerpc_auth_subdissector_list
= g_slist_append(dcerpc_auth_subdissector_list
, d
);
1229 /* Hand off verifier data to a registered dissector */
1231 static void dissect_auth_verf(packet_info
*pinfo
,
1232 e_dce_cn_common_hdr_t
*hdr
,
1233 dcerpc_auth_info
*auth_info
)
1235 dcerpc_dissect_fnct_t
*fn
= NULL
;
1236 /* XXX - "stub" a fake DCERPC INFO STRUCTURE
1237 If a dcerpc_info is really needed, update
1238 the call stacks to include it
1240 FAKE_DCERPC_INFO_STRUCTURE
1242 if (auth_info
== NULL
) {
1246 if (auth_info
->auth_fns
== NULL
) {
1249 di
.ptype
= hdr
->ptype
;
1250 di
.auth_info
= auth_info
;
1252 switch (hdr
->ptype
) {
1255 fn
= auth_info
->auth_fns
->bind_fn
;
1259 fn
= auth_info
->auth_fns
->bind_ack_fn
;
1262 fn
= auth_info
->auth_fns
->auth3_fn
;
1267 fn
= auth_info
->auth_fns
->req_verf_fn
;
1271 fn
= auth_info
->auth_fns
->resp_verf_fn
;
1275 /* Don't know how to handle authentication data in this
1277 proto_tree_add_expert_format(auth_info
->auth_tree
, pinfo
,
1278 &ei_dcerpc_invalid_pdu_authentication_attempt
,
1279 auth_info
->auth_tvb
, 0, 0,
1280 "Don't know how to dissect authentication data for %s pdu type",
1281 val_to_str(hdr
->ptype
, pckt_vals
, "Unknown (%u)"));
1286 fn(auth_info
->auth_tvb
, 0, pinfo
, auth_info
->auth_tree
, &di
, hdr
->drep
);
1288 proto_tree_add_expert_format(auth_info
->auth_tree
, pinfo
,
1289 &ei_dcerpc_verifier_unavailable
,
1290 auth_info
->auth_tvb
, 0, hdr
->auth_len
,
1291 "%s Verifier unavailable",
1292 val_to_str(auth_info
->auth_type
,
1293 authn_protocol_vals
,
1298 proto_tree_add_dcerpc_drep(proto_tree
*tree
, tvbuff_t
*tvb
, int offset
, uint8_t drep
[], int drep_len
)
1300 const uint8_t byteorder
= drep
[0] >> 4;
1301 const uint8_t character
= drep
[0] & 0x0f;
1302 const uint8_t fp
= drep
[1];
1303 proto_item
*ti
= proto_tree_add_bytes(tree
, hf_dcerpc_drep
, tvb
, offset
, drep_len
, drep
);
1304 proto_tree
*tr
= proto_item_add_subtree(ti
, ett_dcerpc_drep
);
1306 proto_tree_add_uint(tr
, hf_dcerpc_drep_byteorder
, tvb
, offset
, 1, byteorder
);
1307 proto_tree_add_uint(tr
, hf_dcerpc_drep_character
, tvb
, offset
, 1, character
);
1308 proto_tree_add_uint(tr
, hf_dcerpc_drep_fp
, tvb
, offset
+1, 1, fp
);
1310 proto_item_append_text(ti
, " (Order: %s, Char: %s, Float: %s)",
1311 val_to_str(byteorder
, drep_byteorder_vals
, "Unknown (%u)"),
1312 val_to_str(character
, drep_character_vals
, "Unknown (%u)"),
1313 val_to_str(fp
, drep_fp_vals
, "Unknown (%u)"));
1317 /* Hand off payload data to a registered dissector */
1319 static tvbuff_t
*decode_encrypted_data(tvbuff_t
*header_tvb
,
1320 tvbuff_t
*payload_tvb
,
1321 tvbuff_t
*trailer_tvb
,
1323 e_dce_cn_common_hdr_t
*hdr
,
1324 dcerpc_auth_info
*auth_info
)
1326 dcerpc_decode_data_fnct_t
*fn
= NULL
;
1328 if (auth_info
== NULL
)
1331 if (auth_info
->auth_fns
== NULL
)
1334 switch (hdr
->ptype
) {
1336 fn
= auth_info
->auth_fns
->req_data_fn
;
1340 fn
= auth_info
->auth_fns
->resp_data_fn
;
1345 return fn(header_tvb
, payload_tvb
, trailer_tvb
, auth_info
->auth_tvb
, pinfo
, auth_info
);
1350 typedef struct _dcerpc_dissector_data
1352 dcerpc_uuid_value
*sub_proto
;
1355 dcerpc_auth_info
*auth_info
;
1357 proto_tree
*dcerpc_tree
;
1358 } dcerpc_dissector_data_t
;
1364 static dissector_table_t uuid_dissector_table
;
1366 /* the registered subdissectors */
1367 GHashTable
*dcerpc_uuids
;
1370 dcerpc_uuid_equal(const void *k1
, const void *k2
)
1372 const guid_key
*key1
= (const guid_key
*)k1
;
1373 const guid_key
*key2
= (const guid_key
*)k2
;
1374 return ((memcmp(&key1
->guid
, &key2
->guid
, sizeof (e_guid_t
)) == 0)
1375 && (key1
->ver
== key2
->ver
));
1379 dcerpc_uuid_hash(const void *k
)
1381 const guid_key
*key
= (const guid_key
*)k
;
1382 /* This isn't perfect, but the Data1 part of these is almost always
1384 return key
->guid
.data1
;
1389 dissect_verification_trailer(packet_info
*pinfo
, tvbuff_t
*tvb
, int stub_offset
,
1390 proto_tree
*parent_tree
, int *signature_offset
);
1393 show_stub_data(packet_info
*pinfo
, tvbuff_t
*tvb
, int offset
, proto_tree
*dcerpc_tree
,
1394 dcerpc_auth_info
*auth_info
, bool is_encrypted
)
1396 int length
, plain_length
, auth_pad_len
;
1397 unsigned auth_pad_offset
;
1400 * We don't show stub data unless we have some in the tvbuff;
1401 * however, in the protocol tree, we show, as the number of
1402 * bytes, the reported number of bytes, not the number of bytes
1403 * that happen to be in the tvbuff.
1405 if (tvb_reported_length_remaining(tvb
, offset
) > 0) {
1406 auth_pad_len
= auth_info
?auth_info
->auth_pad_len
:0;
1407 length
= tvb_reported_length_remaining(tvb
, offset
);
1409 /* if auth_pad_len is larger than length then we ignore auth_pad_len totally */
1410 plain_length
= length
- auth_pad_len
;
1411 if (plain_length
< 1) {
1412 plain_length
= length
;
1415 auth_pad_offset
= offset
+ plain_length
;
1417 if ((auth_info
!= NULL
) &&
1418 (auth_info
->auth_level
== DCE_C_AUTHN_LEVEL_PKT_PRIVACY
)) {
1420 proto_tree_add_item(dcerpc_tree
, hf_dcerpc_encrypted_stub_data
, tvb
, offset
, length
, ENC_NA
);
1421 /* is the padding is still inside the encrypted blob, don't display it explicit */
1424 proto_tree_add_item(dcerpc_tree
, hf_dcerpc_decrypted_stub_data
, tvb
, offset
, plain_length
, ENC_NA
);
1425 dissect_verification_trailer(pinfo
, tvb
, offset
, dcerpc_tree
, NULL
);
1428 proto_tree_add_item(dcerpc_tree
, hf_dcerpc_stub_data
, tvb
, offset
, plain_length
, ENC_NA
);
1429 dissect_verification_trailer(pinfo
, tvb
, offset
, dcerpc_tree
, NULL
);
1431 /* If there is auth padding at the end of the stub, display it */
1432 if (auth_pad_len
!= 0) {
1433 proto_tree_add_item(dcerpc_tree
, hf_dcerpc_auth_padding
, tvb
, auth_pad_offset
, auth_pad_len
, ENC_NA
);
1439 dissect_dcerpc_guid(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
1441 dcerpc_dissector_data_t
* dissector_data
= (dcerpc_dissector_data_t
*)data
;
1442 const char *name
= NULL
;
1443 const dcerpc_sub_dissector
*proc
;
1444 int (*volatile sub_dissect
)(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
, proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
) = NULL
;
1445 proto_item
*pi
, *sub_item
;
1446 proto_tree
*sub_tree
;
1447 volatile unsigned length
;
1448 unsigned reported_length
;
1449 volatile int offset
= 0;
1450 tvbuff_t
*volatile stub_tvb
;
1451 tvbuff_t
*volatile payload_tvb
= NULL
;
1452 volatile unsigned auth_pad_len
;
1453 volatile int auth_pad_offset
;
1454 const char *volatile saved_proto
;
1456 for (proc
= dissector_data
->sub_proto
->procs
; proc
->name
; proc
++) {
1457 if (proc
->num
== dissector_data
->info
->call_data
->opnum
) {
1463 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, dissector_data
->sub_proto
->name
);
1466 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "Unknown operation %u %s",
1467 dissector_data
->info
->call_data
->opnum
,
1468 (dissector_data
->info
->ptype
== PDU_REQ
) ? "request" : "response");
1470 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "%s %s",
1471 name
, (dissector_data
->info
->ptype
== PDU_REQ
) ? "request" : "response");
1473 sub_dissect
= (dissector_data
->info
->ptype
== PDU_REQ
) ?
1474 proc
->dissect_rqst
: proc
->dissect_resp
;
1476 sub_item
= proto_tree_add_item(tree
, dissector_data
->sub_proto
->proto_id
,
1477 tvb
,//(decrypted_tvb != NULL)?decrypted_tvb:tvb,
1479 sub_tree
= proto_item_add_subtree(sub_item
, dissector_data
->sub_proto
->ett
);
1481 proto_item_append_text(sub_item
, ", unknown operation %u",
1482 dissector_data
->info
->call_data
->opnum
);
1484 proto_item_append_text(sub_item
, ", %s", name
);
1488 * Put the operation number into the tree along with
1489 * the operation's name.
1491 if (dissector_data
->sub_proto
->opnum_hf
!= -1)
1492 proto_tree_add_uint_format(sub_tree
, dissector_data
->sub_proto
->opnum_hf
,
1493 tvb
, 0, 0, dissector_data
->info
->call_data
->opnum
,
1494 "Operation: %s (%u)",
1495 name
? name
: "Unknown operation",
1496 dissector_data
->info
->call_data
->opnum
);
1498 proto_tree_add_uint_format_value(sub_tree
, hf_dcerpc_op
, tvb
,
1499 0, 0, dissector_data
->info
->call_data
->opnum
,
1501 name
? name
: "Unknown operation",
1502 dissector_data
->info
->call_data
->opnum
);
1504 if ((dissector_data
->info
->ptype
== PDU_REQ
) && (dissector_data
->info
->call_data
->rep_frame
!= 0)) {
1505 pi
= proto_tree_add_uint(sub_tree
, hf_dcerpc_response_in
,
1506 tvb
, 0, 0, dissector_data
->info
->call_data
->rep_frame
);
1507 proto_item_set_generated(pi
);
1509 if ((dissector_data
->info
->ptype
== PDU_RESP
) && (dissector_data
->info
->call_data
->req_frame
!= 0)) {
1510 pi
= proto_tree_add_uint(sub_tree
, hf_dcerpc_request_in
,
1511 tvb
, 0, 0, dissector_data
->info
->call_data
->req_frame
);
1512 proto_item_set_generated(pi
);
1516 if (!dissector_data
->decrypted
|| (sub_dissect
== NULL
))
1518 show_stub_data(pinfo
, tvb
, 0, sub_tree
, dissector_data
->auth_info
, !dissector_data
->decrypted
);
1519 return tvb_captured_length(tvb
);
1522 /* Either there was no encryption or we successfully decrypted
1523 the encrypted payload. */
1525 /* We have a subdissector - call it. */
1526 saved_proto
= pinfo
->current_proto
;
1527 pinfo
->current_proto
= dissector_data
->sub_proto
->name
;
1529 init_ndr_pointer_list(dissector_data
->info
);
1531 length
= tvb_captured_length(tvb
);
1532 reported_length
= tvb_reported_length(tvb
);
1535 * Remove the authentication padding from the stub data.
1537 if ((dissector_data
->auth_info
!= NULL
) && (dissector_data
->auth_info
->auth_pad_len
!= 0)) {
1538 if (reported_length
>= dissector_data
->auth_info
->auth_pad_len
) {
1540 * OK, the padding length isn't so big that it
1541 * exceeds the stub length. Trim the reported
1542 * length of the tvbuff.
1544 reported_length
-= dissector_data
->auth_info
->auth_pad_len
;
1547 * If that exceeds the actual amount of data in
1548 * the tvbuff (which means we have at least one
1549 * byte of authentication padding in the tvbuff),
1550 * trim the actual amount.
1552 if (length
> reported_length
)
1553 length
= reported_length
;
1555 stub_tvb
= tvb_new_subset_length_caplen(tvb
, 0, length
, reported_length
);
1556 auth_pad_len
= dissector_data
->auth_info
->auth_pad_len
;
1557 auth_pad_offset
= reported_length
;
1560 * The padding length exceeds the stub length.
1561 * Don't bother dissecting the stub, trim the padding
1562 * length to what's in the stub data, and show the
1563 * entire stub as authentication padding.
1566 auth_pad_len
= reported_length
;
1567 auth_pad_offset
= 0;
1572 * No authentication padding.
1576 auth_pad_offset
= 0;
1580 proto_item_set_len(sub_item
, length
);
1583 if (stub_tvb
!= NULL
) {
1585 * Catch all exceptions other than BoundsError, so that even
1586 * if the stub data is bad, we still show the authentication
1589 * If we get BoundsError, it means the frame was cut short
1590 * by a snapshot length, so there's nothing more to
1591 * dissect; just re-throw that exception.
1594 proto_tree
*stub_tree
= NULL
;
1596 int trailer_start_offset
= -1;
1597 int trailer_end_offset
= -1;
1599 stub_tree
= proto_tree_add_subtree_format(dissector_data
->dcerpc_tree
,
1600 stub_tvb
, 0, length
,
1601 ett_dcerpc_complete_stub_data
, NULL
,
1602 "Complete stub data (%d byte%s)", length
,
1603 plurality(length
, "", "s"));
1604 trailer_end_offset
= dissect_verification_trailer(pinfo
,
1607 &trailer_start_offset
);
1609 if (trailer_end_offset
!= -1) {
1610 remaining
= tvb_captured_length_remaining(stub_tvb
,
1611 trailer_start_offset
);
1612 length
-= remaining
;
1615 proto_item_set_len(sub_item
, length
);
1618 proto_item
*payload_item
;
1620 payload_item
= proto_tree_add_item(stub_tree
,
1621 hf_dcerpc_payload_stub_data
,
1622 stub_tvb
, 0, length
, ENC_NA
);
1623 proto_item_append_text(payload_item
, " (%d byte%s)",
1624 length
, plurality(length
, "", "s"));
1627 payload_tvb
= tvb_new_subset_length_caplen(stub_tvb
, 0, length
, length
);
1628 offset
= sub_dissect(payload_tvb
, 0, pinfo
, sub_tree
,
1629 dissector_data
->info
, dissector_data
->drep
);
1631 /* If we have a subdissector and it didn't dissect all
1632 data in the tvb, make a note of it. */
1633 remaining
= tvb_reported_length_remaining(stub_tvb
, offset
);
1635 if (trailer_end_offset
!= -1) {
1636 if (offset
> trailer_start_offset
) {
1637 remaining
= offset
- trailer_start_offset
;
1638 proto_tree_add_item(sub_tree
, hf_dcerpc_stub_data_with_sec_vt
,
1639 stub_tvb
, trailer_start_offset
, remaining
, ENC_NA
);
1640 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
1641 "[Payload with Verification Trailer (%d byte%s)]",
1643 plurality(remaining
, "", "s"));
1646 remaining
= trailer_start_offset
- offset
;
1650 if (remaining
> 0) {
1651 proto_tree_add_expert(sub_tree
, pinfo
, &ei_dcerpc_long_frame
, stub_tvb
, offset
, remaining
);
1652 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
1653 "[Long frame (%d byte%s)]",
1655 plurality(remaining
, "", "s"));
1657 } CATCH_NONFATAL_ERRORS
{
1659 * Somebody threw an exception that means that there
1660 * was a problem dissecting the payload; that means
1661 * that a dissector was found, so we don't need to
1662 * dissect the payload as data or update the protocol
1665 * Just show the exception and then drive on to show
1666 * the authentication padding.
1668 show_exception(stub_tvb
, pinfo
, tree
, EXCEPT_CODE
, GET_MESSAGE
);
1672 /* If there is auth padding at the end of the stub, display it */
1673 if (auth_pad_len
!= 0) {
1674 proto_tree_add_item(sub_tree
, hf_dcerpc_auth_padding
, tvb
, auth_pad_offset
, auth_pad_len
, ENC_NA
);
1677 free_ndr_pointer_list(dissector_data
->info
);
1679 pinfo
->current_proto
= saved_proto
;
1681 return tvb_captured_length(tvb
);
1685 dcerpc_init_finalize(dissector_handle_t guid_handle
, guid_key
*key
, dcerpc_uuid_value
*value
)
1687 module_t
*samr_module
;
1688 const char *filter_name
= proto_get_protocol_filter_name(value
->proto_id
);
1690 g_hash_table_insert(dcerpc_uuids
, key
, value
);
1692 /* Register the GUID with the dissector table */
1693 dissector_add_guid( "dcerpc.uuid", key
, guid_handle
);
1695 /* add this GUID to the global name resolving */
1696 guids_add_uuid(&key
->guid
, proto_get_protocol_short_name(value
->proto
));
1698 /* Register the samr.nt_password preference as obsolete */
1699 /* This should be in packet-dcerpc-samr.c */
1700 if (strcmp(filter_name
, "samr") == 0) {
1701 samr_module
= prefs_register_protocol_obsolete(value
->proto_id
);
1702 prefs_register_obsolete_preference(samr_module
, "nt_password");
1707 dcerpc_init_uuid(int proto
, int ett
, e_guid_t
*uuid
, uint16_t ver
,
1708 const dcerpc_sub_dissector
*procs
, int opnum_hf
)
1710 guid_key
*key
= (guid_key
*)g_malloc(sizeof (*key
));
1711 dcerpc_uuid_value
*value
= (dcerpc_uuid_value
*)g_malloc(sizeof (*value
));
1712 header_field_info
*hf_info
;
1713 dissector_handle_t guid_handle
;
1718 value
->proto
= find_protocol_by_id(proto
);
1719 value
->proto_id
= proto
;
1721 value
->name
= proto_get_protocol_short_name(value
->proto
);
1722 value
->procs
= procs
;
1723 value
->opnum_hf
= opnum_hf
;
1725 hf_info
= proto_registrar_get_nth(opnum_hf
);
1726 hf_info
->strings
= value_string_from_subdissectors(procs
);
1728 /* Register the GUID with the dissector table */
1729 guid_handle
= create_dissector_handle( dissect_dcerpc_guid
, proto
);
1731 dcerpc_init_finalize(guid_handle
, key
, value
);
1735 dcerpc_init_from_handle(int proto
, e_guid_t
*uuid
, uint16_t ver
,
1736 dissector_handle_t guid_handle
)
1738 guid_key
*key
= (guid_key
*)g_malloc(sizeof (*key
));
1739 dcerpc_uuid_value
*value
= (dcerpc_uuid_value
*)g_malloc(sizeof (*value
));
1744 value
->proto
= find_protocol_by_id(proto
);
1745 value
->proto_id
= proto
;
1747 value
->name
= proto_get_protocol_short_name(value
->proto
);
1748 value
->opnum_hf
= 0;
1750 if (g_hash_table_contains(dcerpc_uuids
, key
)) {
1751 g_hash_table_remove(dcerpc_uuids
, key
);
1752 guids_delete_guid(uuid
);
1755 dcerpc_init_finalize(guid_handle
, key
, value
);
1758 /* Function to find the name of a registered protocol
1759 * or NULL if the protocol/version is not known to wireshark.
1762 dcerpc_get_proto_name(e_guid_t
*uuid
, uint16_t ver
)
1764 dissector_handle_t handle
;
1770 handle
= dissector_get_guid_handle(uuid_dissector_table
, &key
);
1771 if (handle
== NULL
) {
1775 return dissector_handle_get_protocol_short_name(handle
);
1778 /* Function to find the opnum hf-field of a registered protocol
1779 * or -1 if the protocol/version is not known to wireshark.
1782 dcerpc_get_proto_hf_opnum(e_guid_t
*uuid
, uint16_t ver
)
1785 dcerpc_uuid_value
*sub_proto
;
1789 if (!(sub_proto
= (dcerpc_uuid_value
*)g_hash_table_lookup(dcerpc_uuids
, &key
))) {
1792 return sub_proto
->opnum_hf
;
1795 /* Create a value_string consisting of DCERPC opnum and name from a
1796 subdissector array. */
1798 value_string
*value_string_from_subdissectors(const dcerpc_sub_dissector
*sd
)
1800 value_string
*vs
= NULL
;
1805 for (i
= 0; sd
[i
].name
; i
++) {
1807 vs
[i
].value
= sd
[i
].num
;
1808 vs
[i
].strptr
= sd
[i
].name
;
1814 vs
= (value_string
*)wmem_alloc(wmem_epan_scope(), (num_sd
+ 1) * sizeof(value_string
));
1818 vs
[num_sd
].value
= 0;
1819 vs
[num_sd
].strptr
= NULL
;
1824 /* Function to find the subdissector table of a registered protocol
1825 * or NULL if the protocol/version is not known to wireshark.
1827 const dcerpc_sub_dissector
*
1828 dcerpc_get_proto_sub_dissector(e_guid_t
*uuid
, uint16_t ver
)
1831 dcerpc_uuid_value
*sub_proto
;
1835 if (!(sub_proto
= (dcerpc_uuid_value
*)g_hash_table_lookup(dcerpc_uuids
, &key
))) {
1838 return sub_proto
->procs
;
1843 dcerpc_connection_equal(const void *k1
, const void *k2
)
1845 const dcerpc_connection
*key1
= (const dcerpc_connection
*)k1
;
1846 const dcerpc_connection
*key2
= (const dcerpc_connection
*)k2
;
1847 return ((key1
->conv
== key2
->conv
)
1848 && (key1
->transport_salt
== key2
->transport_salt
));
1852 dcerpc_connection_hash(const void *k
)
1854 const dcerpc_connection
*key
= (const dcerpc_connection
*)k
;
1857 hash
= GPOINTER_TO_UINT(key
->conv
);
1858 hash
+= g_int64_hash(&key
->transport_salt
);
1865 dcerpc_bind_equal(const void *k1
, const void *k2
)
1867 const dcerpc_bind_key
*key1
= (const dcerpc_bind_key
*)k1
;
1868 const dcerpc_bind_key
*key2
= (const dcerpc_bind_key
*)k2
;
1869 return ((key1
->conv
== key2
->conv
)
1870 && (key1
->ctx_id
== key2
->ctx_id
)
1871 && (key1
->transport_salt
== key2
->transport_salt
));
1875 dcerpc_bind_hash(const void *k
)
1877 const dcerpc_bind_key
*key
= (const dcerpc_bind_key
*)k
;
1880 hash
= GPOINTER_TO_UINT(key
->conv
);
1881 hash
+= key
->ctx_id
;
1882 /* sizeof(unsigned) might be smaller than sizeof(uint64_t) */
1883 hash
+= (unsigned)key
->transport_salt
;
1884 hash
+= (unsigned)(key
->transport_salt
<< sizeof(unsigned));
1890 dcerpc_auth_context_equal(const void *k1
, const void *k2
)
1892 const dcerpc_auth_context
*key1
= (const dcerpc_auth_context
*)k1
;
1893 const dcerpc_auth_context
*key2
= (const dcerpc_auth_context
*)k2
;
1894 return ((key1
->conv
== key2
->conv
)
1895 && (key1
->auth_context_id
== key2
->auth_context_id
)
1896 && (key1
->transport_salt
== key2
->transport_salt
));
1900 dcerpc_auth_context_hash(const void *k
)
1902 const dcerpc_auth_context
*key
= (const dcerpc_auth_context
*)k
;
1905 hash
= GPOINTER_TO_UINT(key
->conv
);
1906 hash
+= key
->auth_context_id
;
1907 /* sizeof(unsigned) might be smaller than sizeof(uint64_t) */
1908 hash
+= (unsigned)key
->transport_salt
;
1909 hash
+= (unsigned)(key
->transport_salt
<< sizeof(unsigned));
1915 * To keep track of callid mappings. Should really use some generic
1916 * conversation support instead.
1918 static wmem_map_t
*dcerpc_cn_calls
;
1919 static wmem_map_t
*dcerpc_dg_calls
;
1921 typedef struct _dcerpc_cn_call_key
{
1922 conversation_t
*conv
;
1924 uint64_t transport_salt
;
1925 } dcerpc_cn_call_key
;
1927 typedef struct _dcerpc_dg_call_key
{
1928 conversation_t
*conv
;
1931 } dcerpc_dg_call_key
;
1935 dcerpc_cn_call_equal(const void *k1
, const void *k2
)
1937 const dcerpc_cn_call_key
*key1
= (const dcerpc_cn_call_key
*)k1
;
1938 const dcerpc_cn_call_key
*key2
= (const dcerpc_cn_call_key
*)k2
;
1939 return ((key1
->conv
== key2
->conv
)
1940 && (key1
->call_id
== key2
->call_id
)
1941 && (key1
->transport_salt
== key2
->transport_salt
));
1945 dcerpc_dg_call_equal(const void *k1
, const void *k2
)
1947 const dcerpc_dg_call_key
*key1
= (const dcerpc_dg_call_key
*)k1
;
1948 const dcerpc_dg_call_key
*key2
= (const dcerpc_dg_call_key
*)k2
;
1949 return ((key1
->conv
== key2
->conv
)
1950 && (key1
->seqnum
== key2
->seqnum
)
1951 && ((memcmp(&key1
->act_id
, &key2
->act_id
, sizeof (e_guid_t
)) == 0)));
1955 dcerpc_cn_call_hash(const void *k
)
1957 const dcerpc_cn_call_key
*key
= (const dcerpc_cn_call_key
*)k
;
1960 hash
= GPOINTER_TO_UINT(key
->conv
);
1961 hash
+= key
->call_id
;
1962 /* sizeof(unsigned) might be smaller than sizeof(uint64_t) */
1963 hash
+= (unsigned)key
->transport_salt
;
1964 hash
+= (unsigned)(key
->transport_salt
<< sizeof(unsigned));
1970 dcerpc_dg_call_hash(const void *k
)
1972 const dcerpc_dg_call_key
*key
= (const dcerpc_dg_call_key
*)k
;
1973 return (GPOINTER_TO_UINT(key
->conv
) + key
->seqnum
+ key
->act_id
.data1
1974 + (key
->act_id
.data2
<< 16) + key
->act_id
.data3
1975 + (key
->act_id
.data4
[0] << 24) + (key
->act_id
.data4
[1] << 16)
1976 + (key
->act_id
.data4
[2] << 8) + (key
->act_id
.data4
[3] << 0)
1977 + (key
->act_id
.data4
[4] << 24) + (key
->act_id
.data4
[5] << 16)
1978 + (key
->act_id
.data4
[6] << 8) + (key
->act_id
.data4
[7] << 0));
1981 /* to keep track of matched calls/responses
1982 this one uses the same value struct as calls, but the key is the frame id
1983 and call id; there can be more than one call in a frame.
1985 XXX - why not just use the same keys as are used for calls?
1988 static wmem_map_t
*dcerpc_matched
;
1990 typedef struct _dcerpc_matched_key
{
1993 } dcerpc_matched_key
;
1996 dcerpc_matched_equal(const void *k1
, const void *k2
)
1998 const dcerpc_matched_key
*key1
= (const dcerpc_matched_key
*)k1
;
1999 const dcerpc_matched_key
*key2
= (const dcerpc_matched_key
*)k2
;
2000 return ((key1
->frame
== key2
->frame
)
2001 && (key1
->call_id
== key2
->call_id
));
2005 dcerpc_matched_hash(const void *k
)
2007 const dcerpc_matched_key
*key
= (const dcerpc_matched_key
*)k
;
2012 uuid_equal(e_guid_t
*uuid1
, e_guid_t
*uuid2
)
2014 if( (uuid1
->data1
!= uuid2
->data1
)
2015 ||(uuid1
->data2
!= uuid2
->data2
)
2016 ||(uuid1
->data3
!= uuid2
->data3
)
2017 ||(uuid1
->data4
[0] != uuid2
->data4
[0])
2018 ||(uuid1
->data4
[1] != uuid2
->data4
[1])
2019 ||(uuid1
->data4
[2] != uuid2
->data4
[2])
2020 ||(uuid1
->data4
[3] != uuid2
->data4
[3])
2021 ||(uuid1
->data4
[4] != uuid2
->data4
[4])
2022 ||(uuid1
->data4
[5] != uuid2
->data4
[5])
2023 ||(uuid1
->data4
[6] != uuid2
->data4
[6])
2024 ||(uuid1
->data4
[7] != uuid2
->data4
[7]) ){
2031 dcerpcstat_init(struct register_srt
* srt
, GArray
* srt_array
)
2033 dcerpcstat_tap_data_t
* tap_data
= (dcerpcstat_tap_data_t
*)get_srt_table_param_data(srt
);
2034 srt_stat_table
*dcerpc_srt_table
;
2036 const dcerpc_sub_dissector
*procs
;
2038 DISSECTOR_ASSERT(tap_data
);
2040 hf_opnum
= dcerpc_get_proto_hf_opnum(&tap_data
->uuid
, tap_data
->ver
);
2041 procs
= dcerpc_get_proto_sub_dissector(&tap_data
->uuid
, tap_data
->ver
);
2044 dcerpc_srt_table
= init_srt_table(tap_data
->prog
, NULL
, srt_array
, tap_data
->num_procedures
, NULL
, proto_registrar_get_nth(hf_opnum
)->abbrev
, tap_data
);
2046 dcerpc_srt_table
= init_srt_table(tap_data
->prog
, NULL
, srt_array
, tap_data
->num_procedures
, NULL
, NULL
, tap_data
);
2049 for(i
=0;i
<tap_data
->num_procedures
;i
++){
2051 const char *proc_name
;
2053 proc_name
= "unknown";
2054 for(j
=0;procs
[j
].name
;j
++)
2056 if (procs
[j
].num
== i
)
2058 proc_name
= procs
[j
].name
;
2062 init_srt_table_row(dcerpc_srt_table
, i
, proc_name
);
2066 static tap_packet_status
2067 dcerpcstat_packet(void *pss
, packet_info
*pinfo
, epan_dissect_t
*edt _U_
, const void *prv
, tap_flags_t flags _U_
)
2070 srt_stat_table
*dcerpc_srt_table
;
2071 srt_data_t
*data
= (srt_data_t
*)pss
;
2072 const dcerpc_info
*ri
= (const dcerpc_info
*)prv
;
2073 dcerpcstat_tap_data_t
* tap_data
;
2075 dcerpc_srt_table
= g_array_index(data
->srt_array
, srt_stat_table
*, i
);
2076 tap_data
= (dcerpcstat_tap_data_t
*)dcerpc_srt_table
->table_specific_data
;
2079 return TAP_PACKET_DONT_REDRAW
;
2081 if(!ri
->call_data
->req_frame
){
2082 /* we have not seen the request so we don't know the delta*/
2083 return TAP_PACKET_DONT_REDRAW
;
2085 if(ri
->call_data
->opnum
>= tap_data
->num_procedures
){
2086 /* don't handle this since it's outside of known table */
2087 return TAP_PACKET_DONT_REDRAW
;
2090 /* we are only interested in reply packets */
2091 if(ri
->ptype
!= PDU_RESP
){
2092 return TAP_PACKET_DONT_REDRAW
;
2095 /* we are only interested in certain program/versions */
2096 if( (!uuid_equal( (&ri
->call_data
->uuid
), (&tap_data
->uuid
)))
2097 ||(ri
->call_data
->ver
!= tap_data
->ver
)){
2098 return TAP_PACKET_DONT_REDRAW
;
2101 add_srt_table_data(dcerpc_srt_table
, ri
->call_data
->opnum
, &ri
->call_data
->req_time
, pinfo
);
2103 return TAP_PACKET_REDRAW
;
2107 dcerpcstat_param(register_srt_t
* srt
, const char* opt_arg
, char** err
)
2110 uint32_t i
, max_procs
;
2111 dcerpcstat_tap_data_t
* tap_data
;
2112 unsigned d1
,d2
,d3
,d40
,d41
,d42
,d43
,d44
,d45
,d46
,d47
;
2115 const dcerpc_sub_dissector
*procs
;
2117 if (sscanf(opt_arg
, ",%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x,%d.%d%n",
2118 &d1
,&d2
,&d3
,&d40
,&d41
,&d42
,&d43
,&d44
,&d45
,&d46
,&d47
,&major
,&minor
,&pos
) == 13)
2120 if ((major
< 0) || (major
> 65535)) {
2121 *err
= ws_strdup_printf("dcerpcstat_init() Major version number %d is invalid - must be positive and <= 65535", major
);
2124 if ((minor
< 0) || (minor
> 65535)) {
2125 *err
= ws_strdup_printf("dcerpcstat_init() Minor version number %d is invalid - must be positive and <= 65535", minor
);
2130 tap_data
= g_new0(dcerpcstat_tap_data_t
, 1);
2132 tap_data
->uuid
.data1
= d1
;
2133 tap_data
->uuid
.data2
= d2
;
2134 tap_data
->uuid
.data3
= d3
;
2135 tap_data
->uuid
.data4
[0] = d40
;
2136 tap_data
->uuid
.data4
[1] = d41
;
2137 tap_data
->uuid
.data4
[2] = d42
;
2138 tap_data
->uuid
.data4
[3] = d43
;
2139 tap_data
->uuid
.data4
[4] = d44
;
2140 tap_data
->uuid
.data4
[5] = d45
;
2141 tap_data
->uuid
.data4
[6] = d46
;
2142 tap_data
->uuid
.data4
[7] = d47
;
2144 procs
= dcerpc_get_proto_sub_dissector(&tap_data
->uuid
, ver
);
2145 tap_data
->prog
= dcerpc_get_proto_name(&tap_data
->uuid
, ver
);
2146 tap_data
->ver
= ver
;
2148 for(i
=0,max_procs
=0;procs
[i
].name
;i
++)
2150 if(procs
[i
].num
>max_procs
)
2152 max_procs
= procs
[i
].num
;
2155 tap_data
->num_procedures
= max_procs
+1;
2157 set_srt_table_param_data(srt
, tap_data
);
2161 *err
= ws_strdup_printf("<uuid>,<major version>.<minor version>[,<filter>]");
2169 * Utility functions. Modeled after packet-rpc.c
2173 dissect_dcerpc_char(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo _U_
,
2174 proto_tree
*tree
, uint8_t *drep
,
2175 int hfindex
, uint8_t *pdata
)
2180 * XXX - fix to handle EBCDIC if we ever support EBCDIC FT_CHAR.
2182 data
= tvb_get_uint8(tvb
, offset
);
2183 if (hfindex
!= -1) {
2184 proto_tree_add_item(tree
, hfindex
, tvb
, offset
, 1, ENC_ASCII
|DREP_ENC_INTEGER(drep
));
2188 tvb_ensure_bytes_exist(tvb
, offset
, 1);
2193 dissect_dcerpc_uint8(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo _U_
,
2194 proto_tree
*tree
, uint8_t *drep
,
2195 int hfindex
, uint8_t *pdata
)
2199 data
= tvb_get_uint8(tvb
, offset
);
2200 if (hfindex
!= -1) {
2201 proto_tree_add_item(tree
, hfindex
, tvb
, offset
, 1, DREP_ENC_INTEGER(drep
));
2205 tvb_ensure_bytes_exist(tvb
, offset
, 1);
2210 dissect_dcerpc_uint16(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo _U_
,
2211 proto_tree
*tree
, uint8_t *drep
,
2212 int hfindex
, uint16_t *pdata
)
2216 data
= ((drep
[0] & DREP_LITTLE_ENDIAN
)
2217 ? tvb_get_letohs(tvb
, offset
)
2218 : tvb_get_ntohs(tvb
, offset
));
2220 if (hfindex
!= -1) {
2221 proto_tree_add_item(tree
, hfindex
, tvb
, offset
, 2, DREP_ENC_INTEGER(drep
));
2225 tvb_ensure_bytes_exist(tvb
, offset
, 2);
2230 dissect_dcerpc_uint32(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo _U_
,
2231 proto_tree
*tree
, uint8_t *drep
,
2232 int hfindex
, uint32_t *pdata
)
2236 data
= ((drep
[0] & DREP_LITTLE_ENDIAN
)
2237 ? tvb_get_letohl(tvb
, offset
)
2238 : tvb_get_ntohl(tvb
, offset
));
2240 if (hfindex
!= -1) {
2241 proto_tree_add_item(tree
, hfindex
, tvb
, offset
, 4, DREP_ENC_INTEGER(drep
));
2245 tvb_ensure_bytes_exist(tvb
, offset
, 4);
2249 /* handles 32 bit unix time_t */
2251 dissect_dcerpc_time_t(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo _U_
,
2252 proto_tree
*tree
, uint8_t *drep
,
2253 int hfindex
, uint32_t *pdata
)
2258 data
= ((drep
[0] & DREP_LITTLE_ENDIAN
)
2259 ? tvb_get_letohl(tvb
, offset
)
2260 : tvb_get_ntohl(tvb
, offset
));
2264 if (hfindex
!= -1) {
2265 if (data
== 0xffffffff) {
2266 /* special case, no time specified */
2267 proto_tree_add_time_format_value(tree
, hfindex
, tvb
, offset
, 4, &tv
, "No time specified");
2269 proto_tree_add_time(tree
, hfindex
, tvb
, offset
, 4, &tv
);
2275 tvb_ensure_bytes_exist(tvb
, offset
, 4);
2280 dissect_dcerpc_uint64(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo _U_
,
2281 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
,
2282 int hfindex
, uint64_t *pdata
)
2286 data
= ((drep
[0] & DREP_LITTLE_ENDIAN
)
2287 ? tvb_get_letoh64(tvb
, offset
)
2288 : tvb_get_ntoh64(tvb
, offset
));
2290 if (hfindex
!= -1) {
2291 header_field_info
*hfinfo
;
2293 /* This might be a field that is either 32bit, in NDR or
2294 64 bits in NDR64. So we must be careful and call the right
2297 hfinfo
= proto_registrar_get_nth(hfindex
);
2299 switch (hfinfo
->type
) {
2301 proto_tree_add_uint64(tree
, hfindex
, tvb
, offset
, 8, data
);
2304 proto_tree_add_int64(tree
, hfindex
, tvb
, offset
, 8, data
);
2307 /* The value is truncated to 32bits. 64bit values have only been
2308 seen on fuzz-tested files */
2309 DISSECTOR_ASSERT((di
->call_data
->flags
& DCERPC_IS_NDR64
) || (data
<= UINT32_MAX
));
2310 proto_tree_add_uint(tree
, hfindex
, tvb
, offset
, 8, (uint32_t)data
);
2315 tvb_ensure_bytes_exist(tvb
, offset
, 8);
2321 dissect_dcerpc_float(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
2322 proto_tree
*tree
, uint8_t *drep
,
2323 int hfindex
, float *pdata
)
2329 case(DCE_RPC_DREP_FP_IEEE
):
2330 data
= ((drep
[0] & DREP_LITTLE_ENDIAN
)
2331 ? tvb_get_letohieee_float(tvb
, offset
)
2332 : tvb_get_ntohieee_float(tvb
, offset
));
2333 if (tree
&& hfindex
!= -1) {
2334 proto_tree_add_float(tree
, hfindex
, tvb
, offset
, 4, data
);
2337 case(DCE_RPC_DREP_FP_VAX
): /* (fall trough) */
2338 case(DCE_RPC_DREP_FP_CRAY
): /* (fall trough) */
2339 case(DCE_RPC_DREP_FP_IBM
): /* (fall trough) */
2341 /* ToBeDone: non IEEE floating formats */
2342 /* Set data to a negative infinity value */
2344 proto_tree_add_expert_format(tree
, pinfo
, &ei_dcerpc_not_implemented
, tvb
, offset
, 4,
2345 "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!",
2350 tvb_ensure_bytes_exist(tvb
, offset
, 4);
2356 dissect_dcerpc_double(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo _U_
,
2357 proto_tree
*tree
, uint8_t *drep
,
2358 int hfindex
, double *pdata
)
2364 case(DCE_RPC_DREP_FP_IEEE
):
2365 data
= ((drep
[0] & DREP_LITTLE_ENDIAN
)
2366 ? tvb_get_letohieee_double(tvb
, offset
)
2367 : tvb_get_ntohieee_double(tvb
, offset
));
2368 if (tree
&& hfindex
!= -1) {
2369 proto_tree_add_double(tree
, hfindex
, tvb
, offset
, 8, data
);
2372 case(DCE_RPC_DREP_FP_VAX
): /* (fall trough) */
2373 case(DCE_RPC_DREP_FP_CRAY
): /* (fall trough) */
2374 case(DCE_RPC_DREP_FP_IBM
): /* (fall trough) */
2376 /* ToBeDone: non IEEE double formats */
2377 /* Set data to a negative infinity value */
2379 proto_tree_add_expert_format(tree
, pinfo
, &ei_dcerpc_not_implemented
, tvb
, offset
, 8,
2380 "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!",
2385 tvb_ensure_bytes_exist(tvb
, offset
, 8);
2391 dissect_dcerpc_uuid_t(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo _U_
,
2392 proto_tree
*tree
, uint8_t *drep
,
2393 int hfindex
, e_guid_t
*pdata
)
2398 if (drep
[0] & DREP_LITTLE_ENDIAN
) {
2399 tvb_get_letohguid(tvb
, offset
, (e_guid_t
*) &uuid
);
2401 tvb_get_ntohguid(tvb
, offset
, (e_guid_t
*) &uuid
);
2403 if (tree
&& hfindex
!= -1) {
2404 proto_tree_add_guid(tree
, hfindex
, tvb
, offset
, 16, (e_guid_t
*) &uuid
);
2414 * a couple simpler things
2417 dcerpc_tvb_get_ntohs(tvbuff_t
*tvb
, int offset
, uint8_t *drep
)
2419 if (drep
[0] & DREP_LITTLE_ENDIAN
) {
2420 return tvb_get_letohs(tvb
, offset
);
2422 return tvb_get_ntohs(tvb
, offset
);
2427 dcerpc_tvb_get_ntohl(tvbuff_t
*tvb
, int offset
, uint8_t *drep
)
2429 if (drep
[0] & DREP_LITTLE_ENDIAN
) {
2430 return tvb_get_letohl(tvb
, offset
);
2432 return tvb_get_ntohl(tvb
, offset
);
2437 dcerpc_tvb_get_uuid(tvbuff_t
*tvb
, int offset
, uint8_t *drep
, e_guid_t
*uuid
)
2439 if (drep
[0] & DREP_LITTLE_ENDIAN
) {
2440 tvb_get_letohguid(tvb
, offset
, (e_guid_t
*) uuid
);
2442 tvb_get_ntohguid(tvb
, offset
, (e_guid_t
*) uuid
);
2447 dissect_ndr_conformant_array_hdr(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
2448 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
,
2449 struct ndr_generic_array
*nga
)
2451 int conformance_size
= 4;
2454 DISSECTOR_ASSERT(!nga
->is_conformant
&& !nga
->is_varying
);
2456 if (di
->call_data
->flags
& DCERPC_IS_NDR64
) {
2457 conformance_size
= 8;
2460 /* conformant array header */
2461 offset
= dissect_ndr_uint3264(tvb
, offset
, pinfo
, tree
, di
, drep
,
2463 DISSECTOR_ASSERT(val
<= UINT32_MAX
);
2464 nga
->max_count
= (uint32_t)val
;
2465 nga
->max_count_offset
= offset
-conformance_size
;
2468 nga
->actual_count
= nga
->max_count
;
2470 nga
->is_conformant
= true;
2476 dissect_ndr_varying_array_hdr(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
2477 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
,
2478 struct ndr_generic_array
*nga
)
2480 int conformance_size
= 4;
2483 DISSECTOR_ASSERT(!nga
->is_varying
);
2485 if (di
->call_data
->flags
& DCERPC_IS_NDR64
) {
2486 conformance_size
= 8;
2489 /* varying array header */
2490 offset
= dissect_ndr_uint3264(tvb
, offset
, pinfo
, tree
, di
, drep
,
2492 DISSECTOR_ASSERT(val
<= UINT32_MAX
);
2493 nga
->offset
= (uint32_t)val
;
2494 nga
->offset_offset
= offset
-conformance_size
;
2495 offset
= dissect_ndr_uint3264(tvb
, offset
, pinfo
, tree
, di
, drep
,
2497 DISSECTOR_ASSERT(val
<= UINT32_MAX
);
2498 nga
->actual_count
= (uint32_t)val
;
2499 nga
->actual_count_offset
= offset
-conformance_size
;
2501 nga
->is_varying
= true;
2507 dissect_ndr_generic_array(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
2508 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
,
2509 struct ndr_generic_array
*nga
,
2510 dcerpc_dissect_fnct_t
*fnct_bytes
,
2511 dcerpc_dissect_fnct_blk_t
*fnct_block
)
2513 int conformance_size
= 4;
2515 if (di
->call_data
->flags
& DCERPC_IS_NDR64
) {
2516 conformance_size
= 8;
2519 DISSECTOR_ASSERT(nga
->is_conformant
|| nga
->is_varying
);
2520 /* ensure that just one pointer is set in the call */
2521 DISSECTOR_ASSERT((fnct_bytes
&& !fnct_block
) || (!fnct_bytes
&& fnct_block
));
2523 /* we don't remember where in the bytestream this field was */
2525 if (nga
->is_conformant
) {
2526 proto_tree_add_uint(tree
, hf_dcerpc_array_max_count
, tvb
,
2527 nga
->max_count_offset
,
2531 if (nga
->is_varying
) {
2532 proto_tree_add_uint(tree
, hf_dcerpc_array_offset
, tvb
,
2536 proto_tree_add_uint(tree
, hf_dcerpc_array_actual_count
, tvb
,
2537 nga
->actual_count_offset
,
2542 /* real run, dissect the elements */
2544 offset
= (*fnct_block
)(tvb
, offset
, nga
->actual_count
,
2545 pinfo
, tree
, di
, drep
);
2548 for (i
=0 ;i
<nga
->actual_count
; i
++) {
2549 int old_offset
= offset
;
2550 offset
= (*fnct_bytes
)(tvb
, offset
, pinfo
, tree
, di
, drep
);
2551 /* Make sure we're moving forward */
2552 if (old_offset
>= offset
)
2561 dissect_ndr_generic_array_bytes(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
2562 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
,
2563 struct ndr_generic_array
*nga
,
2564 dcerpc_dissect_fnct_t
*fnct_bytes
)
2566 return dissect_ndr_generic_array(tvb
, offset
, pinfo
,
2567 tree
, di
, drep
, nga
,
2573 dissect_ndr_generic_array_block(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
2574 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
,
2575 struct ndr_generic_array
*nga
,
2576 dcerpc_dissect_fnct_blk_t
*fnct_block
)
2578 return dissect_ndr_generic_array(tvb
, offset
, pinfo
,
2579 tree
, di
, drep
, nga
,
2585 /* function to dissect a unidimensional conformant array */
2587 dissect_ndr_c_and_or_v_array_core(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
2588 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
,
2589 bool is_conformant
, bool is_varying
,
2590 dcerpc_dissect_fnct_t
*fnct_bytes
,
2591 dcerpc_dissect_fnct_blk_t
*fnct_block
)
2593 struct ndr_generic_array nga
= { .is_conformant
= false, };
2595 DISSECTOR_ASSERT(is_conformant
|| is_varying
);
2596 /* ensure that just one pointer is set in the call */
2597 DISSECTOR_ASSERT((fnct_bytes
&& !fnct_block
) || (!fnct_bytes
&& fnct_block
));
2600 offset
= dissect_ndr_conformant_array_hdr(tvb
, offset
, pinfo
, tree
, di
, drep
, &nga
);
2602 offset
= dissect_ndr_varying_array_hdr(tvb
, offset
, pinfo
, tree
, di
, drep
, &nga
);
2604 offset
= dissect_ndr_generic_array_block(tvb
, offset
, pinfo
,
2605 tree
, di
, drep
, &nga
,
2607 } else if (fnct_bytes
) {
2608 offset
= dissect_ndr_generic_array_bytes(tvb
, offset
, pinfo
,
2609 tree
, di
, drep
, &nga
,
2617 /* function to dissect a unidimensional conformant array */
2619 dissect_ndr_ucarray_core(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
2620 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
,
2621 dcerpc_dissect_fnct_t
*fnct_bytes
,
2622 dcerpc_dissect_fnct_blk_t
*fnct_block
)
2624 return dissect_ndr_c_and_or_v_array_core(tvb
, offset
, pinfo
,
2626 true, /* is_conformant */
2627 false, /* is_varying */
2633 dissect_ndr_ucarray_block(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
2634 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
,
2635 dcerpc_dissect_fnct_blk_t
*fnct
)
2637 return dissect_ndr_ucarray_core(tvb
, offset
, pinfo
, tree
, di
, drep
, NULL
, fnct
);
2641 dissect_ndr_ucarray(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
2642 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
,
2643 dcerpc_dissect_fnct_t
*fnct
)
2645 return dissect_ndr_ucarray_core(tvb
, offset
, pinfo
, tree
, di
, drep
, fnct
, NULL
);
2648 /* function to dissect a unidimensional conformant and varying array
2649 * depending on the dissection function passed as a parameter,
2650 * content of the array will be dissected as a block or byte by byte
2653 dissect_ndr_ucvarray_core(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
2654 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
,
2655 dcerpc_dissect_fnct_t
*fnct_bytes
,
2656 dcerpc_dissect_fnct_blk_t
*fnct_block
)
2658 return dissect_ndr_c_and_or_v_array_core(tvb
, offset
, pinfo
,
2660 true, /* is_conformant */
2661 true, /* is_varying */
2667 dissect_ndr_ucvarray_block(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
2668 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
,
2669 dcerpc_dissect_fnct_blk_t
*fnct
)
2671 return dissect_ndr_ucvarray_core(tvb
, offset
, pinfo
, tree
, di
, drep
, NULL
, fnct
);
2675 dissect_ndr_ucvarray(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
2676 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
,
2677 dcerpc_dissect_fnct_t
*fnct
)
2679 return dissect_ndr_ucvarray_core(tvb
, offset
, pinfo
, tree
, di
, drep
, fnct
, NULL
);
2681 /* function to dissect a unidimensional varying array */
2683 dissect_ndr_uvarray_core(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
2684 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
,
2685 dcerpc_dissect_fnct_t
*fnct_bytes
,
2686 dcerpc_dissect_fnct_blk_t
*fnct_block
)
2688 return dissect_ndr_c_and_or_v_array_core(tvb
, offset
, pinfo
,
2690 false, /* is_conformant */
2691 true, /* is_varying */
2697 dissect_ndr_uvarray(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
2698 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
,
2699 dcerpc_dissect_fnct_t
*fnct
)
2701 return dissect_ndr_uvarray_core(tvb
, offset
, pinfo
, tree
, di
, drep
, fnct
, NULL
);
2704 /* Dissect an string of bytes. This corresponds to
2705 IDL of the form '[string] byte *foo'.
2707 It can also be used for a conformant varying array of bytes if
2708 the contents of the array should be shown as a big blob, rather
2709 than showing each byte as an individual element.
2711 XXX - which of those is really the IDL type for, for example,
2712 the encrypted data in some MAPI packets? (Microsoft hasn't
2715 XXX - does this need to do all the conformant array stuff that
2716 "dissect_ndr_ucvarray()" does? These are presumably for strings
2717 that are conformant and varying - they're stored like conformant
2718 varying arrays of bytes. */
2720 dissect_ndr_byte_array(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
2721 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
)
2725 if (di
->conformant_run
) {
2726 /* just a run to handle conformant arrays, no scalars to dissect */
2730 /* NDR array header */
2732 offset
= dissect_ndr_uint3264(tvb
, offset
, pinfo
, tree
, di
, drep
,
2733 hf_dcerpc_array_max_count
, NULL
);
2735 offset
= dissect_ndr_uint3264(tvb
, offset
, pinfo
, tree
, di
, drep
,
2736 hf_dcerpc_array_offset
, NULL
);
2738 offset
= dissect_ndr_uint3264(tvb
, offset
, pinfo
, tree
, di
, drep
,
2739 hf_dcerpc_array_actual_count
, &len
);
2741 DISSECTOR_ASSERT(len
<= UINT32_MAX
);
2743 proto_tree_add_item(tree
, di
->hf_index
, tvb
, offset
, (uint32_t)len
,
2747 offset
+= (uint32_t)len
;
2752 /* For dissecting arrays that are to be interpreted as strings. */
2754 /* Dissect an NDR conformant and/or varying string of elements. */
2755 struct dcerpc_ndr_string_uarray_blk_state
{
2763 dcerpc_ndr_string_uarray_blk(tvbuff_t
*tvb
, int offset
, int actual_count
,
2764 packet_info
*pinfo
, proto_tree
*tree
,
2765 dcerpc_info
*di
, uint8_t *drep
)
2767 struct dcerpc_ndr_string_uarray_blk_state
*state
=
2768 (struct dcerpc_ndr_string_uarray_blk_state
*)di
->private_data
;
2769 int size_is
= state
->size_is
;
2770 int hfindex
= state
->hfindex
;
2771 bool add_subtree
= state
->add_subtree
;
2772 char **data
= state
->data
;
2773 proto_item
*string_item
;
2774 proto_tree
*string_tree
;
2775 uint64_t len
= actual_count
;
2776 uint32_t buffer_len
;
2780 string_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, -1, ett_dcerpc_string
, &string_item
,
2781 proto_registrar_get_name(hfindex
));
2787 /* The value is truncated to 32bits. 64bit values have only been
2788 seen on fuzztested files */
2789 buffer_len
= size_is
* (uint32_t)len
;
2792 if (!di
->no_align
&& (offset
% size_is
))
2793 offset
+= size_is
- (offset
% size_is
);
2796 * "tvb_get_string_enc()" throws an exception if the entire string
2797 * isn't in the tvbuff. If the length is bogus, this should
2798 * keep us from trying to allocate an immensely large buffer.
2799 * (It won't help if the length is *valid* but immensely large,
2800 * but that's another matter; in any case, that would happen only
2801 * if we had an immensely large tvbuff....)
2803 * XXX - so why are we doing tvb_ensure_bytes_exist()?
2805 tvb_ensure_bytes_exist(tvb
, offset
, buffer_len
);
2806 if (size_is
== sizeof(uint16_t)) {
2807 s
= (char *)tvb_get_string_enc(pinfo
->pool
, tvb
, offset
, buffer_len
,
2808 ENC_UTF_16
|DREP_ENC_INTEGER(drep
));
2811 * XXX - what if size_is is neither 1 nor 2?
2813 s
= (char *)tvb_get_string_enc(pinfo
->pool
, tvb
, offset
, buffer_len
,
2814 DREP_ENC_CHAR(drep
));
2816 if (tree
&& buffer_len
)
2817 proto_tree_add_string(string_tree
, hfindex
, tvb
, offset
,
2820 if (string_item
!= NULL
)
2821 proto_item_append_text(string_item
, ": %s", s
);
2826 offset
+= buffer_len
;
2828 proto_item_set_end(string_item
, tvb
, offset
);
2834 dissect_ndr_generic_array_string(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
2835 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
,
2836 int size_is
, int hfindex
, bool add_subtree
,
2837 struct ndr_generic_array
*nga
,
2840 struct dcerpc_ndr_string_uarray_blk_state state
= {
2843 .add_subtree
= add_subtree
,
2846 dcerpc_info old_di
= *di
;
2847 header_field_info
*hfinfo
;
2849 DISSECTOR_ASSERT(nga
->is_conformant
|| nga
->is_varying
);
2850 /* Make sure this really is a string field. */
2851 hfinfo
= proto_registrar_get_nth(hfindex
);
2852 DISSECTOR_ASSERT_FIELD_TYPE(hfinfo
, FT_STRING
);
2855 di
->private_data
= &state
;
2856 offset
= dissect_ndr_generic_array_block(tvb
, offset
, pinfo
,
2857 tree
, di
, drep
, nga
,
2858 dcerpc_ndr_string_uarray_blk
);
2865 dissect_ndr_c_and_or_v_string(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
2866 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
,
2867 int size_is
, int hfindex
, bool add_subtree
,
2868 bool is_conformant
, bool is_varying
,
2871 struct ndr_generic_array nga
= { .is_conformant
= false, };
2872 header_field_info
*hfinfo
;
2874 DISSECTOR_ASSERT(is_conformant
|| is_varying
);
2875 /* Make sure this really is a string field. */
2876 hfinfo
= proto_registrar_get_nth(hfindex
);
2877 DISSECTOR_ASSERT_FIELD_TYPE(hfinfo
, FT_STRING
);
2880 offset
= dissect_ndr_conformant_array_hdr(tvb
, offset
, pinfo
, tree
, di
, drep
, &nga
);
2882 offset
= dissect_ndr_varying_array_hdr(tvb
, offset
, pinfo
, tree
, di
, drep
, &nga
);
2883 offset
= dissect_ndr_generic_array_string(tvb
, offset
, pinfo
, tree
, di
, drep
, size_is
, hfindex
, add_subtree
, &nga
, data
);
2888 /* Dissect an NDR conformant varying string of elements. */
2890 dissect_ndr_cvstring(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
2891 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
, int size_is
,
2892 int hfindex
, bool add_subtree
, char **data
)
2894 return dissect_ndr_c_and_or_v_string(tvb
, offset
, pinfo
,
2896 size_is
, hfindex
, add_subtree
,
2897 true, /* is_conformant */
2898 true, /* is_varying */
2902 /* Dissect an NDR conformant string of elements. */
2904 dissect_ndr_cstring(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
2905 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
, int size_is
,
2906 int hfindex
, bool add_subtree
, char **data
)
2908 return dissect_ndr_c_and_or_v_string(tvb
, offset
, pinfo
,
2910 size_is
, hfindex
, add_subtree
,
2911 true, /* is_conformant */
2912 false, /* is_varying */
2916 /* Dissect an conformant varying string of chars.
2917 This corresponds to IDL of the form '[string] char *foo'.
2919 XXX - at least according to the DCE RPC 1.1 spec, a string has
2920 a null terminator, which isn't necessary as a terminator for
2921 the transfer language (as there's a length), but is presumably
2922 there for the benefit of null-terminated-string languages
2923 such as C. Is this ever used for purely counted strings?
2924 (Not that it matters if it is.) */
2926 dissect_ndr_char_cvstring(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
2927 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
)
2929 return dissect_ndr_cvstring(tvb
, offset
, pinfo
, tree
, di
, drep
,
2930 sizeof(uint8_t), di
->hf_index
,
2934 /* Dissect a conformant varying string of wchars (wide characters).
2935 This corresponds to IDL of the form '[string] wchar *foo'
2937 XXX - at least according to the DCE RPC 1.1 spec, a string has
2938 a null terminator, which isn't necessary as a terminator for
2939 the transfer language (as there's a length), but is presumably
2940 there for the benefit of null-terminated-string languages
2941 such as C. Is this ever used for purely counted strings?
2942 (Not that it matters if it is.) */
2944 dissect_ndr_wchar_cvstring(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
2945 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
)
2947 return dissect_ndr_cvstring(tvb
, offset
, pinfo
, tree
, di
, drep
,
2948 sizeof(uint16_t), di
->hf_index
,
2952 /* This function is aimed for PIDL usage and dissects a UNIQUE pointer to
2956 PIDL_dissect_cvstring(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
, proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
, int chsize
, int hfindex
, uint32_t param
)
2959 int levels
= CB_STR_ITEM_LEVELS(param
);
2961 offset
= dissect_ndr_cvstring(tvb
, offset
, pinfo
, tree
, di
, drep
,
2965 if (!di
->conformant_run
) {
2966 /* Append string to COL_INFO */
2967 if (param
& PIDL_SET_COL_INFO
) {
2968 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", %s", s
);
2970 /* Save string to dcv->private_data */
2971 if ((param
& PIDL_STR_SAVE
)
2972 && (!pinfo
->fd
->visited
)) {
2973 dcerpc_call_value
*dcv
= (dcerpc_call_value
*)di
->call_data
;
2974 dcv
->private_data
= wmem_strdup(wmem_file_scope(), s
);
2976 /* Append string to upper-level proto_items */
2977 if ((levels
> 0) && tree
&& s
&& s
[0]) {
2978 proto_item_append_text(tree
, ": %s", s
);
2979 tree
= tree
->parent
;
2982 proto_item_append_text(tree
, ": %s", s
);
2983 tree
= tree
->parent
;
2985 while (levels
> 0) {
2986 proto_item_append_text(tree
, " %s", s
);
2987 tree
= tree
->parent
;
2998 /* Dissect an NDR varying string of elements.
2999 The length of each element is given by the 'size_is' parameter;
3000 the elements are assumed to be characters or wide characters.
3003 dissect_ndr_vstring(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
3004 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
, int size_is
,
3005 int hfindex
, bool add_subtree
, char **data
)
3007 return dissect_ndr_c_and_or_v_string(tvb
, offset
, pinfo
,
3009 size_is
, hfindex
, add_subtree
,
3010 false, /* is_conformant */
3011 true, /* is_varying */
3015 /* Dissect an varying string of chars.
3016 This corresponds to IDL of the form '[string] char *foo'.
3018 XXX - at least according to the DCE RPC 1.1 spec, a string has
3019 a null terminator, which isn't necessary as a terminator for
3020 the transfer language (as there's a length), but is presumably
3021 there for the benefit of null-terminated-string languages
3022 such as C. Is this ever used for purely counted strings?
3023 (Not that it matters if it is.) */
3025 dissect_ndr_char_vstring(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
3026 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
)
3028 return dissect_ndr_vstring(tvb
, offset
, pinfo
, tree
, di
, drep
,
3029 sizeof(uint8_t), di
->hf_index
,
3033 /* Dissect a varying string of wchars (wide characters).
3034 This corresponds to IDL of the form '[string] wchar *foo'
3036 XXX - at least according to the DCE RPC 1.1 spec, a string has
3037 a null terminator, which isn't necessary as a terminator for
3038 the transfer language (as there's a length), but is presumably
3039 there for the benefit of null-terminated-string languages
3040 such as C. Is this ever used for purely counted strings?
3041 (Not that it matters if it is.) */
3043 dissect_ndr_wchar_vstring(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
3044 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
)
3046 return dissect_ndr_vstring(tvb
, offset
, pinfo
, tree
, di
, drep
,
3047 sizeof(uint16_t), di
->hf_index
,
3051 /* as a kludge, we represent all embedded reference pointers as id == -1
3052 hoping that his will not collide with any non-ref pointers */
3053 typedef struct ndr_pointer_data
{
3055 proto_item
*item
; /* proto_item for pointer */
3056 proto_tree
*tree
; /* subtree of above item */
3057 dcerpc_dissect_fnct_t
*fnct
; /*if non-NULL, we have not called it yet*/
3059 dcerpc_callback_fnct_t
*callback
;
3060 void *callback_args
;
3061 dcerpc_ptr_stack
*ptr_stack
;
3062 uint64_t switch_level
;
3063 } ndr_pointer_data_t
;
3066 free_ndr_pointer_list(dcerpc_info
*di
)
3068 while (di
->pointers
.list_list
) {
3069 GSList
*list
= (GSList
*)g_slist_nth_data(di
->pointers
.list_list
, 0);
3070 di
->pointers
.list_list
= g_slist_remove(di
->pointers
.list_list
, list
);
3071 g_slist_free_full(list
, g_free
);
3073 g_slist_free_full(di
->pointers
.list_list
, g_free
);
3074 if (di
->pointers
.hash
) {
3075 g_hash_table_destroy(di
->pointers
.hash
);
3077 memset(&di
->pointers
, 0, sizeof(di
->pointers
));
3081 init_ndr_pointer_list(dcerpc_info
*di
)
3083 di
->conformant_run
= 0;
3085 free_ndr_pointer_list(di
);
3087 di
->pointers
.are_top_level
= true;
3089 di
->pointers
.hash
= g_hash_table_new(g_int_hash
, g_int_equal
);
3093 dissect_deferred_pointers(packet_info
*pinfo
, tvbuff_t
*tvb
, int offset
, dcerpc_info
*di
, uint8_t *drep
)
3095 int found_new_pointer
;
3098 unsigned original_depth
;
3100 GSList
*current_ndr_pointer_list
;
3103 * pidl has a difficiency of unconditionally emitting calls
3104 * dissect_deferred_pointers() to the generated dissectors.
3106 if (di
->pointers
.list_list
== NULL
) {
3110 /* Probably not necessary, it is supposed to prevent more pointers from
3111 * being added to the list. */
3112 di
->pointers
.list
= NULL
;
3116 /* Obtain the current list of pointers at this level. */
3117 current_ndr_pointer_list
= (GSList
*)g_slist_last(di
->pointers
.list_list
)->data
;
3118 original_depth
= g_slist_length(di
->pointers
.list_list
);
3120 len
= g_slist_length(current_ndr_pointer_list
);
3124 found_new_pointer
= 0;
3126 for (i
=next_pointer
; i
<len
; i
++) {
3127 ndr_pointer_data_t
*tnpd
= (ndr_pointer_data_t
*)g_slist_nth_data(current_ndr_pointer_list
, i
);
3130 GSList
*saved_ndr_pointer_list
= NULL
;
3131 dcerpc_ptr_stack
*saved_ptr_stack
= di
->ptr_stack
;
3132 uint64_t saved_switch_level
= di
->switch_level
;
3134 dcerpc_dissect_fnct_t
*fnct
;
3137 found_new_pointer
= 1;
3140 di
->ptr_stack
= tnpd
->ptr_stack
;
3141 di
->hf_index
= tnpd
->hf_index
;
3142 /* first a run to handle any conformant
3144 di
->conformant_run
= 1;
3145 di
->conformant_eaten
= 0;
3146 old_offset
= offset
;
3147 saved_ndr_pointer_list
= current_ndr_pointer_list
;
3148 di
->pointers
.list
= NULL
;
3149 offset
= (*(fnct
))(tvb
, offset
, pinfo
, NULL
, di
, drep
);
3151 DISSECTOR_ASSERT((offset
-old_offset
) == di
->conformant_eaten
);
3152 /* This is to check for any bugs in the dissectors.
3154 * Basically, the NDR representation will store all
3155 * arrays in two blocks, one block with the dimension
3156 * description, like size, number of elements and such,
3157 * and another block that contains the actual data stored
3159 * If the array is embedded directly inside another,
3160 * encapsulating aggregate type, like a union or struct,
3161 * then these two blocks will be stored at different places
3162 * in the bytestream, with other data between the blocks.
3164 * For this reason, all pointers to types (both aggregate
3165 * and scalar, for simplicity no distinction is made)
3166 * will have its dissector called twice.
3167 * The dissector will first be called with conformant_run == 1
3168 * in which mode the dissector MUST NOT consume any data from
3169 * the tvbuff (i.e. may not dissect anything) except the
3170 * initial control block for arrays.
3171 * The second time the dissector is called, with
3172 * conformant_run == 0, all other data for the type will be
3175 * All dissect_ndr_<type> dissectors are already prepared
3176 * for this and knows when it should eat data from the tvb
3177 * and when not to, so implementors of dissectors will
3178 * normally not need to worry about this or even know about
3179 * it. However, if a dissector for an aggregate type calls
3180 * a subdissector from outside packet-dcerpc.c, such as
3181 * the dissector in packet-smb.c for NT Security Descriptors
3182 * as an example, then it is VERY important to encapsulate
3183 * this call to an external subdissector with the appropriate
3184 * test for conformant_run, i.e. it will need something like
3186 * dcerpc_info *di (received as function parameter)
3188 * if (di->conformant_run) {
3192 * to make sure it makes the right thing.
3193 * This assert will signal when someone has forgotten to
3194 * make the dissector aware of this requirement.
3197 /* now we dissect the actual pointer */
3198 di
->conformant_run
= 0;
3199 old_offset
= offset
;
3200 offset
= (*(fnct
))(tvb
, offset
, pinfo
, tnpd
->tree
, di
, drep
);
3202 tnpd
->callback(pinfo
, tnpd
->tree
, tnpd
->item
, di
, tvb
, old_offset
, offset
, tnpd
->callback_args
);
3203 proto_item_set_len(tnpd
->item
, offset
- old_offset
);
3204 di
->ptr_stack
= saved_ptr_stack
;
3205 di
->switch_level
= saved_switch_level
;
3206 if (di
->pointers
.list
) {
3207 /* We found some pointers to dissect, descend into it. */
3209 len
= g_slist_length(di
->pointers
.list
);
3210 current_ndr_pointer_list
= di
->pointers
.list
;
3211 di
->pointers
.list
= NULL
;
3212 goto process_list
; /* Process the new current_ndr_pointer_list */
3214 current_ndr_pointer_list
= saved_ndr_pointer_list
;
3217 /* If we found the end of the list, but add_pointer_to_list extended
3218 * it, then be sure to handle those extra elements. */
3219 if (i
== (len
- 1) && (di
->pointers
.must_check_size
== true)) {
3220 len
= g_slist_length(di
->pointers
.list
);
3221 di
->pointers
.must_check_size
= false;
3225 /* We reached the end of one level, go to the level bellow if possible
3226 * reset list a level n
3228 if ((i
>= (len
- 1)) && (g_slist_length(di
->pointers
.list_list
) > original_depth
)) {
3230 /* Remove existing list */
3231 g_slist_free_full(current_ndr_pointer_list
, g_free
);
3232 list
= (GSList
*)g_slist_last(di
->pointers
.list_list
)->data
;
3233 di
->pointers
.list_list
= g_slist_remove(di
->pointers
.list_list
, list
);
3235 /* Rewind on the lower level, in theory it's not too great because we
3236 * will one more time iterate on pointers already done
3237 * In practice it shouldn't be that bad !
3240 /* Move to the next list of pointers. */
3241 current_ndr_pointer_list
= (GSList
*)g_slist_last(di
->pointers
.list_list
)->data
;
3242 len
= g_slist_length(current_ndr_pointer_list
);
3243 found_new_pointer
= 1;
3246 } while (found_new_pointer
);
3247 DISSECTOR_ASSERT(original_depth
== g_slist_length(di
->pointers
.list_list
));
3249 g_slist_free_full(di
->pointers
.list
, g_free
);
3250 /* Restore the previous list of pointers. */
3251 di
->pointers
.list
= (GSList
*)g_slist_last(di
->pointers
.list_list
)->data
;
3257 find_pointer_index(dcerpc_info
*di
, uint32_t id
)
3259 unsigned *p
= (unsigned*) g_hash_table_lookup(di
->pointers
.hash
, &id
);
3265 add_pointer_to_list(packet_info
*pinfo
, proto_tree
*tree
, proto_item
*item
,
3266 dcerpc_info
*di
, dcerpc_dissect_fnct_t
*fnct
, uint32_t id
, int hf_index
,
3267 dcerpc_callback_fnct_t
*callback
, void *callback_args
)
3269 ndr_pointer_data_t
*npd
;
3272 /* check if this pointer is valid */
3273 if (id
!= 0xffffffff) {
3274 dcerpc_call_value
*value
;
3276 value
= di
->call_data
;
3278 if (di
->ptype
== PDU_REQ
) {
3279 if (!(pinfo
->fd
->visited
)) {
3280 if (id
> value
->max_ptr
) {
3281 value
->max_ptr
= id
;
3285 /* if we haven't seen the request bail out since we can't
3286 know whether this is the first non-NULL instance
3288 if (value
->req_frame
== 0) {
3289 /* XXX THROW EXCEPTION */
3292 /* We saw this one in the request frame, nothing to
3294 if (id
<= value
->max_ptr
) {
3300 npd
= g_new(ndr_pointer_data_t
, 1);
3305 npd
->hf_index
= hf_index
;
3306 npd
->callback
= callback
;
3307 npd
->callback_args
= callback_args
;
3308 npd
->ptr_stack
= di
->ptr_stack
;
3309 npd
->switch_level
= di
->switch_level
;
3310 p_id
= wmem_new(wmem_file_scope(), unsigned);
3313 /* Update the list of pointers for use by dissect_deferred_pointers. If this
3314 * is the first pointer, create a list and add it to the stack. */
3315 if (!di
->pointers
.list
) {
3316 di
->pointers
.list
= g_slist_append(NULL
, npd
);
3317 di
->pointers
.list_list
= g_slist_append(di
->pointers
.list_list
,
3320 di
->pointers
.list
= g_slist_append(di
->pointers
.list
, npd
);
3322 g_hash_table_insert(di
->pointers
.hash
, p_id
, p_id
);
3323 di
->pointers
.must_check_size
= true;
3327 /* This function dissects an NDR pointer and stores the callback for later
3328 * deferred dissection.
3330 * fnct is the callback function for when we have reached this object in
3333 * type is what type of pointer.
3335 * this is text is what text we should put in any created tree node.
3337 * hf_index is what hf value we want to pass to the callback function when
3338 * it is called, the callback can later pick this one up from di->hf_index.
3340 * callback is executed after the pointer has been dereferenced.
3342 * callback_args is passed as an argument to the callback function
3344 * See packet-dcerpc-samr.c for examples
3347 dissect_ndr_pointer_cb(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
3348 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
, dcerpc_dissect_fnct_t
*fnct
,
3349 int type
, const char *text
, int hf_index
,
3350 dcerpc_callback_fnct_t
*callback
, void *callback_args
)
3352 proto_tree
*tr
= NULL
;
3353 int start_offset
= offset
;
3354 int pointer_size
= 4;
3356 if (di
->conformant_run
) {
3357 /* this call was only for dissecting the header for any
3358 embedded conformant array. we will not parse any
3359 pointers in this mode.
3363 if (di
->call_data
->flags
& DCERPC_IS_NDR64
) {
3368 /*TOP LEVEL REFERENCE POINTER*/
3369 if (di
->pointers
.are_top_level
3370 && (type
== NDR_POINTER_REF
) ) {
3373 /* we must find out a nice way to do the length here */
3374 tr
= proto_tree_add_subtree(tree
, tvb
, offset
, 0,
3375 ett_dcerpc_pointer_data
, &item
, text
);
3377 add_pointer_to_list(pinfo
, tr
, item
, di
, fnct
, 0xffffffff,
3378 hf_index
, callback
, callback_args
);
3382 /*TOP LEVEL FULL POINTER*/
3383 if (di
->pointers
.are_top_level
3384 && (type
== NDR_POINTER_PTR
) ) {
3389 /* get the referent id */
3390 offset
= dissect_ndr_uint3264(tvb
, offset
, pinfo
, NULL
, di
, drep
, -1, &id
);
3392 /* we got a NULL pointer */
3394 proto_tree_add_bytes_format_value(tree
, hf_dcerpc_null_pointer
, tvb
, offset
-pointer_size
,
3395 pointer_size
, NULL
, "%s", text
);
3399 /* see if we have seen this pointer before
3400 The value is truncated to 32bits. 64bit values have only been
3401 seen on fuzz-tested files */
3402 found
= find_pointer_index(di
, (uint32_t)id
);
3404 /* we have seen this pointer before */
3406 proto_tree_add_string(tree
, hf_dcerpc_duplicate_ptr
, tvb
, offset
-pointer_size
, pointer_size
, text
);
3411 tr
= proto_tree_add_subtree(tree
, tvb
, offset
-pointer_size
,
3412 pointer_size
, ett_dcerpc_pointer_data
, &item
, text
);
3413 if (di
->call_data
->flags
& DCERPC_IS_NDR64
) {
3414 proto_tree_add_uint64(tr
, hf_dcerpc_referent_id64
, tvb
,
3415 offset
-pointer_size
, pointer_size
, id
);
3417 proto_tree_add_uint(tr
, hf_dcerpc_referent_id32
, tvb
,
3418 offset
-pointer_size
, pointer_size
, (uint32_t)id
);
3420 add_pointer_to_list(pinfo
, tr
, item
, di
, fnct
, (uint32_t)id
, hf_index
,
3421 callback
, callback_args
);
3424 /*TOP LEVEL UNIQUE POINTER*/
3425 if (di
->pointers
.are_top_level
3426 && (type
== NDR_POINTER_UNIQUE
) ) {
3430 /* get the referent id */
3431 offset
= dissect_ndr_uint3264(tvb
, offset
, pinfo
, NULL
, di
, drep
, -1, &id
);
3433 /* we got a NULL pointer */
3435 proto_tree_add_bytes_format_value(tree
, hf_dcerpc_null_pointer
, tvb
, offset
-pointer_size
,
3436 pointer_size
, NULL
, "%s",text
);
3441 tr
= proto_tree_add_subtree(tree
, tvb
, offset
-pointer_size
,
3443 ett_dcerpc_pointer_data
, &item
, text
);
3444 if (di
->call_data
->flags
& DCERPC_IS_NDR64
) {
3445 proto_tree_add_uint64(tr
, hf_dcerpc_referent_id64
, tvb
,
3446 offset
-pointer_size
, pointer_size
, id
);
3448 proto_tree_add_uint(tr
, hf_dcerpc_referent_id32
, tvb
,
3449 offset
-pointer_size
, pointer_size
, (uint32_t)id
);
3451 add_pointer_to_list(pinfo
, tr
, item
, di
, fnct
, 0xffffffff,
3452 hf_index
, callback
, callback_args
);
3456 /*EMBEDDED REFERENCE POINTER*/
3457 if ((!di
->pointers
.are_top_level
)
3458 && (type
== NDR_POINTER_REF
) ) {
3462 /* get the referent id */
3463 offset
= dissect_ndr_uint3264(tvb
, offset
, pinfo
, NULL
, di
, drep
, -1, &id
);
3466 tr
= proto_tree_add_subtree(tree
, tvb
, offset
-pointer_size
,
3468 ett_dcerpc_pointer_data
,&item
,text
);
3469 if (di
->call_data
->flags
& DCERPC_IS_NDR64
) {
3470 proto_tree_add_uint64(tr
, hf_dcerpc_referent_id64
, tvb
,
3471 offset
-pointer_size
, pointer_size
, id
);
3473 proto_tree_add_uint(tr
, hf_dcerpc_referent_id32
, tvb
,
3474 offset
-pointer_size
, pointer_size
, (uint32_t)id
);
3476 add_pointer_to_list(pinfo
, tr
, item
, di
, fnct
, 0xffffffff,
3477 hf_index
, callback
, callback_args
);
3481 /*EMBEDDED UNIQUE POINTER*/
3482 if ((!di
->pointers
.are_top_level
)
3483 && (type
== NDR_POINTER_UNIQUE
) ) {
3487 /* get the referent id */
3488 offset
= dissect_ndr_uint3264(tvb
, offset
, pinfo
, NULL
, di
, drep
, -1, &id
);
3490 /* we got a NULL pointer */
3492 proto_tree_add_bytes_format_value(tree
, hf_dcerpc_null_pointer
, tvb
, offset
-pointer_size
,
3493 pointer_size
, NULL
, "%s",text
);
3498 tr
= proto_tree_add_subtree(tree
, tvb
, offset
-pointer_size
,
3500 ett_dcerpc_pointer_data
,&item
,text
);
3501 if (di
->call_data
->flags
& DCERPC_IS_NDR64
) {
3502 proto_tree_add_uint64(tr
, hf_dcerpc_referent_id64
, tvb
,
3503 offset
-pointer_size
, pointer_size
, id
);
3505 proto_tree_add_uint(tr
, hf_dcerpc_referent_id32
, tvb
,
3506 offset
-pointer_size
, pointer_size
, (uint32_t)id
);
3508 add_pointer_to_list(pinfo
, tr
, item
, di
, fnct
, 0xffffffff,
3509 hf_index
, callback
, callback_args
);
3513 /*EMBEDDED FULL POINTER*/
3514 if ((!di
->pointers
.are_top_level
)
3515 && (type
== NDR_POINTER_PTR
) ) {
3520 /* get the referent id */
3521 offset
= dissect_ndr_uint3264(tvb
, offset
, pinfo
, NULL
, di
, drep
, -1, &id
);
3523 /* we got a NULL pointer */
3525 proto_tree_add_bytes_format_value(tree
, hf_dcerpc_null_pointer
, tvb
, offset
-pointer_size
,
3526 pointer_size
, NULL
, "%s",text
);
3530 /* see if we have seen this pointer before
3531 The value is truncated to 32bits. 64bit values have only been
3532 seen on fuzztested files */
3533 found
= find_pointer_index(di
, (uint32_t)id
);
3535 /* we have seen this pointer before */
3537 proto_tree_add_string(tree
, hf_dcerpc_duplicate_ptr
, tvb
, offset
-pointer_size
, pointer_size
, text
);
3542 tr
= proto_tree_add_subtree(tree
, tvb
, offset
-pointer_size
,
3544 ett_dcerpc_pointer_data
, &item
, text
);
3545 if (di
->call_data
->flags
& DCERPC_IS_NDR64
) {
3546 proto_tree_add_uint64(tr
, hf_dcerpc_referent_id64
, tvb
,
3547 offset
-pointer_size
, pointer_size
, id
);
3549 proto_tree_add_uint(tr
, hf_dcerpc_referent_id32
, tvb
,
3550 offset
-pointer_size
, pointer_size
, (uint32_t)id
);
3552 add_pointer_to_list(pinfo
, tr
, item
, di
, fnct
, (uint32_t)id
, hf_index
,
3553 callback
, callback_args
);
3559 /* After each top level pointer we have dissected we have to
3560 dissect all deferrals before we move on to the next top level
3562 if (di
->pointers
.are_top_level
== true) {
3563 di
->pointers
.are_top_level
= false;
3564 offset
= dissect_deferred_pointers(pinfo
, tvb
, offset
, di
, drep
);
3565 di
->pointers
.are_top_level
= true;
3568 /* Set the length for the new subtree */
3570 proto_item_set_len(tr
, offset
-start_offset
);
3576 dissect_ndr_pointer(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
3577 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
, dcerpc_dissect_fnct_t
*fnct
,
3578 int type
, const char *text
, int hf_index
)
3580 return dissect_ndr_pointer_cb(
3581 tvb
, offset
, pinfo
, tree
, di
, drep
, fnct
, type
, text
, hf_index
,
3585 dissect_ndr_toplevel_pointer(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
3586 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
, dcerpc_dissect_fnct_t
*fnct
,
3587 int type
, const char *text
, int hf_index
)
3591 di
->pointers
.are_top_level
= true;
3592 ret
= dissect_ndr_pointer_cb(
3593 tvb
, offset
, pinfo
, tree
, di
, drep
, fnct
, type
, text
, hf_index
,
3598 dissect_ndr_embedded_pointer(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
3599 proto_tree
*tree
, dcerpc_info
*di
, uint8_t *drep
, dcerpc_dissect_fnct_t
*fnct
,
3600 int type
, const char *text
, int hf_index
)
3604 di
->pointers
.are_top_level
= false;
3605 ret
= dissect_ndr_pointer_cb(
3606 tvb
, offset
, pinfo
, tree
, di
, drep
, fnct
, type
, text
, hf_index
,
3612 dissect_sec_vt_bitmask(proto_tree
*tree
, tvbuff_t
*tvb
)
3614 proto_tree_add_bitmask(tree
, tvb
, 0,
3615 hf_dcerpc_sec_vt_bitmask
,
3616 ett_dcerpc_sec_vt_bitmask
,
3617 sec_vt_bitmask_fields
,
3622 dissect_sec_vt_pcontext(packet_info
*pinfo
, proto_tree
*tree
, tvbuff_t
*tvb
)
3625 proto_item
*ti
= NULL
;
3626 proto_tree
*tr
= proto_tree_add_subtree(tree
, tvb
, offset
, -1,
3627 ett_dcerpc_sec_vt_pcontext
,
3630 const char *uuid_name
;
3632 tvb_get_letohguid(tvb
, offset
, &uuid
);
3633 uuid_name
= guids_get_uuid_name(&uuid
, pinfo
->pool
);
3635 uuid_name
= guid_to_str(pinfo
->pool
, &uuid
);
3638 proto_tree_add_guid_format(tr
, hf_dcerpc_sec_vt_pcontext_uuid
, tvb
,
3639 offset
, 16, &uuid
, "Abstract Syntax: %s", uuid_name
);
3642 proto_tree_add_item(tr
, hf_dcerpc_sec_vt_pcontext_ver
,
3643 tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
3646 tvb_get_letohguid(tvb
, offset
, &uuid
);
3647 uuid_name
= guids_get_uuid_name(&uuid
, pinfo
->pool
);
3649 uuid_name
= guid_to_str(pinfo
->pool
, &uuid
);
3652 proto_tree_add_guid_format(tr
, hf_dcerpc_sec_vt_pcontext_uuid
, tvb
,
3653 offset
, 16, &uuid
, "Transfer Syntax: %s", uuid_name
);
3656 proto_tree_add_item(tr
, hf_dcerpc_sec_vt_pcontext_ver
,
3657 tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
3660 proto_item_set_len(ti
, offset
);
3664 dissect_sec_vt_header(packet_info
*pinfo
, proto_tree
*tree
, tvbuff_t
*tvb
)
3667 proto_item
*ti
= NULL
;
3668 proto_tree
*tr
= proto_tree_add_subtree(tree
, tvb
, offset
, -1,
3669 ett_dcerpc_sec_vt_header
,
3672 uint8_t ptype
= tvb_get_uint8(tvb
, offset
);
3674 proto_tree_add_uint(tr
, hf_dcerpc_packet_type
, tvb
, offset
, 1, ptype
);
3677 proto_tree_add_item(tr
, hf_dcerpc_reserved
, tvb
, offset
, 1, ENC_NA
);
3680 proto_tree_add_item(tr
, hf_dcerpc_reserved
, tvb
, offset
, 2, ENC_NA
);
3683 tvb_memcpy(tvb
, drep
, offset
, 4);
3684 proto_tree_add_dcerpc_drep(tr
, tvb
, offset
, drep
, 4);
3687 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, tr
, drep
,
3688 hf_dcerpc_cn_call_id
, NULL
);
3690 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, tr
, drep
,
3691 hf_dcerpc_cn_ctx_id
, NULL
);
3693 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, tr
, drep
,
3694 hf_dcerpc_opnum
, NULL
);
3696 proto_item_set_len(ti
, offset
);
3700 dissect_sec_vt_preauth(packet_info
*pinfo _U_
, proto_tree
*tree
, tvbuff_t
*tvb
)
3705 proto_item
*ti
= NULL
;
3706 proto_tree
*tr
= proto_tree_add_subtree(tree
, tvb
, offset
, -1,
3707 ett_dcerpc_sec_vt_preauth
,
3710 tvb_memcpy(tvb
, salt
, offset
, 16);
3711 proto_tree_add_bytes(tr
, hf_dcerpc_sec_vt_preauth_salt
, tvb
, offset
, 16, salt
);
3714 tvb_memcpy(tvb
, sha512
, offset
, 64);
3715 proto_tree_add_bytes(tr
, hf_dcerpc_sec_vt_preauth_sha512
, tvb
, offset
, 64, sha512
);
3718 proto_item_set_len(ti
, offset
);
3722 dissect_verification_trailer_impl(packet_info
*pinfo
, tvbuff_t
*tvb
, int stub_offset
,
3723 proto_tree
*parent_tree
, int *signature_offset
)
3725 int remaining
= tvb_captured_length_remaining(tvb
, stub_offset
);
3727 int signature_start
;
3730 SEC_VT_COMMAND_BITMASK_1
= 0x0001,
3731 SEC_VT_COMMAND_PCONTEXT
= 0x0002,
3732 SEC_VT_COMMAND_HEADER2
= 0x0003,
3733 SEC_VT_COMMAND_PREAUTH
= 0x0004,
3734 SEC_VT_COMMAND_END
= 0x4000,
3735 SEC_VT_MUST_PROCESS_COMMAND
= 0x8000,
3736 SEC_VT_COMMAND_MASK
= 0x3fff,
3738 proto_item
*payload_item
;
3742 if (signature_offset
!= NULL
) {
3743 *signature_offset
= -1;
3746 /* We need at least signature + the header of one command */
3747 if (remaining
< (int)(sizeof(TRAILER_SIGNATURE
) + 4)) {
3751 /* We only scan the last 512 bytes for a possible trailer */
3752 if (remaining
> 512) {
3753 offset
= remaining
- 512;
3758 offset
+= stub_offset
;
3760 signature_start
= tvb_find_tvb(tvb
, tvb_trailer_signature
, offset
);
3761 if (signature_start
== -1) {
3764 payload_length
= signature_start
- stub_offset
;
3765 payload_item
= proto_tree_add_item(parent_tree
,
3766 hf_dcerpc_payload_stub_data
,
3767 tvb
, stub_offset
, payload_length
, ENC_NA
);
3768 proto_item_append_text(payload_item
, " (%d byte%s)",
3769 payload_length
, plurality(payload_length
, "", "s"));
3771 if (signature_offset
!= NULL
) {
3772 *signature_offset
= signature_start
;
3774 remaining
-= (signature_start
- offset
);
3775 offset
= signature_start
;
3777 tree
= proto_tree_add_subtree(parent_tree
, tvb
, offset
, -1,
3778 ett_dcerpc_verification_trailer
,
3779 &item
, "Verification Trailer");
3781 proto_tree_add_item(tree
, hf_dcerpc_sec_vt_signature
,
3782 tvb
, offset
, sizeof(TRAILER_SIGNATURE
), ENC_NA
);
3783 offset
+= (int)sizeof(TRAILER_SIGNATURE
);
3784 remaining
-= (int)sizeof(TRAILER_SIGNATURE
);
3786 while (remaining
>= 4) {
3788 uint16_t len
, len_missalign
;
3789 bool cmd_end
, cmd_must
;
3792 tvbuff_t
*cmd_tvb
= NULL
;
3794 cmd
= (sec_vt_command
)tvb_get_letohs(tvb
, offset
);
3795 len
= tvb_get_letohs(tvb
, offset
+ 2);
3796 cmd_end
= cmd
& SEC_VT_COMMAND_END
;
3797 cmd_must
= cmd
& SEC_VT_MUST_PROCESS_COMMAND
;
3798 cmd
= (sec_vt_command
)(cmd
& SEC_VT_COMMAND_MASK
);
3800 tr
= proto_tree_add_subtree_format(tree
, tvb
, offset
, 4 + len
,
3801 ett_dcerpc_sec_vt_pcontext
,
3803 val_to_str(cmd
, sec_vt_command_cmd_vals
,
3804 "Unknown (0x%04x)"));
3807 proto_item_append_text(ti
, "!!!");
3810 proto_item_append_text(ti
, ", END");
3813 proto_tree_add_bitmask(tr
, tvb
, offset
,
3814 hf_dcerpc_sec_vt_command
,
3815 ett_dcerpc_sec_vt_command
,
3816 sec_vt_command_fields
,
3820 proto_tree_add_item(tr
, hf_dcerpc_sec_vt_command_length
, tvb
,
3821 offset
, 2, ENC_LITTLE_ENDIAN
);
3824 cmd_tvb
= tvb_new_subset_length(tvb
, offset
, len
);
3826 case SEC_VT_COMMAND_BITMASK_1
:
3827 dissect_sec_vt_bitmask(tr
, cmd_tvb
);
3829 case SEC_VT_COMMAND_PCONTEXT
:
3830 dissect_sec_vt_pcontext(pinfo
, tr
, cmd_tvb
);
3832 case SEC_VT_COMMAND_HEADER2
:
3833 dissect_sec_vt_header(pinfo
, tr
, cmd_tvb
);
3835 case SEC_VT_COMMAND_PREAUTH
:
3836 dissect_sec_vt_preauth(pinfo
, tr
, cmd_tvb
);
3839 proto_tree_add_item(tr
, hf_dcerpc_unknown
, cmd_tvb
, 0, len
, ENC_NA
);
3844 remaining
-= (4 + len
);
3846 len_missalign
= len
& 1;
3848 if (len_missalign
) {
3849 int l
= 2-len_missalign
;
3850 proto_tree_add_item(tr
, hf_dcerpc_missalign
, tvb
, offset
, l
, ENC_NA
);
3860 proto_item_set_end(item
, tvb
, offset
);
3865 dissect_verification_trailer(packet_info
*pinfo
, tvbuff_t
*tvb
, int stub_offset
,
3866 proto_tree
*parent_tree
, int *signature_offset
)
3868 volatile int ret
= -1;
3871 * Even if we found a signature we can't be sure to have a
3872 * valid verification trailer, we're only relatively sure
3873 * if we manage to dissect it completely, otherwise it
3874 * may be part of the real payload. That's why we have
3875 * a try/catch block here.
3877 ret
= dissect_verification_trailer_impl(pinfo
, tvb
, stub_offset
, parent_tree
, signature_offset
);
3878 } CATCH_NONFATAL_ERRORS
{
3884 dcerpc_try_handoff(packet_info
*pinfo
, proto_tree
*tree
,
3885 proto_tree
*dcerpc_tree
,
3886 tvbuff_t
*volatile tvb
, bool decrypted
,
3887 uint8_t *drep
, dcerpc_info
*info
,
3888 dcerpc_auth_info
*auth_info
)
3890 volatile int offset
= 0;
3892 dcerpc_dissector_data_t dissector_data
;
3893 proto_item
*hidden_item
;
3895 /* GUID and UUID are same size, but compiler complains about structure "name" differences */
3896 memcpy(&key
.guid
, &info
->call_data
->uuid
, sizeof(key
.guid
));
3897 key
.ver
= info
->call_data
->ver
;
3899 dissector_data
.sub_proto
= (dcerpc_uuid_value
*)g_hash_table_lookup(dcerpc_uuids
, &key
);
3900 dissector_data
.info
= info
;
3901 dissector_data
.decrypted
= decrypted
;
3902 dissector_data
.auth_info
= auth_info
;
3903 dissector_data
.drep
= drep
;
3904 dissector_data
.dcerpc_tree
= dcerpc_tree
;
3906 /* Check the dissector table before the hash table. Hopefully the hash table entries can
3907 all be converted to use dissector table */
3908 if ((dissector_data
.sub_proto
== NULL
) ||
3909 (!dissector_try_guid_new(uuid_dissector_table
, &key
, tvb
, pinfo
, tree
, false, &dissector_data
))) {
3911 * We don't have a dissector for this UUID, or the protocol
3912 * for that UUID is disabled.
3915 hidden_item
= proto_tree_add_boolean(dcerpc_tree
, hf_dcerpc_unknown_if_id
,
3916 tvb
, offset
, 0, true);
3917 proto_item_set_hidden(hidden_item
);
3918 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " %s V%u",
3919 guids_resolve_guid_to_str(&info
->call_data
->uuid
, pinfo
->pool
), info
->call_data
->ver
);
3921 show_stub_data(pinfo
, tvb
, 0, dcerpc_tree
, auth_info
, !decrypted
);
3925 tap_queue_packet(dcerpc_tap
, pinfo
, info
);
3930 dissect_dcerpc_cn_auth_move(dcerpc_auth_info
*auth_info
, proto_tree
*dcerpc_tree
)
3932 if (auth_info
->auth_item
!= NULL
) {
3933 proto_item
*last_item
= proto_tree_add_item(dcerpc_tree
, hf_dcerpc_auth_info
,
3934 auth_info
->auth_tvb
, 0, 0, ENC_NA
);
3935 if (last_item
!= NULL
) {
3936 proto_item_set_hidden(last_item
);
3937 proto_tree_move_item(dcerpc_tree
, last_item
, auth_info
->auth_item
);
3942 static dcerpc_connection
*find_or_create_dcerpc_connection(packet_info
*pinfo
)
3944 dcerpc_connection connection_key
= {
3945 .conv
= find_or_create_conversation(pinfo
),
3946 .transport_salt
= dcerpc_get_transport_salt(pinfo
),
3947 .first_frame
= UINT32_MAX
,
3949 dcerpc_connection
*connection
= NULL
;
3951 connection
= (dcerpc_connection
*)wmem_map_lookup(dcerpc_connections
, &connection_key
);
3952 if (connection
!= NULL
) {
3956 connection
= wmem_new(wmem_file_scope(), dcerpc_connection
);
3957 if (connection
== NULL
) {
3961 *connection
= connection_key
;
3962 wmem_map_insert(dcerpc_connections
, connection
, connection
);
3965 if (pinfo
->fd
->num
< connection
->first_frame
) {
3966 connection
->first_frame
= pinfo
->fd
->num
;
3971 static dcerpc_auth_context
*find_or_create_dcerpc_auth_context(packet_info
*pinfo
,
3972 dcerpc_auth_info
*auth_info
)
3974 dcerpc_auth_context auth_key
= {
3975 .conv
= find_or_create_conversation(pinfo
),
3976 .transport_salt
= dcerpc_get_transport_salt(pinfo
),
3977 .auth_type
= auth_info
->auth_type
,
3978 .auth_level
= auth_info
->auth_level
,
3979 .auth_context_id
= auth_info
->auth_context_id
,
3980 .first_frame
= UINT32_MAX
,
3982 dcerpc_auth_context
*auth_value
= NULL
;
3984 auth_value
= (dcerpc_auth_context
*)wmem_map_lookup(dcerpc_auths
, &auth_key
);
3985 if (auth_value
!= NULL
) {
3989 auth_value
= wmem_new(wmem_file_scope(), dcerpc_auth_context
);
3990 if (auth_value
== NULL
) {
3994 *auth_value
= auth_key
;
3995 wmem_map_insert(dcerpc_auths
, auth_value
, auth_value
);
3998 if (pinfo
->fd
->num
< auth_value
->first_frame
) {
3999 auth_value
->first_frame
= pinfo
->fd
->num
;
4005 dissect_dcerpc_cn_auth(tvbuff_t
*tvb
, int stub_offset
, packet_info
*pinfo
,
4006 proto_tree
*dcerpc_tree
, e_dce_cn_common_hdr_t
*hdr
,
4007 dcerpc_auth_info
*auth_info
)
4009 volatile int offset
;
4012 * Initially set auth_level and auth_type to zero to indicate that we
4013 * haven't yet seen any authentication level information.
4015 auth_info
->hdr_signing
= false;
4016 auth_info
->auth_type
= 0;
4017 auth_info
->auth_level
= 0;
4018 auth_info
->auth_context_id
= 0;
4019 auth_info
->auth_pad_len
= 0;
4020 auth_info
->auth_size
= 0;
4021 auth_info
->auth_fns
= NULL
;
4022 auth_info
->auth_tvb
= NULL
;
4023 auth_info
->auth_item
= NULL
;
4024 auth_info
->auth_tree
= NULL
;
4025 auth_info
->auth_hdr_tvb
= NULL
;
4028 * The authentication information is at the *end* of the PDU; in
4029 * request and response PDUs, the request and response stub data
4032 * Is there any authentication data (i.e., is the authentication length
4033 * non-zero), and is the authentication length valid (i.e., is it, plus
4034 * 8 bytes for the type/level/pad length/reserved/context id, less than
4035 * or equal to the fragment length minus the starting offset of the
4040 && ((hdr
->auth_len
+ 8) <= (hdr
->frag_len
- stub_offset
))) {
4043 * Yes, there is authentication data, and the length is valid.
4044 * Do we have all the bytes of stub data?
4045 * (If not, we'd throw an exception dissecting *that*, so don't
4046 * bother trying to dissect the authentication information and
4047 * throwing another exception there.)
4049 offset
= hdr
->frag_len
- (hdr
->auth_len
+ 8);
4050 if (offset
== 0 || tvb_offset_exists(tvb
, offset
- 1)) {
4051 dcerpc_connection
*connection
= NULL
;
4052 dcerpc_auth_context
*auth_context
= NULL
;
4053 int auth_offset
= offset
;
4055 /* Compute the size of the auth block. Note that this should not
4056 include auth padding, since when NTLMSSP encryption is used, the
4057 padding is actually inside the encrypted stub */
4058 auth_info
->auth_size
= hdr
->auth_len
+ 8;
4060 auth_info
->auth_item
= proto_tree_add_item(dcerpc_tree
, hf_dcerpc_auth_info
,
4061 tvb
, offset
, auth_info
->auth_size
, ENC_NA
);
4062 auth_info
->auth_tree
= proto_item_add_subtree(auth_info
->auth_item
, ett_dcerpc_auth_info
);
4065 * Either there's no stub data, or the last byte of the stub
4066 * data is present in the captured data, so we shouldn't
4067 * get a BoundsError dissecting the stub data.
4069 * Try dissecting the authentication data.
4070 * Catch all exceptions, so that even if the auth info is bad
4071 * or we don't have all of it, we still show the stuff we
4072 * dissect after this, such as stub data.
4075 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, auth_info
->auth_tree
, hdr
->drep
,
4076 hf_dcerpc_auth_type
,
4077 &auth_info
->auth_type
);
4078 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, auth_info
->auth_tree
, hdr
->drep
,
4079 hf_dcerpc_auth_level
,
4080 &auth_info
->auth_level
);
4082 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, auth_info
->auth_tree
, hdr
->drep
,
4083 hf_dcerpc_auth_pad_len
,
4084 &auth_info
->auth_pad_len
);
4085 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, auth_info
->auth_tree
, hdr
->drep
,
4086 hf_dcerpc_auth_rsrvd
, NULL
);
4087 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, auth_info
->auth_tree
, hdr
->drep
,
4088 hf_dcerpc_auth_ctx_id
,
4089 &auth_info
->auth_context_id
);
4091 proto_item_append_text(auth_info
->auth_item
,
4092 ": %s, %s, AuthContextId(%d)",
4093 val_to_str(auth_info
->auth_type
,
4094 authn_protocol_vals
,
4096 val_to_str(auth_info
->auth_level
,
4099 auth_info
->auth_context_id
);
4102 * Dissect the authentication data.
4104 auth_info
->auth_hdr_tvb
= tvb_new_subset_length_caplen(tvb
, auth_offset
, 8, 8);
4105 auth_info
->auth_tvb
= tvb_new_subset_length_caplen(tvb
, offset
,
4106 MIN(hdr
->auth_len
,tvb_reported_length_remaining(tvb
, offset
)),
4109 connection
= find_or_create_dcerpc_connection(pinfo
);
4110 auth_context
= find_or_create_dcerpc_auth_context(pinfo
, auth_info
);
4111 if (auth_context
!= NULL
) {
4112 if (hdr
->ptype
== PDU_BIND
|| hdr
->ptype
== PDU_ALTER
) {
4113 if (auth_context
->first_frame
== pinfo
->fd
->num
) {
4114 auth_context
->hdr_signing
= (hdr
->flags
& PFC_HDR_SIGNING
);
4115 if (auth_context
->hdr_signing
&& connection
!= NULL
) {
4116 connection
->hdr_signing_negotiated
= true;
4120 if (connection
!= NULL
&& connection
->hdr_signing_negotiated
) {
4121 auth_context
->hdr_signing
= true;
4124 auth_info
->hdr_signing
= auth_context
->hdr_signing
;
4127 auth_info
->auth_fns
= get_auth_subdissector_fns(auth_info
->auth_level
,
4128 auth_info
->auth_type
);
4129 if (auth_info
->auth_fns
!= NULL
)
4130 dissect_auth_verf(pinfo
, hdr
, auth_info
);
4132 proto_tree_add_item(auth_info
->auth_tree
,
4133 hf_dcerpc_auth_credentials
,
4134 auth_info
->auth_tvb
, 0,
4135 hdr
->auth_len
, ENC_NA
);
4137 } CATCH_BOUNDS_ERRORS
{
4138 show_exception(tvb
, pinfo
, dcerpc_tree
, EXCEPT_CODE
, GET_MESSAGE
);
4145 /* We need to hash in the SMB fid number to generate a unique hash table
4146 * key as DCERPC over SMB allows several pipes over the same TCP/IP
4148 * We pass this function the transport type here to make sure we only look
4149 * at this function if it came across an SMB pipe.
4150 * Other transports might need to mix in their own extra multiplexing data
4151 * as well in the future.
4155 dcerpc_get_transport_salt(packet_info
*pinfo
)
4157 dcerpc_decode_as_data
* decode_data
= dcerpc_get_decode_data(pinfo
);
4159 switch (decode_data
->dcetransporttype
) {
4160 case DCE_CN_TRANSPORT_SMBPIPE
:
4161 /* DCERPC over smb */
4162 return decode_data
->dcetransportsalt
;
4165 /* Some other transport... */
4170 dcerpc_set_transport_salt(uint64_t dcetransportsalt
, packet_info
*pinfo
)
4172 dcerpc_decode_as_data
* decode_data
= dcerpc_get_decode_data(pinfo
);
4174 decode_data
->dcetransportsalt
= dcetransportsalt
;
4178 * Connection oriented packet types
4182 dissect_dcerpc_cn_bind(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
4183 proto_tree
*dcerpc_tree
, e_dce_cn_common_hdr_t
*hdr
)
4185 conversation_t
*conv
= find_or_create_conversation(pinfo
);
4186 uint8_t num_ctx_items
= 0;
4189 uint8_t num_trans_items
;
4194 uint16_t if_ver
, if_ver_minor
;
4195 dcerpc_auth_info auth_info
;
4197 const char *uuid_name
= NULL
;
4198 proto_item
*iface_item
= NULL
;
4199 dcerpc_decode_as_data
* decode_data
= dcerpc_get_decode_data(pinfo
);
4201 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4202 hf_dcerpc_cn_max_xmit
, NULL
);
4204 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4205 hf_dcerpc_cn_max_recv
, NULL
);
4207 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4208 hf_dcerpc_cn_assoc_group
, NULL
);
4210 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4211 hf_dcerpc_cn_num_ctx_items
, &num_ctx_items
);
4216 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", %u context items:", num_ctx_items
);
4218 for (i
= 0; i
< num_ctx_items
; i
++) {
4219 proto_item
*ctx_item
= NULL
;
4220 proto_tree
*ctx_tree
= NULL
, *iface_tree
= NULL
;
4221 int ctx_offset
= offset
;
4223 dissect_dcerpc_uint16(tvb
, offset
, pinfo
, NULL
, hdr
->drep
,
4224 hf_dcerpc_cn_ctx_id
, &ctx_id
);
4226 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
4227 /* (if we have multiple contexts, this might cause "decode as"
4228 * to behave unpredictably) */
4229 decode_data
->dcectxid
= ctx_id
;
4232 ctx_item
= proto_tree_add_item(dcerpc_tree
, hf_dcerpc_cn_ctx_item
,
4235 ctx_tree
= proto_item_add_subtree(ctx_item
, ett_dcerpc_cn_ctx
);
4238 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, ctx_tree
, hdr
->drep
,
4239 hf_dcerpc_cn_ctx_id
, &ctx_id
);
4240 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, ctx_tree
, hdr
->drep
,
4241 hf_dcerpc_cn_num_trans_items
, &num_trans_items
);
4244 proto_item_append_text(ctx_item
, "[%u]: Context ID:%u", i
+1, ctx_id
);
4250 dcerpc_tvb_get_uuid(tvb
, offset
, hdr
->drep
, &if_id
);
4253 iface_item
= proto_tree_add_item(ctx_tree
, hf_dcerpc_cn_bind_abstract_syntax
, tvb
, offset
, 0, ENC_NA
);
4254 iface_tree
= proto_item_add_subtree(iface_item
, ett_dcerpc_cn_iface
);
4256 uuid_str
= guid_to_str(pinfo
->pool
, (e_guid_t
*)&if_id
);
4257 uuid_name
= guids_get_uuid_name(&if_id
, pinfo
->pool
);
4259 proto_tree_add_guid_format(iface_tree
, hf_dcerpc_cn_bind_if_id
, tvb
,
4260 offset
, 16, (e_guid_t
*) &if_id
, "Interface: %s UUID: %s", uuid_name
, uuid_str
);
4261 proto_item_append_text(iface_item
, ": %s", uuid_name
);
4262 proto_item_append_text(ctx_item
, ", %s", uuid_name
);
4264 proto_tree_add_guid_format(iface_tree
, hf_dcerpc_cn_bind_if_id
, tvb
,
4265 offset
, 16, (e_guid_t
*) &if_id
, "Interface UUID: %s", uuid_str
);
4266 proto_item_append_text(iface_item
, ": %s", uuid_str
);
4267 proto_item_append_text(ctx_item
, ", %s", uuid_str
);
4272 if (hdr
->drep
[0] & DREP_LITTLE_ENDIAN
) {
4273 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, iface_tree
, hdr
->drep
,
4274 hf_dcerpc_cn_bind_if_ver
, &if_ver
);
4275 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, iface_tree
, hdr
->drep
,
4276 hf_dcerpc_cn_bind_if_ver_minor
, &if_ver_minor
);
4278 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, iface_tree
, hdr
->drep
,
4279 hf_dcerpc_cn_bind_if_ver_minor
, &if_ver_minor
);
4280 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, iface_tree
, hdr
->drep
,
4281 hf_dcerpc_cn_bind_if_ver
, &if_ver
);
4285 proto_item_append_text(iface_item
, " V%u.%u", if_ver
, if_ver_minor
);
4286 proto_item_set_len(iface_item
, 20);
4289 memset(&trans_id
, 0, sizeof(trans_id
));
4290 for (j
= 0; j
< num_trans_items
; j
++) {
4291 proto_tree
*trans_tree
= NULL
;
4292 proto_item
*trans_item
= NULL
;
4294 dcerpc_tvb_get_uuid(tvb
, offset
, hdr
->drep
, &trans_id
);
4297 trans_item
= proto_tree_add_item(ctx_tree
, hf_dcerpc_cn_bind_trans_syntax
, tvb
, offset
, 0, ENC_NA
);
4298 trans_tree
= proto_item_add_subtree(trans_item
, ett_dcerpc_cn_trans_syntax
);
4300 uuid_str
= guid_to_str(pinfo
->pool
, (e_guid_t
*) &trans_id
);
4301 uuid_name
= guids_get_uuid_name(&trans_id
, pinfo
->pool
);
4303 /* check for [MS-RPCE] 3.3.1.5.3 Bind Time Feature Negotiation */
4304 if (trans_id
.data1
== 0x6cb71c2c && trans_id
.data2
== 0x9812 && trans_id
.data3
== 0x4540) {
4305 proto_tree_add_guid_format(trans_tree
, hf_dcerpc_cn_bind_trans_id
,
4306 tvb
, offset
, 16, (e_guid_t
*) &trans_id
,
4307 "Transfer Syntax: Bind Time Feature Negotiation UUID:%s",
4309 proto_tree_add_bitmask(trans_tree
, tvb
, offset
+ 8,
4310 hf_dcerpc_cn_bind_trans_btfn
,
4311 ett_dcerpc_cn_bind_trans_btfn
,
4312 dcerpc_cn_bind_trans_btfn_fields
,
4314 proto_item_append_text(trans_item
, "[%u]: Bind Time Feature Negotiation", j
+1);
4315 proto_item_append_text(ctx_item
, ", Bind Time Feature Negotiation");
4316 } else if (uuid_name
) {
4317 proto_tree_add_guid_format(trans_tree
, hf_dcerpc_cn_bind_trans_id
,
4318 tvb
, offset
, 16, (e_guid_t
*) &trans_id
,
4319 "Transfer Syntax: %s UUID:%s", uuid_name
, uuid_str
);
4320 proto_item_append_text(trans_item
, "[%u]: %s", j
+1, uuid_name
);
4321 proto_item_append_text(ctx_item
, ", %s", uuid_name
);
4323 proto_tree_add_guid_format(trans_tree
, hf_dcerpc_cn_bind_trans_id
,
4324 tvb
, offset
, 16, (e_guid_t
*) &trans_id
,
4325 "Transfer Syntax: %s", uuid_str
);
4326 proto_item_append_text(trans_item
, "[%u]: %s", j
+1, uuid_str
);
4327 proto_item_append_text(ctx_item
, ", %s", uuid_str
);
4333 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, trans_tree
, hdr
->drep
,
4334 hf_dcerpc_cn_bind_trans_ver
, &trans_ver
);
4336 proto_item_set_len(trans_item
, 20);
4337 proto_item_append_text(trans_item
, " V%u", trans_ver
);
4341 /* if this is the first time we've seen this packet, we need to
4342 update the dcerpc_binds table so that any later calls can
4343 match to the interface.
4344 XXX We assume that BINDs will NEVER be fragmented.
4346 if (!(pinfo
->fd
->visited
)) {
4347 dcerpc_bind_key
*key
;
4348 dcerpc_bind_value
*value
;
4350 key
= wmem_new(wmem_file_scope(), dcerpc_bind_key
);
4352 key
->ctx_id
= ctx_id
;
4353 key
->transport_salt
= dcerpc_get_transport_salt(pinfo
);
4355 value
= wmem_new(wmem_file_scope(), dcerpc_bind_value
);
4356 value
->uuid
= if_id
;
4357 value
->ver
= if_ver
;
4358 value
->transport
= trans_id
;
4360 /* add this entry to the bind table */
4361 wmem_map_insert(dcerpc_binds
, key
, value
);
4365 col_append_str(pinfo
->cinfo
, COL_INFO
, ",");
4367 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " %s V%u.%u (%s)",
4368 guids_resolve_guid_to_str(&if_id
, pinfo
->pool
), if_ver
, if_ver_minor
,
4369 guids_resolve_guid_to_str(&trans_id
, pinfo
->pool
));
4372 proto_item_set_len(ctx_item
, offset
- ctx_offset
);
4377 * XXX - we should save the authentication type *if* we have
4378 * an authentication header, and associate it with an authentication
4379 * context, so subsequent PDUs can use that context.
4381 dissect_dcerpc_cn_auth(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
, &auth_info
);
4385 dissect_dcerpc_cn_bind_ack(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
4386 proto_tree
*dcerpc_tree
, e_dce_cn_common_hdr_t
*hdr
)
4388 uint16_t max_xmit
, max_recv
;
4389 uint16_t sec_addr_len
;
4390 uint8_t num_results
;
4392 uint16_t result
= 0;
4393 uint16_t reason
= 0;
4396 dcerpc_auth_info auth_info
;
4397 const char *uuid_name
= NULL
;
4398 const char *result_str
= NULL
;
4400 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4401 hf_dcerpc_cn_max_xmit
, &max_xmit
);
4403 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4404 hf_dcerpc_cn_max_recv
, &max_recv
);
4406 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4407 hf_dcerpc_cn_assoc_group
, NULL
);
4409 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4410 hf_dcerpc_cn_sec_addr_len
, &sec_addr_len
);
4411 if (sec_addr_len
!= 0) {
4412 proto_tree_add_item(dcerpc_tree
, hf_dcerpc_cn_sec_addr
, tvb
, offset
,
4413 sec_addr_len
, ENC_ASCII
);
4414 offset
+= sec_addr_len
;
4418 offset
+= 4 - offset
% 4;
4421 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4422 hf_dcerpc_cn_num_results
, &num_results
);
4427 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", max_xmit: %u max_recv: %u, %u results:",
4428 max_xmit
, max_recv
, num_results
);
4430 for (i
= 0; i
< num_results
; i
++) {
4431 proto_tree
*ctx_tree
= NULL
;
4432 proto_item
*ctx_item
= NULL
;
4435 ctx_tree
= proto_tree_add_subtree_format(dcerpc_tree
, tvb
, offset
, 24, ett_dcerpc_cn_ctx
, &ctx_item
, "Ctx Item[%u]:", i
+1);
4438 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, ctx_tree
,
4439 hdr
->drep
, hf_dcerpc_cn_ack_result
,
4442 /* [MS-RPCE] 3.3.1.5.3 check if this Ctx Item is the response to a Bind Time Feature Negotiation request */
4444 proto_tree_add_bitmask(ctx_tree
, tvb
, offset
,
4445 hf_dcerpc_cn_bind_trans_btfn
,
4446 ett_dcerpc_cn_bind_trans_btfn
,
4447 dcerpc_cn_bind_trans_btfn_fields
,
4450 } else if (result
!= 0) {
4451 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, ctx_tree
,
4452 hdr
->drep
, hf_dcerpc_cn_ack_reason
,
4456 * The reason for rejection isn't meaningful, and often isn't
4457 * set, when the syntax was accepted.
4462 result_str
= val_to_str(result
, p_cont_result_vals
, "Unknown result (%u)");
4465 dcerpc_tvb_get_uuid(tvb
, offset
, hdr
->drep
, &trans_id
);
4466 uuid_name
= guids_get_uuid_name(&trans_id
, pinfo
->pool
);
4468 uuid_name
= guid_to_str(pinfo
->pool
, (e_guid_t
*) &trans_id
);
4470 proto_tree_add_guid_format(ctx_tree
, hf_dcerpc_cn_ack_trans_id
, tvb
,
4471 offset
, 16, (e_guid_t
*) &trans_id
, "Transfer Syntax: %s",
4473 proto_item_append_text(ctx_item
, " %s, %s", result_str
, uuid_name
);
4477 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, ctx_tree
, hdr
->drep
,
4478 hf_dcerpc_cn_ack_trans_ver
, &trans_ver
);
4481 col_append_str(pinfo
->cinfo
, COL_INFO
, ",");
4483 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " %s", result_str
);
4487 * XXX - do we need to do anything with the authentication level
4488 * we get back from this?
4490 dissect_dcerpc_cn_auth(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
, &auth_info
);
4494 dissect_dcerpc_cn_bind_nak(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
4495 proto_tree
*dcerpc_tree
, e_dce_cn_common_hdr_t
*hdr
)
4498 uint8_t num_protocols
;
4501 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
,
4502 hdr
->drep
, hf_dcerpc_cn_reject_reason
,
4505 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " reason: %s",
4506 val_to_str(reason
, reject_reason_vals
, "Unknown (%u)"));
4508 if (reason
== PROTOCOL_VERSION_NOT_SUPPORTED
) {
4509 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4510 hf_dcerpc_cn_num_protocols
,
4513 for (i
= 0; i
< num_protocols
; i
++) {
4514 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, dcerpc_tree
,
4515 hdr
->drep
, hf_dcerpc_cn_protocol_ver_major
,
4517 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, dcerpc_tree
,
4518 hdr
->drep
, hf_dcerpc_cn_protocol_ver_minor
,
4524 /* Return a string describing a DCE/RPC fragment as first, middle, or end
4527 #define PFC_FRAG_MASK 0x03
4530 fragment_type(uint8_t flags
)
4532 static const char* t
[4] = {
4538 return t
[flags
& PFC_FRAG_MASK
];
4541 /* Dissect stub data (payload) of a DCERPC packet. */
4544 dissect_dcerpc_cn_stub(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
4545 proto_tree
*dcerpc_tree
, proto_tree
*tree
,
4546 e_dce_cn_common_hdr_t
*hdr
, dcerpc_info
*di
,
4547 dcerpc_auth_info
*auth_info
, uint32_t alloc_hint _U_
,
4550 int length
, reported_length
;
4551 bool save_fragmented
;
4552 fragment_head
*fd_head
= NULL
;
4554 tvbuff_t
*header_tvb
= NULL
, *trailer_tvb
= NULL
;
4555 tvbuff_t
*payload_tvb
, *decrypted_tvb
= NULL
;
4557 proto_item
*parent_pi
;
4558 proto_item
*dcerpc_tree_item
;
4560 save_fragmented
= pinfo
->fragmented
;
4562 length
= tvb_reported_length_remaining(tvb
, offset
);
4563 reported_length
= tvb_reported_length_remaining(tvb
, offset
);
4564 if (reported_length
< 0 ||
4565 (uint32_t)reported_length
< auth_info
->auth_size
) {
4566 /* We don't even have enough bytes for the authentication
4570 reported_length
-= auth_info
->auth_size
;
4571 if (length
> reported_length
)
4572 length
= reported_length
;
4573 header_tvb
= tvb_new_subset_length_caplen(tvb
, 0, offset
, offset
);
4574 payload_tvb
= tvb_new_subset_length_caplen(tvb
, offset
, length
, reported_length
);
4575 trailer_tvb
= auth_info
->auth_hdr_tvb
;
4577 /* Decrypt the PDU if it is encrypted */
4579 if (auth_info
->auth_type
&&
4580 (auth_info
->auth_level
== DCE_C_AUTHN_LEVEL_PKT_PRIVACY
)) {
4582 /* Start out assuming we won't succeed in decrypting. */
4584 if (auth_info
->auth_fns
!= NULL
) {
4587 result
= decode_encrypted_data(header_tvb
, payload_tvb
, trailer_tvb
,
4588 pinfo
, hdr
, auth_info
);
4590 proto_tree_add_item(dcerpc_tree
, hf_dcerpc_encrypted_stub_data
, payload_tvb
, 0, -1, ENC_NA
);
4592 add_new_data_source(
4593 pinfo
, result
, "Decrypted stub data");
4596 decrypted_tvb
= result
;
4600 decrypted_tvb
= payload_tvb
;
4602 /* if this packet is not fragmented, just dissect it and exit */
4603 if (PFC_NOT_FRAGMENTED(hdr
)) {
4604 pinfo
->fragmented
= false;
4606 dcerpc_try_handoff(pinfo
, tree
, dcerpc_tree
,
4607 ((decrypted_tvb
!= NULL
) ? decrypted_tvb
: payload_tvb
),
4608 ((decrypted_tvb
!= NULL
) ? true : false),
4609 hdr
->drep
, di
, auth_info
);
4611 pinfo
->fragmented
= save_fragmented
;
4615 /* The packet is fragmented. */
4616 pinfo
->fragmented
= true;
4618 /* debug output of essential fragment data. */
4619 /* leave it here for future debugging sessions */
4620 /*printf("DCE num:%u offset:%u frag_len:%u tvb_len:%u\n",
4621 pinfo->num, offset, hdr->frag_len, tvb_reported_length(decrypted_tvb));*/
4623 /* if we are not doing reassembly and this is the first fragment
4624 then just dissect it and exit
4625 XXX - if we're not doing reassembly, can we decrypt an
4628 if ( (!dcerpc_reassemble
) && (hdr
->flags
& PFC_FIRST_FRAG
) ) {
4630 dcerpc_try_handoff(pinfo
, tree
, dcerpc_tree
,
4631 ((decrypted_tvb
!= NULL
) ? decrypted_tvb
: payload_tvb
),
4632 ((decrypted_tvb
!= NULL
) ? true : false),
4633 hdr
->drep
, di
, auth_info
);
4635 expert_add_info_format(pinfo
, NULL
, &ei_dcerpc_fragment
, "%s fragment", fragment_type(hdr
->flags
));
4637 pinfo
->fragmented
= save_fragmented
;
4641 /* if we have already seen this packet, see if it was reassembled
4642 and if so dissect the full pdu.
4645 if (pinfo
->fd
->visited
) {
4646 fd_head
= fragment_get_reassembled_id(&dcerpc_co_reassembly_table
, pinfo
, frame
);
4650 /* if we are not doing reassembly and it was neither a complete PDU
4651 nor the first fragment then there is nothing more we can do
4652 so we just have to exit
4654 if ( !dcerpc_reassemble
|| (tvb_captured_length(tvb
) != tvb_reported_length(tvb
)) )
4657 /* if we didn't get 'frame' we don't know where the PDU started and thus
4658 it is pointless to continue
4663 /* from now on we must attempt to reassemble the PDU
4666 /* if we get here we know it is the first time we see the packet
4667 and we also know it is only a fragment and not a full PDU,
4668 thus we must reassemble it.
4671 /* Do we have any non-encrypted data to reassemble? */
4672 if (decrypted_tvb
== NULL
) {
4673 /* No. We can't even try to reassemble. */
4677 /* defragmentation is a bit tricky, as there's no offset of the fragment
4678 * in the protocol data.
4680 * just use fragment_add_seq_next() and hope that TCP/SMB segments coming
4681 * in with the correct sequence.
4683 fd_head
= fragment_add_seq_next(&dcerpc_co_reassembly_table
,
4684 decrypted_tvb
, 0, pinfo
, frame
, NULL
,
4685 tvb_reported_length(decrypted_tvb
),
4686 !(hdr
->flags
& PFC_LAST_FRAG
) /* more_frags */);
4690 /* if reassembly is complete and this is the last fragment
4691 * (multiple fragments in one PDU are possible!)
4692 * dissect the full PDU
4694 if (fd_head
&& (fd_head
->flags
& FD_DEFRAGMENTED
) ) {
4696 if ((pinfo
->num
== fd_head
->reassembled_in
) && (hdr
->flags
& PFC_LAST_FRAG
) ) {
4698 proto_item
*frag_tree_item
;
4700 next_tvb
= tvb_new_chain((decrypted_tvb
)?decrypted_tvb
:payload_tvb
,
4703 add_new_data_source(pinfo
, next_tvb
, "Reassembled DCE/RPC");
4704 show_fragment_tree(fd_head
, &dcerpc_frag_items
,
4705 tree
, pinfo
, next_tvb
, &frag_tree_item
);
4706 /* the toplevel fragment subtree is now behind all desegmented data,
4707 * move it right behind the DCE/RPC tree */
4708 dcerpc_tree_item
= proto_tree_get_parent(dcerpc_tree
);
4709 if (frag_tree_item
&& dcerpc_tree_item
) {
4710 proto_tree_move_item(tree
, dcerpc_tree_item
, frag_tree_item
);
4713 pinfo
->fragmented
= false;
4715 expert_add_info_format(pinfo
, frag_tree_item
, &ei_dcerpc_fragment_reassembled
, "%s fragment, reassembled", fragment_type(hdr
->flags
));
4717 dcerpc_try_handoff(pinfo
, tree
, dcerpc_tree
, next_tvb
, true, hdr
->drep
, di
, auth_info
);
4720 if (decrypted_tvb
) {
4721 pi
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_reassembled_in
,
4722 decrypted_tvb
, 0, 0, fd_head
->reassembled_in
);
4724 pi
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_reassembled_in
,
4725 payload_tvb
, 0, 0, fd_head
->reassembled_in
);
4727 proto_item_set_generated(pi
);
4728 parent_pi
= proto_tree_get_parent(dcerpc_tree
);
4729 if (parent_pi
!= NULL
) {
4730 proto_item_append_text(parent_pi
, ", [Reas: #%u]", fd_head
->reassembled_in
);
4732 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
4733 " [DCE/RPC %s fragment, reas: #%u]", fragment_type(hdr
->flags
), fd_head
->reassembled_in
);
4734 expert_add_info_format(pinfo
, NULL
, &ei_dcerpc_fragment_reassembled
, "%s fragment, reassembled in #%u", fragment_type(hdr
->flags
), fd_head
->reassembled_in
);
4737 /* Reassembly not complete - some fragments
4738 are missing. Just show the stub data. */
4739 expert_add_info_format(pinfo
, NULL
, &ei_dcerpc_fragment
, "%s fragment", fragment_type(hdr
->flags
));
4741 if (decrypted_tvb
) {
4742 show_stub_data(pinfo
, decrypted_tvb
, 0, tree
, auth_info
, false);
4744 show_stub_data(pinfo
, payload_tvb
, 0, tree
, auth_info
, true);
4748 pinfo
->fragmented
= save_fragmented
;
4752 dissect_dcerpc_cn_rqst(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
4753 proto_tree
*dcerpc_tree
, proto_tree
*tree
,
4754 e_dce_cn_common_hdr_t
*hdr
)
4756 conversation_t
*conv
;
4759 e_guid_t obj_id
= DCERPC_UUID_NULL
;
4760 dcerpc_auth_info auth_info
;
4761 uint32_t alloc_hint
;
4763 proto_item
*parent_pi
;
4764 dcerpc_decode_as_data
* decode_data
= dcerpc_get_decode_data(pinfo
);
4766 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4767 hf_dcerpc_cn_alloc_hint
, &alloc_hint
);
4769 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4770 hf_dcerpc_cn_ctx_id
, &ctx_id
);
4771 parent_pi
= proto_tree_get_parent(dcerpc_tree
);
4772 if (parent_pi
!= NULL
) {
4773 proto_item_append_text(parent_pi
, ", Ctx: %u", ctx_id
);
4776 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4777 hf_dcerpc_opnum
, &opnum
);
4779 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
4780 decode_data
->dcectxid
= ctx_id
;
4782 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", opnum: %u, Ctx: %u",
4785 if (hdr
->flags
& PFC_OBJECT_UUID
) {
4786 dcerpc_tvb_get_uuid(tvb
, offset
, hdr
->drep
, &obj_id
);
4788 proto_tree_add_guid_format(dcerpc_tree
, hf_dcerpc_obj_id
, tvb
,
4789 offset
, 16, (e_guid_t
*) &obj_id
, "Object UUID: %s",
4790 guid_to_str(pinfo
->pool
, (e_guid_t
*) &obj_id
));
4796 * XXX - what if this was set when the connection was set up,
4797 * and we just have a security context?
4799 dissect_dcerpc_cn_auth(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
, &auth_info
);
4801 conv
= find_conversation_pinfo(pinfo
, 0);
4803 show_stub_data(pinfo
, tvb
, offset
, dcerpc_tree
, &auth_info
, true);
4805 dcerpc_matched_key matched_key
, *new_matched_key
;
4806 dcerpc_call_value
*value
;
4808 /* !!! we can NOT check visited here since this will interact
4809 badly with when SMB handles (i.e. calls the subdissector)
4810 and desegmented pdu's .
4811 Instead we check if this pdu is already in the matched table or not
4813 matched_key
.frame
= pinfo
->num
;
4814 matched_key
.call_id
= hdr
->call_id
;
4815 value
= (dcerpc_call_value
*)wmem_map_lookup(dcerpc_matched
, &matched_key
);
4817 dcerpc_bind_key bind_key
;
4818 dcerpc_bind_value
*bind_value
;
4820 bind_key
.conv
= conv
;
4821 bind_key
.ctx_id
= ctx_id
;
4822 bind_key
.transport_salt
= dcerpc_get_transport_salt(pinfo
);
4824 if ((bind_value
= (dcerpc_bind_value
*)wmem_map_lookup(dcerpc_binds
, &bind_key
)) ) {
4825 if (!(hdr
->flags
&PFC_FIRST_FRAG
)) {
4826 dcerpc_cn_call_key call_key
;
4827 dcerpc_call_value
*call_value
;
4829 call_key
.conv
= conv
;
4830 call_key
.call_id
= hdr
->call_id
;
4831 call_key
.transport_salt
= dcerpc_get_transport_salt(pinfo
);
4832 if ((call_value
= (dcerpc_call_value
*)wmem_map_lookup(dcerpc_cn_calls
, &call_key
))) {
4833 new_matched_key
= wmem_new(wmem_file_scope(), dcerpc_matched_key
);
4834 *new_matched_key
= matched_key
;
4835 wmem_map_insert(dcerpc_matched
, new_matched_key
, call_value
);
4839 dcerpc_cn_call_key
*call_key
;
4840 dcerpc_call_value
*call_value
;
4842 /* We found the binding and it is the first fragment
4843 (or a complete PDU) of a dcerpc pdu so just add
4844 the call to both the call table and the
4847 call_key
= wmem_new(wmem_file_scope(), dcerpc_cn_call_key
);
4848 call_key
->conv
= conv
;
4849 call_key
->call_id
= hdr
->call_id
;
4850 call_key
->transport_salt
= dcerpc_get_transport_salt(pinfo
);
4852 /* if there is already a matching call in the table
4853 remove it so it is replaced with the new one */
4854 if (wmem_map_lookup(dcerpc_cn_calls
, call_key
)) {
4855 wmem_map_remove(dcerpc_cn_calls
, call_key
);
4858 call_value
= wmem_new(wmem_file_scope(), dcerpc_call_value
);
4859 call_value
->uuid
= bind_value
->uuid
;
4860 call_value
->ver
= bind_value
->ver
;
4861 call_value
->object_uuid
= obj_id
;
4862 call_value
->opnum
= opnum
;
4863 call_value
->req_frame
= pinfo
->num
;
4864 call_value
->req_time
= pinfo
->abs_ts
;
4865 call_value
->rep_frame
= 0;
4866 call_value
->max_ptr
= 0;
4867 call_value
->se_data
= NULL
;
4868 call_value
->private_data
= NULL
;
4869 call_value
->pol
= NULL
;
4870 call_value
->flags
= 0;
4871 if (!memcmp(&bind_value
->transport
, &uuid_ndr64
, sizeof(uuid_ndr64
))) {
4872 call_value
->flags
|= DCERPC_IS_NDR64
;
4875 wmem_map_insert(dcerpc_cn_calls
, call_key
, call_value
);
4877 new_matched_key
= wmem_new(wmem_file_scope(), dcerpc_matched_key
);
4878 *new_matched_key
= matched_key
;
4879 wmem_map_insert(dcerpc_matched
, new_matched_key
, call_value
);
4888 di
= wmem_new0(pinfo
->pool
, dcerpc_info
);
4889 /* handoff this call */
4890 di
->dcerpc_procedure_name
= "";
4892 di
->call_id
= hdr
->call_id
;
4893 di
->transport_salt
= dcerpc_get_transport_salt(pinfo
);
4894 di
->ptype
= PDU_REQ
;
4895 di
->call_data
= value
;
4898 if (value
->rep_frame
!= 0) {
4899 pi
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_response_in
,
4900 tvb
, 0, 0, value
->rep_frame
);
4901 proto_item_set_generated(pi
);
4902 if (parent_pi
!= NULL
) {
4903 proto_item_append_text(parent_pi
, ", [Resp: #%u]", value
->rep_frame
);
4907 dissect_dcerpc_cn_stub(tvb
, offset
, pinfo
, dcerpc_tree
, tree
,
4908 hdr
, di
, &auth_info
, alloc_hint
,
4911 /* no bind information, simply show stub data */
4912 proto_tree_add_expert_format(dcerpc_tree
, pinfo
, &ei_dcerpc_cn_ctx_id_no_bind
, tvb
, offset
, 0, "No bind info for interface Context ID %u - capture start too late?", ctx_id
);
4913 show_stub_data(pinfo
, tvb
, offset
, dcerpc_tree
, &auth_info
, true);
4918 * Move the auth_info subtree to the end,
4919 * as it's also at the end of the pdu on the wire.
4921 dissect_dcerpc_cn_auth_move(&auth_info
, dcerpc_tree
);
4925 dissect_dcerpc_cn_resp(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
4926 proto_tree
*dcerpc_tree
, proto_tree
*tree
,
4927 e_dce_cn_common_hdr_t
*hdr
)
4929 dcerpc_call_value
*value
= NULL
;
4930 conversation_t
*conv
;
4932 dcerpc_auth_info auth_info
;
4933 uint32_t alloc_hint
;
4935 proto_item
*parent_pi
;
4936 e_guid_t obj_id_null
= DCERPC_UUID_NULL
;
4937 dcerpc_decode_as_data
* decode_data
= dcerpc_get_decode_data(pinfo
);
4939 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4940 hf_dcerpc_cn_alloc_hint
, &alloc_hint
);
4942 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4943 hf_dcerpc_cn_ctx_id
, &ctx_id
);
4944 parent_pi
= proto_tree_get_parent(dcerpc_tree
);
4945 if (parent_pi
!= NULL
) {
4946 proto_item_append_text(parent_pi
, ", Ctx: %u", ctx_id
);
4949 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
4950 decode_data
->dcectxid
= ctx_id
;
4952 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", Ctx: %u", ctx_id
);
4954 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4955 hf_dcerpc_cn_cancel_count
, NULL
);
4960 * XXX - what if this was set when the connection was set up,
4961 * and we just have a security context?
4963 dissect_dcerpc_cn_auth(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
, &auth_info
);
4965 conv
= find_conversation_pinfo(pinfo
, 0);
4968 /* no point in creating one here, really */
4969 show_stub_data(pinfo
, tvb
, offset
, dcerpc_tree
, &auth_info
, true);
4971 dcerpc_matched_key matched_key
, *new_matched_key
;
4973 /* !!! we can NOT check visited here since this will interact
4974 badly with when SMB handles (i.e. calls the subdissector)
4975 and desegmented pdu's .
4976 Instead we check if this pdu is already in the matched table or not
4978 matched_key
.frame
= pinfo
->num
;
4979 matched_key
.call_id
= hdr
->call_id
;
4980 value
= (dcerpc_call_value
*)wmem_map_lookup(dcerpc_matched
, &matched_key
);
4982 dcerpc_cn_call_key call_key
;
4983 dcerpc_call_value
*call_value
;
4985 call_key
.conv
= conv
;
4986 call_key
.call_id
= hdr
->call_id
;
4987 call_key
.transport_salt
= dcerpc_get_transport_salt(pinfo
);
4989 if ((call_value
= (dcerpc_call_value
*)wmem_map_lookup(dcerpc_cn_calls
, &call_key
))) {
4990 /* extra sanity check, only match them if the reply
4991 came after the request */
4992 if (call_value
->req_frame
<pinfo
->num
) {
4993 new_matched_key
= wmem_new(wmem_file_scope(), dcerpc_matched_key
);
4994 *new_matched_key
= matched_key
;
4995 wmem_map_insert(dcerpc_matched
, new_matched_key
, call_value
);
4997 if (call_value
->rep_frame
== 0) {
4998 call_value
->rep_frame
= pinfo
->num
;
5007 di
= wmem_new0(pinfo
->pool
, dcerpc_info
);
5008 /* handoff this call */
5009 di
->dcerpc_procedure_name
= "";
5011 di
->call_id
= hdr
->call_id
;
5012 di
->transport_salt
= dcerpc_get_transport_salt(pinfo
);
5013 di
->ptype
= PDU_RESP
;
5014 di
->call_data
= value
;
5016 pi
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_opnum
, tvb
, 0, 0, value
->opnum
);
5017 proto_item_set_generated(pi
);
5019 /* (optional) "Object UUID" from request */
5020 if (dcerpc_tree
&& (memcmp(&value
->object_uuid
, &obj_id_null
, sizeof(obj_id_null
)) != 0)) {
5021 pi
= proto_tree_add_guid_format(dcerpc_tree
, hf_dcerpc_obj_id
, tvb
,
5022 offset
, 0, (e_guid_t
*) &value
->object_uuid
, "Object UUID: %s",
5023 guid_to_str(pinfo
->pool
, (e_guid_t
*) &value
->object_uuid
));
5024 proto_item_set_generated(pi
);
5028 if (value
->req_frame
!= 0) {
5030 pi
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_request_in
,
5031 tvb
, 0, 0, value
->req_frame
);
5032 proto_item_set_generated(pi
);
5033 if (parent_pi
!= NULL
) {
5034 proto_item_append_text(parent_pi
, ", [Req: #%u]", value
->req_frame
);
5036 nstime_delta(&delta_ts
, &pinfo
->abs_ts
, &value
->req_time
);
5037 pi
= proto_tree_add_time(dcerpc_tree
, hf_dcerpc_time
, tvb
, offset
, 0, &delta_ts
);
5038 proto_item_set_generated(pi
);
5040 proto_tree_add_expert(dcerpc_tree
, pinfo
, &ei_dcerpc_no_request_found
, tvb
, 0, 0);
5043 dissect_dcerpc_cn_stub(tvb
, offset
, pinfo
, dcerpc_tree
, tree
,
5044 hdr
, di
, &auth_info
, alloc_hint
,
5047 /* no bind information, simply show stub data */
5048 proto_tree_add_expert_format(dcerpc_tree
, pinfo
, &ei_dcerpc_cn_ctx_id_no_bind
, tvb
, offset
, 0, "No bind info for interface Context ID %u - capture start too late?", ctx_id
);
5049 show_stub_data(pinfo
, tvb
, offset
, dcerpc_tree
, &auth_info
, true);
5054 * Move the auth_info subtree to the end,
5055 * as it's also at the end of the pdu on the wire.
5057 dissect_dcerpc_cn_auth_move(&auth_info
, dcerpc_tree
);
5061 dissect_dcerpc_cn_fault(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
5062 proto_tree
*dcerpc_tree
, e_dce_cn_common_hdr_t
*hdr
)
5064 dcerpc_call_value
*value
= NULL
;
5065 conversation_t
*conv
;
5068 uint32_t alloc_hint
;
5069 dcerpc_auth_info auth_info
;
5070 int length
, reported_length
;
5071 tvbuff_t
*stub_tvb
= NULL
;
5072 proto_item
*pi
= NULL
;
5073 dcerpc_decode_as_data
* decode_data
= dcerpc_get_decode_data(pinfo
);
5075 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
5076 hf_dcerpc_cn_alloc_hint
, &alloc_hint
);
5078 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
5079 hf_dcerpc_cn_ctx_id
, &ctx_id
);
5081 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
5082 hf_dcerpc_cn_cancel_count
, NULL
);
5083 proto_tree_add_bitmask(dcerpc_tree
, tvb
, offset
,
5084 hf_dcerpc_cn_fault_flags
,
5085 ett_dcerpc_fault_flags
,
5086 dcerpc_cn_fault_flags_fields
,
5087 DREP_ENC_INTEGER(hdr
->drep
));
5091 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
5092 hf_dcerpc_cn_status
, &status
);
5094 status
= ((hdr
->drep
[0] & DREP_LITTLE_ENDIAN
)
5095 ? tvb_get_letohl(tvb
, offset
)
5096 : tvb_get_ntohl(tvb
, offset
));
5098 pi
= proto_tree_add_item(dcerpc_tree
, hf_dcerpc_cn_status
, tvb
, offset
, 4, DREP_ENC_INTEGER(hdr
->drep
));
5101 expert_add_info_format(pinfo
, pi
, &ei_dcerpc_cn_status
, "Fault: %s", val_to_str(status
, reject_status_vals
, "Unknown (0x%08x)"));
5103 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
5104 decode_data
->dcectxid
= ctx_id
;
5106 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
5107 ", Ctx: %u, status: %s", ctx_id
,
5108 val_to_str(status
, reject_status_vals
,
5109 "Unknown (0x%08x)"));
5112 proto_tree_add_item(dcerpc_tree
, hf_dcerpc_reserved
, tvb
, offset
, 4, ENC_NA
);
5116 * XXX - what if this was set when the connection was set up,
5117 * and we just have a security context?
5119 dissect_dcerpc_cn_auth(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
, &auth_info
);
5121 length
= tvb_captured_length_remaining(tvb
, offset
);
5122 reported_length
= tvb_reported_length_remaining(tvb
, offset
);
5123 if (reported_length
< 0 ||
5124 (uint32_t)reported_length
< auth_info
.auth_size
) {
5125 /* We don't even have enough bytes for the authentication
5129 reported_length
-= auth_info
.auth_size
;
5130 if (length
> reported_length
)
5131 length
= reported_length
;
5132 stub_tvb
= tvb_new_subset_length_caplen(tvb
, offset
, length
, reported_length
);
5134 conv
= find_conversation_pinfo(pinfo
, 0);
5136 /* no point in creating one here, really */
5138 dcerpc_matched_key matched_key
, *new_matched_key
;
5140 /* !!! we can NOT check visited here since this will interact
5141 badly with when SMB handles (i.e. calls the subdissector)
5142 and desegmented pdu's .
5143 Instead we check if this pdu is already in the matched table or not
5145 matched_key
.frame
= pinfo
->num
;
5146 matched_key
.call_id
= hdr
->call_id
;
5147 value
= (dcerpc_call_value
*)wmem_map_lookup(dcerpc_matched
, &matched_key
);
5149 dcerpc_cn_call_key call_key
;
5150 dcerpc_call_value
*call_value
;
5152 call_key
.conv
= conv
;
5153 call_key
.call_id
= hdr
->call_id
;
5154 call_key
.transport_salt
= dcerpc_get_transport_salt(pinfo
);
5156 if ((call_value
= (dcerpc_call_value
*)wmem_map_lookup(dcerpc_cn_calls
, &call_key
))) {
5157 new_matched_key
= wmem_new(wmem_file_scope(), dcerpc_matched_key
);
5158 *new_matched_key
= matched_key
;
5159 wmem_map_insert(dcerpc_matched
, new_matched_key
, call_value
);
5162 if (call_value
->rep_frame
== 0) {
5163 call_value
->rep_frame
= pinfo
->num
;
5170 proto_tree
*stub_tree
= NULL
;
5173 proto_item
*parent_pi
;
5175 di
= wmem_new0(pinfo
->pool
, dcerpc_info
);
5176 /* handoff this call */
5177 di
->dcerpc_procedure_name
= "";
5179 di
->call_id
= hdr
->call_id
;
5180 di
->transport_salt
= dcerpc_get_transport_salt(pinfo
);
5181 di
->ptype
= PDU_FAULT
;
5182 di
->call_data
= value
;
5184 pi
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_opnum
, tvb
, 0, 0, value
->opnum
);
5185 proto_item_set_generated(pi
);
5186 if (value
->req_frame
!= 0) {
5188 pi
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_request_in
,
5189 tvb
, 0, 0, value
->req_frame
);
5190 proto_item_set_generated(pi
);
5191 parent_pi
= proto_tree_get_parent(dcerpc_tree
);
5192 if (parent_pi
!= NULL
) {
5193 proto_item_append_text(parent_pi
, ", [Req: #%u]", value
->req_frame
);
5195 nstime_delta(&delta_ts
, &pinfo
->abs_ts
, &value
->req_time
);
5196 pi
= proto_tree_add_time(dcerpc_tree
, hf_dcerpc_time
, tvb
, offset
, 0, &delta_ts
);
5197 proto_item_set_generated(pi
);
5199 proto_tree_add_expert(dcerpc_tree
, pinfo
, &ei_dcerpc_no_request_found
, tvb
, 0, 0);
5202 length
= tvb_reported_length_remaining(stub_tvb
, 0);
5203 /* as we now create a tvb in dissect_dcerpc_cn() containing only the
5204 * stub_data, the following calculation is no longer valid:
5205 * stub_length = hdr->frag_len - offset - auth_info.auth_size;
5206 * simply use the remaining length of the tvb instead.
5207 * XXX - or better use the reported_length?!?
5209 stub_length
= length
;
5211 stub_tree
= proto_tree_add_subtree_format(dcerpc_tree
,
5212 stub_tvb
, 0, stub_length
,
5213 ett_dcerpc_fault_stub_data
, NULL
,
5214 "Fault stub data (%d byte%s)", stub_length
,
5215 plurality(stub_length
, "", "s"));
5217 /* If we don't have reassembly enabled, or this packet contains
5218 the entire PDU, or if we don't have all the data in this
5219 fragment, just call the handoff directly if this is the
5220 first fragment or the PDU isn't fragmented. */
5221 if ( (!dcerpc_reassemble
) || PFC_NOT_FRAGMENTED(hdr
) ||
5222 !tvb_bytes_exist(stub_tvb
, 0, stub_length
) ) {
5223 if (hdr
->flags
&PFC_FIRST_FRAG
) {
5224 /* First fragment, possibly the only fragment */
5226 * XXX - should there be a third routine for each
5227 * function in an RPC subdissector, to handle
5228 * fault responses? The DCE RPC 1.1 spec says
5229 * three's "stub data" here, which I infer means
5230 * that it's protocol-specific and call-specific.
5232 * It should probably get passed the status code
5233 * as well, as that might be protocol-specific.
5235 if (stub_length
> 0) {
5236 proto_tree_add_item(stub_tree
, hf_dcerpc_fault_stub_data
, stub_tvb
, 0, stub_length
, ENC_NA
);
5239 /* PDU is fragmented and this isn't the first fragment */
5240 if (stub_length
> 0) {
5241 proto_tree_add_item(stub_tree
, hf_dcerpc_fragment_data
, stub_tvb
, 0, stub_length
, ENC_NA
);
5245 /* Reassembly is enabled, the PDU is fragmented, and
5246 we have all the data in the fragment; the first two
5247 of those mean we should attempt reassembly, and the
5248 third means we can attempt reassembly. */
5251 proto_tree_add_item(stub_tree
, hf_dcerpc_fragment_data
, stub_tvb
, 0, stub_length
, ENC_NA
);
5254 if (hdr
->flags
&PFC_FIRST_FRAG
) { /* FIRST fragment */
5255 if ( (!pinfo
->fd
->visited
) && value
->rep_frame
) {
5256 fragment_add_seq_next(&dcerpc_co_reassembly_table
,
5258 pinfo
, value
->rep_frame
, NULL
,
5262 } else if (hdr
->flags
&PFC_LAST_FRAG
) { /* LAST fragment */
5263 if ( value
->rep_frame
) {
5264 fragment_head
*fd_head
;
5266 fd_head
= fragment_add_seq_next(&dcerpc_co_reassembly_table
,
5268 pinfo
, value
->rep_frame
, NULL
,
5273 /* We completed reassembly */
5275 proto_item
*frag_tree_item
;
5277 next_tvb
= tvb_new_chain(stub_tvb
, fd_head
->tvb_data
);
5278 add_new_data_source(pinfo
, next_tvb
, "Reassembled DCE/RPC");
5279 show_fragment_tree(fd_head
, &dcerpc_frag_items
,
5280 dcerpc_tree
, pinfo
, next_tvb
, &frag_tree_item
);
5283 * XXX - should there be a third routine for each
5284 * function in an RPC subdissector, to handle
5285 * fault responses? The DCE RPC 1.1 spec says
5286 * three's "stub data" here, which I infer means
5287 * that it's protocol-specific and call-specific.
5289 * It should probably get passed the status code
5290 * as well, as that might be protocol-specific.
5294 proto_tree_add_item(dcerpc_tree
, hf_dcerpc_stub_data
, stub_tvb
, 0, stub_length
, ENC_NA
);
5299 } else { /* MIDDLE fragment(s) */
5300 if ( (!pinfo
->fd
->visited
) && value
->rep_frame
) {
5301 fragment_add_seq_next(&dcerpc_co_reassembly_table
,
5303 pinfo
, value
->rep_frame
, NULL
,
5313 * Move the auth_info subtree to the end,
5314 * as it's also at the end of the pdu on the wire.
5316 dissect_dcerpc_cn_auth_move(&auth_info
, dcerpc_tree
);
5320 dissect_dcerpc_cn_rts(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
5321 proto_tree
*dcerpc_tree
, e_dce_cn_common_hdr_t
*hdr
)
5323 proto_item
*tf
= NULL
;
5324 proto_item
*parent_pi
= NULL
;
5325 proto_tree
*cn_rts_pdu_tree
= NULL
;
5327 uint16_t commands_nb
= 0;
5330 const char *info_str
= NULL
;
5331 static int * const flags
[] = {
5332 &hf_dcerpc_cn_rts_flags_ping
,
5333 &hf_dcerpc_cn_rts_flags_other_cmd
,
5334 &hf_dcerpc_cn_rts_flags_recycle_channel
,
5335 &hf_dcerpc_cn_rts_flags_in_channel
,
5336 &hf_dcerpc_cn_rts_flags_out_channel
,
5337 &hf_dcerpc_cn_rts_flags_eof
,
5341 /* Dissect specific RTS header */
5342 rts_flags
= dcerpc_tvb_get_ntohs(tvb
, offset
, hdr
->drep
);
5343 proto_tree_add_bitmask_value_with_flags(dcerpc_tree
, tvb
, offset
, hf_dcerpc_cn_rts_flags
,
5344 ett_dcerpc_cn_rts_flags
, flags
, rts_flags
, BMT_NO_APPEND
);
5347 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
5348 hf_dcerpc_cn_rts_commands_nb
, &commands_nb
);
5350 /* Create the RTS PDU tree - we do not yet know its name */
5351 cn_rts_pdu_tree
= proto_tree_add_subtree_format(dcerpc_tree
, tvb
, offset
, -1, ett_dcerpc_cn_rts_pdu
, &tf
, "RTS PDU: %u commands", commands_nb
);
5353 cmd
= (uint32_t *)wmem_alloc(pinfo
->pool
, sizeof (uint32_t) * (commands_nb
+ 1));
5355 /* Dissect commands */
5356 for (i
= 0; i
< commands_nb
; ++i
) {
5357 proto_tree
*cn_rts_command_tree
= NULL
;
5358 const uint32_t command
= dcerpc_tvb_get_ntohl(tvb
, offset
, hdr
->drep
);
5360 tf
= proto_tree_add_uint(cn_rts_pdu_tree
, hf_dcerpc_cn_rts_command
, tvb
, offset
, 4, command
);
5361 cn_rts_command_tree
= proto_item_add_subtree(tf
, ett_dcerpc_cn_rts_command
);
5364 case RTS_CMD_RECEIVEWINDOWSIZE
:
5365 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_receivewindowsize
, NULL
);
5367 case RTS_CMD_FLOWCONTROLACK
:
5368 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_fack_bytesreceived
, NULL
);
5369 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_fack_availablewindow
, NULL
);
5370 offset
= dissect_dcerpc_uuid_t(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_fack_channelcookie
, NULL
);
5372 case RTS_CMD_CONNECTIONTIMEOUT
:
5373 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_connectiontimeout
, NULL
);
5375 case RTS_CMD_COOKIE
:
5376 offset
= dissect_dcerpc_uuid_t(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_cookie
, NULL
);
5378 case RTS_CMD_CHANNELLIFETIME
:
5379 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_channellifetime
, NULL
);
5381 case RTS_CMD_CLIENTKEEPALIVE
:
5382 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_clientkeepalive
, NULL
);
5384 case RTS_CMD_VERSION
:
5385 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_version
, NULL
);
5389 case RTS_CMD_PADDING
: {
5391 const uint32_t conformance_count
= dcerpc_tvb_get_ntohl(tvb
, offset
, hdr
->drep
);
5392 proto_tree_add_uint(cn_rts_command_tree
, hf_dcerpc_cn_rts_command_conformancecount
, tvb
, offset
, 4, conformance_count
);
5394 padding
= (uint8_t *)tvb_memdup(pinfo
->pool
, tvb
, offset
, conformance_count
);
5395 proto_tree_add_bytes(cn_rts_command_tree
, hf_dcerpc_cn_rts_command_padding
, tvb
, offset
, conformance_count
, padding
);
5396 offset
+= conformance_count
;
5398 case RTS_CMD_NEGATIVEANCE
:
5402 case RTS_CMD_CLIENTADDRESS
: {
5404 const uint32_t addrtype
= dcerpc_tvb_get_ntohl(tvb
, offset
, hdr
->drep
);
5405 proto_tree_add_uint(cn_rts_command_tree
, hf_dcerpc_cn_rts_command_addrtype
, tvb
, offset
, 4, addrtype
);
5409 const uint32_t addr4
= tvb_get_ipv4(tvb
, offset
);
5410 proto_tree_add_ipv4_format_value(cn_rts_command_tree
, hf_dcerpc_cmd_client_ipv4
, tvb
, offset
, 4, addr4
, "%s", get_hostname(addr4
));
5415 tvb_get_ipv6(tvb
, offset
, &addr6
);
5416 proto_tree_add_ipv6_format_value(cn_rts_command_tree
, hf_dcerpc_cmd_client_ipv6
, tvb
, offset
, 16, &addr6
, "%s", get_hostname6(&addr6
));
5420 padding
= (uint8_t *)tvb_memdup(pinfo
->pool
, tvb
, offset
, 12);
5421 proto_tree_add_bytes(cn_rts_command_tree
, hf_dcerpc_cn_rts_command_padding
, tvb
, offset
, 12, padding
);
5424 case RTS_CMD_ASSOCIATIONGROUPID
:
5425 offset
= dissect_dcerpc_uuid_t(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_associationgroupid
, NULL
);
5427 case RTS_CMD_DESTINATION
:
5428 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_forwarddestination
, NULL
);
5430 case RTS_CMD_PINGTRAFFICSENTNOTIFY
:
5431 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_pingtrafficsentnotify
, NULL
);
5434 expert_add_info(pinfo
, tf
, &ei_dcerpc_cn_rts_command
);
5439 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "RPCH");
5441 /* Define which PDU Body we are dealing with */
5442 info_str
= "unknown RTS PDU";
5444 switch (rts_flags
) {
5446 switch (commands_nb
) {
5448 if (cmd
[0] == 0x2) {
5449 info_str
= "CONN/A3";
5450 } else if (cmd
[0] == 0x3) {
5451 info_str
= "IN_R1/A5,IN_R1/A6,IN_R2/A2,IN_R2/A5,OUT_R2/A4";
5452 } else if (cmd
[0] == 0x7) {
5453 info_str
= "IN_R1/B1";
5454 } else if (cmd
[0] == 0x0) {
5455 info_str
= "IN_R1/B2";
5456 } else if (cmd
[0] == 0xD) {
5457 info_str
= "IN_R2/A3,IN_R2/A4";
5458 } else if (cmd
[0] == 0xA) {
5459 info_str
= "OUT_R1/A9,OUT_R1/A10,OUT_R1/A11,OUT_R2/B1,OUT_R2/B2";
5463 if ((cmd
[0] == 0x0) && (cmd
[1] == 0x6)) {
5464 info_str
= "CONN/B3";
5465 } else if ((cmd
[0] == 0xD) && (cmd
[1] == 0xA)) {
5466 info_str
= "OUT_R2/A5,OUT_R2/A6";
5470 if ((cmd
[0] == 0x6) && (cmd
[1] == 0x0) && (cmd
[2] == 0x2)) {
5471 info_str
= "CONN/C1,CONN/C2";
5475 if ((cmd
[0] == 0x6) && (cmd
[1] == 0x3) && (cmd
[2] == 0x3) && (cmd
[3] == 0x0)) {
5476 info_str
= "CONN/A1";
5477 } else if ((cmd
[0] == 0xD) && (cmd
[1] == 0x6) && (cmd
[2] == 0x0) && (cmd
[3] == 0x2)) {
5478 info_str
= "IN_R1/A3,IN_R1/A4";
5482 if ((cmd
[0] == 0x6) && (cmd
[1] == 0x3) && (cmd
[2] == 0x3) && (cmd
[3] == 0x4) && (cmd
[4] == 0x5) && (cmd
[5] == 0xC)) {
5483 info_str
= "CONN/B1";
5491 switch (commands_nb
) {
5496 if ((cmd
[0] == 0x7) || (cmd
[0] == 0x8)) {
5497 info_str
= "OUT_R2/C1";
5504 case RTS_FLAG_OTHER_CMD
:
5505 switch (commands_nb
) {
5507 if (cmd
[0] == 0x5) {
5508 info_str
= "Keep-Alive";
5509 } else if (cmd
[0] == 0xE) {
5510 info_str
= "PingTrafficSentNotify";
5511 } else if (cmd
[0] == 0x1) {
5512 info_str
= "FlowControlAck";
5516 if ((cmd
[0] == 0xD) && (cmd
[1] == 0x1)) {
5517 info_str
= "FlowControlAckWithDestination";
5524 case RTS_FLAG_RECYCLE_CHANNEL
:
5525 switch (commands_nb
) {
5527 if (cmd
[0] == 0xD) {
5528 info_str
= "OUT_R1/A1,OUT_R1/A2,OUT_R2/A1,OUT_R2/A2";
5532 if ((cmd
[0] == 0x6) && (cmd
[1] == 0x3) && (cmd
[2] == 0x3) && (cmd
[3] == 0x3)) {
5533 info_str
= "IN_R1/A1,IN_R2/A1";
5537 if ((cmd
[0] == 0x6) && (cmd
[1] == 0x3) && (cmd
[2] == 0x3) && (cmd
[3] == 0x3) && (cmd
[4] == 0x0)) {
5538 info_str
= "OUT_R1/A3,OUT_R2/A3";
5545 case RTS_FLAG_IN_CHANNEL
|RTS_FLAG_RECYCLE_CHANNEL
:
5546 switch (commands_nb
) {
5548 if ((cmd
[0] == 0x6) && (cmd
[1] == 0x3) && (cmd
[2] == 0x3) && (cmd
[3] == 0x3) && (cmd
[4] == 0x0) && (cmd
[5] == 0x2)) {
5549 info_str
= "IN_R1/A2";
5556 case RTS_FLAG_IN_CHANNEL
:
5557 switch (commands_nb
) {
5559 if ((cmd
[0] == 0x6) && (cmd
[1] == 0x3) && (cmd
[2] == 0x3) && (cmd
[3] == 0x0) && (cmd
[4] == 0x2) && (cmd
[5] == 0xC) && (cmd
[6] == 0xB)) {
5560 info_str
= "CONN/B2";
5567 case RTS_FLAG_OUT_CHANNEL
|RTS_FLAG_RECYCLE_CHANNEL
:
5568 switch (commands_nb
) {
5570 if ((cmd
[0] == 0x6) && (cmd
[1] == 0x3) && (cmd
[2] == 0x3) && (cmd
[3] == 0x3) && (cmd
[4] == 0x4) && (cmd
[5] == 0) && (cmd
[6] == 0x2)) {
5571 info_str
= "OUT_R1/A4";
5578 case RTS_FLAG_OUT_CHANNEL
:
5579 switch (commands_nb
) {
5581 if ((cmd
[0] == 0xD) && (cmd
[1] == 0x3)) {
5582 info_str
= "OUT_R1/A7,OUT_R1/A8,OUT_R2/A8";
5586 if ((cmd
[0] == 0xD) && (cmd
[1] == 0x6) && (cmd
[2] == 0x2)) {
5587 info_str
= "OUT_R1/A5,OUT_R1/A6";
5588 } else if ((cmd
[0] == 0xD) && (cmd
[1] == 0x3) && (cmd
[2] == 0x6)) {
5589 info_str
= "OUT_R2/A7";
5593 if ((cmd
[0] == 0x6) && (cmd
[1] == 0x3) && (cmd
[2] == 0x3) && (cmd
[3] == 0x4) && (cmd
[4] == 0x0)) {
5594 info_str
= "CONN/A2";
5602 switch (commands_nb
) {
5604 if (cmd
[0] == 0xA) {
5605 info_str
= "OUT_R2/B3";
5613 switch (commands_nb
) {
5625 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "%s, ", info_str
);
5626 col_set_fence(pinfo
->cinfo
,COL_INFO
);
5628 parent_pi
= proto_tree_get_parent(dcerpc_tree
);
5629 if (parent_pi
!= NULL
) {
5630 proto_item_append_text(parent_pi
, ", %s", info_str
);
5634 /* Test to see if this looks like a connection oriented PDU */
5636 is_dcerpc(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo _U_
)
5639 uint8_t rpc_ver_minor
;
5644 if (!tvb_bytes_exist(tvb
, offset
, sizeof(e_dce_cn_common_hdr_t
)))
5645 return false; /* not enough information to check */
5647 rpc_ver
= tvb_get_uint8(tvb
, offset
++);
5650 rpc_ver_minor
= tvb_get_uint8(tvb
, offset
++);
5651 if ((rpc_ver_minor
!= 0) && (rpc_ver_minor
!= 1))
5653 ptype
= tvb_get_uint8(tvb
, offset
++);
5654 if (ptype
> PDU_RTS
)
5656 /* Skip flags, nothing good to check */
5659 tvb_memcpy(tvb
, (uint8_t *)drep
, offset
, sizeof (drep
));
5662 if (drep
[1] > DCE_RPC_DREP_FP_IBM
)
5664 offset
+= (int)sizeof(drep
);
5665 frag_len
= dcerpc_tvb_get_ntohs(tvb
, offset
, drep
);
5666 if (frag_len
< sizeof(e_dce_cn_common_hdr_t
)) {
5674 * DCERPC dissector for connection oriented calls.
5677 dissect_dcerpc_cn(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
5678 proto_tree
*tree
, bool can_desegment
, int *pkt_len
)
5680 static const uint8_t nulls
[4] = { 0 };
5684 proto_item
*ti
= NULL
;
5685 proto_item
*tf
= NULL
;
5686 proto_tree
*dcerpc_tree
= NULL
;
5687 e_dce_cn_common_hdr_t hdr
;
5688 dcerpc_auth_info auth_info
;
5689 tvbuff_t
*fragment_tvb
;
5690 dcerpc_decode_as_data
* decode_data
= dcerpc_get_decode_data(pinfo
);
5691 static int * const hdr_flags
[] = {
5692 &hf_dcerpc_cn_flags_object
,
5693 &hf_dcerpc_cn_flags_maybe
,
5694 &hf_dcerpc_cn_flags_dne
,
5695 &hf_dcerpc_cn_flags_mpx
,
5696 &hf_dcerpc_cn_flags_reserved
,
5697 &hf_dcerpc_cn_flags_cancel_pending
,
5698 &hf_dcerpc_cn_flags_last_frag
,
5699 &hf_dcerpc_cn_flags_first_frag
,
5704 * when done over nbt, dcerpc requests are padded with 4 bytes of null
5705 * data for some reason.
5707 * XXX - if that's always the case, the right way to do this would
5708 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
5709 * the 4 bytes of null padding, and make that the dissector
5710 * used for "netbios".
5712 if (tvb_memeql(tvb
, offset
, nulls
, 4) == 0) {
5721 * Check if this looks like a C/O DCERPC call
5723 if (!is_dcerpc(tvb
, offset
, pinfo
))
5726 start_offset
= offset
;
5727 hdr
.rpc_ver
= tvb_get_uint8(tvb
, offset
++);
5728 hdr
.rpc_ver_minor
= tvb_get_uint8(tvb
, offset
++);
5729 hdr
.ptype
= tvb_get_uint8(tvb
, offset
++);
5731 hdr
.flags
= tvb_get_uint8(tvb
, offset
++);
5732 tvb_memcpy(tvb
, (uint8_t *)hdr
.drep
, offset
, sizeof (hdr
.drep
));
5733 offset
+= (int)sizeof (hdr
.drep
);
5735 hdr
.frag_len
= dcerpc_tvb_get_ntohs(tvb
, offset
, hdr
.drep
);
5737 hdr
.auth_len
= dcerpc_tvb_get_ntohs(tvb
, offset
, hdr
.drep
);
5739 hdr
.call_id
= dcerpc_tvb_get_ntohl(tvb
, offset
, hdr
.drep
);
5742 if (can_desegment
&& pinfo
->can_desegment
5743 && !tvb_bytes_exist(tvb
, start_offset
, hdr
.frag_len
)) {
5744 pinfo
->desegment_offset
= start_offset
;
5745 pinfo
->desegment_len
= hdr
.frag_len
- tvb_reported_length_remaining(tvb
, start_offset
);
5746 *pkt_len
= 0; /* desegmentation required */
5750 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "DCERPC");
5752 if (decode_data
->dcectxid
!= 0) {
5753 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
5754 * append a delimiter and set a column fence */
5755 col_append_str(pinfo
->cinfo
, COL_INFO
, " # ");
5756 col_set_fence(pinfo
->cinfo
,COL_INFO
);
5758 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "%s: call_id: %u",
5759 pckt_vals
[hdr
.ptype
].strptr
, hdr
.call_id
);
5761 if (decode_data
->dcectxid
!= 0) {
5762 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU */
5763 expert_add_info(pinfo
, NULL
, &ei_dcerpc_fragment_multiple
);
5766 offset
= start_offset
;
5767 tvb_ensure_bytes_exist(tvb
, offset
, 16);
5769 ti
= proto_tree_add_item(tree
, proto_dcerpc
, tvb
, offset
, hdr
.frag_len
, ENC_NA
);
5770 dcerpc_tree
= proto_item_add_subtree(ti
, ett_dcerpc
);
5773 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_ver
, tvb
, offset
, 1, hdr
.rpc_ver
);
5776 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_ver_minor
, tvb
, offset
, 1, hdr
.rpc_ver_minor
);
5779 tf
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_packet_type
, tvb
, offset
, 1, hdr
.ptype
);
5782 #if 0 /* XXX - too much "output noise", removed for now */
5783 if (hdr
.ptype
== PDU_BIND
|| hdr
.ptype
== PDU_ALTER
||
5784 hdr
.ptype
== PDU_BIND_ACK
|| hdr
.ptype
== PDU_ALTER_ACK
)
5785 expert_add_info_format(pinfo
, tf
, &ei_dcerpc_context_change
, "Context change: %s", val_to_str(hdr
.ptype
, pckt_vals
, "(0x%x)"));
5787 if (hdr
.ptype
== PDU_BIND_NAK
)
5788 expert_add_info(pinfo
, tf
, &ei_dcerpc_bind_not_acknowledged
);
5791 proto_item_append_text(ti
, " %s, Fragment: %s",
5792 val_to_str(hdr
.ptype
, pckt_vals
, "Unknown (0x%02x)"),
5793 fragment_type(hdr
.flags
));
5796 proto_tree_add_bitmask_value_with_flags(dcerpc_tree
, tvb
, offset
, hf_dcerpc_cn_flags
,
5797 ett_dcerpc_cn_flags
, hdr_flags
, hdr
.flags
, BMT_NO_APPEND
);
5800 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", Fragment: %s", fragment_type(hdr
.flags
));
5802 proto_tree_add_dcerpc_drep(dcerpc_tree
, tvb
, offset
, hdr
.drep
, (int)sizeof (hdr
.drep
));
5803 offset
+= (int)sizeof (hdr
.drep
);
5805 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_cn_frag_len
, tvb
, offset
, 2, hdr
.frag_len
);
5808 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_cn_auth_len
, tvb
, offset
, 2, hdr
.auth_len
);
5811 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_cn_call_id
, tvb
, offset
, 4, hdr
.call_id
);
5815 proto_item_append_text(ti
, ", FragLen: %u, Call: %u", hdr
.frag_len
, hdr
.call_id
);
5819 * None of the stuff done above should throw an exception, because
5820 * we would have rejected this as "not DCE RPC" if we didn't have all
5821 * of it. (XXX - perhaps we should request reassembly if we have
5822 * enough of the header to consider it DCE RPC but not enough to
5823 * get the fragment length; in that case the stuff still wouldn't
5824 * throw an exception.)
5826 * The rest of the stuff might, so return the PDU length to our caller.
5827 * XXX - should we construct a tvbuff containing only the PDU and
5828 * use that? Or should we have separate "is this a DCE RPC PDU",
5829 * "how long is it", and "dissect it" routines - which might let us
5830 * do most of the work in "tcp_dissect_pdus()"?
5832 if (pkt_len
!= NULL
)
5833 *pkt_len
= hdr
.frag_len
+ padding
;
5835 /* The remaining bytes in the current tvb might contain multiple
5836 * DCE/RPC fragments, so create a new tvb subset for this fragment.
5837 * Only limit the end of the fragment, but not the offset start,
5838 * as the authentication function dissect_dcerpc_cn_auth() will fail
5839 * (and other functions might fail as well) computing the right start
5842 subtvb_len
= MIN(hdr
.frag_len
, tvb_reported_length(tvb
));
5843 fragment_tvb
= tvb_new_subset_length_caplen(tvb
, start_offset
,
5844 subtvb_len
/* length */,
5845 hdr
.frag_len
/* reported_length */);
5848 * Packet type specific stuff is next.
5850 switch (hdr
.ptype
) {
5853 dissect_dcerpc_cn_bind(fragment_tvb
, MIN(offset
- start_offset
, subtvb_len
), pinfo
, dcerpc_tree
, &hdr
);
5858 dissect_dcerpc_cn_bind_ack(fragment_tvb
, MIN(offset
- start_offset
, subtvb_len
), pinfo
, dcerpc_tree
, &hdr
);
5863 * Nothing after the common header other than credentials.
5865 dissect_dcerpc_cn_auth(fragment_tvb
, MIN(offset
- start_offset
, subtvb_len
), pinfo
, dcerpc_tree
, &hdr
,
5870 dissect_dcerpc_cn_rqst(fragment_tvb
, MIN(offset
- start_offset
, subtvb_len
), pinfo
, dcerpc_tree
, tree
, &hdr
);
5874 dissect_dcerpc_cn_resp(fragment_tvb
, MIN(offset
- start_offset
, subtvb_len
), pinfo
, dcerpc_tree
, tree
, &hdr
);
5878 dissect_dcerpc_cn_fault(fragment_tvb
, MIN(offset
- start_offset
, subtvb_len
), pinfo
, dcerpc_tree
, &hdr
);
5882 dissect_dcerpc_cn_bind_nak(fragment_tvb
, MIN(offset
- start_offset
, subtvb_len
), pinfo
, dcerpc_tree
, &hdr
);
5888 * Nothing after the common header other than an authentication
5891 dissect_dcerpc_cn_auth(fragment_tvb
, MIN(offset
- start_offset
, subtvb_len
), pinfo
, dcerpc_tree
, &hdr
,
5897 * Nothing after the common header, not even an authentication
5902 dissect_dcerpc_cn_rts(fragment_tvb
, MIN(offset
- start_offset
, subtvb_len
), pinfo
, dcerpc_tree
, &hdr
);
5906 /* might as well dissect the auth info */
5907 dissect_dcerpc_cn_auth(fragment_tvb
, MIN(offset
- start_offset
, subtvb_len
), pinfo
, dcerpc_tree
, &hdr
,
5915 * DCERPC dissector for connection oriented calls over packet-oriented
5919 dissect_dcerpc_cn_pk(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
5921 dcerpc_decode_as_data
* decode_data
= dcerpc_get_decode_data(pinfo
);
5924 * Only one PDU per transport packet, and only one transport
5927 decode_data
->dcetransporttype
= DCE_TRANSPORT_UNKNOWN
;
5928 if (!dissect_dcerpc_cn(tvb
, 0, pinfo
, tree
, false, NULL
)) {
5930 * It wasn't a DCERPC PDU.
5942 * DCERPC dissector for connection oriented calls over byte-stream
5944 * we need to distinguish here between SMB and non-TCP (more in the future?)
5945 * to be able to know what kind of private_data structure to expect.
5948 dissect_dcerpc_cn_bs_body(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
5950 volatile int offset
= 0;
5952 volatile int dcerpc_pdus
= 0;
5953 volatile bool ret
= false;
5956 * There may be multiple PDUs per transport packet; keep
5959 while (tvb_reported_length_remaining(tvb
, offset
) != 0) {
5962 if (dissect_dcerpc_cn(tvb
, offset
, pinfo
, tree
,
5963 dcerpc_cn_desegment
, &pdu_len
)) {
5966 } CATCH_NONFATAL_ERRORS
{
5968 * Somebody threw an exception that means that there
5969 * was a problem dissecting the payload; that means
5970 * that a dissector was found, so we don't need to
5971 * dissect the payload as data or update the protocol
5974 * Just show the exception and then continue dissecting
5977 show_exception(tvb
, pinfo
, tree
, EXCEPT_CODE
, GET_MESSAGE
);
5979 * Presumably it looked enough like a DCE RPC PDU that we
5980 * dissected enough of it to throw an exception.
5985 if (dcerpc_pdus
== 0) {
5986 bool try_desegment
= false;
5987 if (dcerpc_cn_desegment
&& pinfo
->can_desegment
&&
5988 !tvb_bytes_exist(tvb
, offset
, sizeof(e_dce_cn_common_hdr_t
))) {
5989 /* look for a previous occurrence of the DCE-RPC protocol */
5990 wmem_list_frame_t
*cur
;
5991 cur
= wmem_list_frame_prev(wmem_list_tail(pinfo
->layers
));
5992 while (cur
!= NULL
) {
5993 if (proto_dcerpc
== (int)GPOINTER_TO_UINT(wmem_list_frame_data(cur
))) {
5994 try_desegment
= true;
5997 cur
= wmem_list_frame_prev(cur
);
6001 if (try_desegment
) {
6002 /* It didn't look like DCE-RPC but we already had one DCE-RPC
6003 * layer in this packet and what we have is short. Assume that
6004 * it was just too short to tell and ask the TCP layer for more
6006 pinfo
->desegment_offset
= offset
;
6007 pinfo
->desegment_len
= (uint32_t)(sizeof(e_dce_cn_common_hdr_t
) - tvb_reported_length_remaining(tvb
, offset
));
6009 /* Really not DCE-RPC */
6015 * Well, we've seen at least one DCERPC PDU.
6019 /* if we had more than one Req/Resp in this PDU change the protocol column */
6020 /* this will formerly contain the last interface name, which may not be the same for all Req/Resp */
6021 if (dcerpc_pdus
>= 2)
6022 col_add_fstr(pinfo
->cinfo
, COL_PROTOCOL
, "%u*DCERPC", dcerpc_pdus
);
6026 * Desegmentation required - bail now, but give the user a hint that desegmentation might be done later.
6028 proto_tree_add_uint_format(tree
, hf_dcerpc_cn_deseg_req
, tvb
, offset
,
6030 tvb_reported_length_remaining(tvb
, offset
),
6031 "[DCE RPC: %u byte%s left, desegmentation might follow]",
6032 tvb_reported_length_remaining(tvb
, offset
),
6033 plurality(tvb_reported_length_remaining(tvb
, offset
), "", "s"));
6038 * Step to the next PDU.
6046 dissect_dcerpc_cn_bs(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
6048 dcerpc_decode_as_data
* decode_data
= dcerpc_get_decode_data(pinfo
);
6050 decode_data
->dcetransporttype
= DCE_TRANSPORT_UNKNOWN
;
6051 return dissect_dcerpc_cn_bs_body(tvb
, pinfo
, tree
);
6055 get_dcerpc_pdu_len(packet_info
*pinfo _U_
, tvbuff_t
*tvb
,
6056 int offset
, void *data _U_
)
6061 tvb_memcpy(tvb
, (uint8_t *)drep
, offset
+4, sizeof(drep
));
6062 frag_len
= dcerpc_tvb_get_ntohs(tvb
, offset
+8, drep
);
6065 /* tcp_dissect_pdus() interprets a 0 return value as meaning
6066 * "a PDU starts here, but the length cannot be determined yet, so
6067 * we need at least one more segment." However, a frag_len of 0 here
6068 * is instead a bogus length. Instead return 1, another bogus length
6069 * also less than our fixed length, so that the TCP dissector will
6070 * correctly interpret it as a bogus and report an error.
6078 dissect_dcerpc_pdu(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
6081 dissect_dcerpc_cn(tvb
, 0, pinfo
, tree
,
6082 /* Desegment is already handled by TCP, don't confuse it */
6089 dissect_dcerpc_tcp_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
6091 dcerpc_decode_as_data
* decode_data
;
6093 if (!is_dcerpc(tvb
, 0, pinfo
))
6096 decode_data
= dcerpc_get_decode_data(pinfo
);
6097 decode_data
->dcetransporttype
= DCE_TRANSPORT_UNKNOWN
;
6099 tcp_dissect_pdus(tvb
, pinfo
, tree
, dcerpc_cn_desegment
, sizeof(e_dce_cn_common_hdr_t
), get_dcerpc_pdu_len
, dissect_dcerpc_pdu
, data
);
6104 dissect_dcerpc_tcp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
6106 dcerpc_decode_as_data
* decode_data
;
6108 decode_data
= dcerpc_get_decode_data(pinfo
);
6109 decode_data
->dcetransporttype
= DCE_TRANSPORT_UNKNOWN
;
6111 tcp_dissect_pdus(tvb
, pinfo
, tree
, dcerpc_cn_desegment
, sizeof(e_dce_cn_common_hdr_t
), get_dcerpc_pdu_len
, dissect_dcerpc_pdu
, data
);
6112 return tvb_captured_length(tvb
);
6116 dissect_dcerpc_cn_smbpipe(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
6118 dcerpc_decode_as_data
* decode_data
= dcerpc_get_decode_data(pinfo
);
6120 decode_data
->dcetransporttype
= DCE_CN_TRANSPORT_SMBPIPE
;
6121 return dissect_dcerpc_cn_bs_body(tvb
, pinfo
, tree
);
6125 dissect_dcerpc_cn_smb2(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
6127 dcerpc_decode_as_data
* decode_data
= dcerpc_get_decode_data(pinfo
);
6129 decode_data
->dcetransporttype
= DCE_CN_TRANSPORT_SMBPIPE
;
6130 return dissect_dcerpc_cn_bs_body(tvb
, pinfo
, tree
);
6136 dissect_dcerpc_dg_auth(tvbuff_t
*tvb
, int offset
, proto_tree
*dcerpc_tree
,
6137 e_dce_dg_common_hdr_t
*hdr
, int *auth_level_p
)
6139 proto_tree
*auth_tree
= NULL
;
6140 uint8_t protection_level
;
6143 * Initially set "*auth_level_p" to -1 to indicate that we haven't
6144 * yet seen any authentication level information.
6146 if (auth_level_p
!= NULL
)
6150 * The authentication information is at the *end* of the PDU; in
6151 * request and response PDUs, the request and response stub data
6154 * If the full packet is here, and there's data past the end of the
6155 * packet body, then dissect the auth info.
6157 offset
+= hdr
->frag_len
;
6158 if (tvb_reported_length_remaining(tvb
, offset
) > 0) {
6159 switch (hdr
->auth_proto
) {
6161 case DCE_C_RPC_AUTHN_PROTOCOL_KRB5
:
6162 auth_tree
= proto_tree_add_subtree(dcerpc_tree
, tvb
, offset
, -1, ett_dcerpc_krb5_auth_verf
, NULL
, "Kerberos authentication verifier");
6163 protection_level
= tvb_get_uint8(tvb
, offset
);
6164 if (auth_level_p
!= NULL
)
6165 *auth_level_p
= protection_level
;
6166 proto_tree_add_uint(auth_tree
, hf_dcerpc_krb5_av_prot_level
, tvb
, offset
, 1, protection_level
);
6168 proto_tree_add_item(auth_tree
, hf_dcerpc_krb5_av_key_vers_num
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
6170 if (protection_level
== DCE_C_AUTHN_LEVEL_PKT_PRIVACY
)
6171 offset
+= 6; /* 6 bytes of padding */
6173 offset
+= 2; /* 2 bytes of padding */
6174 proto_tree_add_item(auth_tree
, hf_dcerpc_krb5_av_key_auth_verifier
, tvb
, offset
, 16, ENC_NA
);
6179 proto_tree_add_item(dcerpc_tree
, hf_dcerpc_authentication_verifier
, tvb
, offset
, -1, ENC_NA
);
6186 dissect_dcerpc_dg_cancel_ack(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
6187 proto_tree
*dcerpc_tree
,
6188 e_dce_dg_common_hdr_t
*hdr
)
6192 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
,
6193 hdr
->drep
, hf_dcerpc_dg_cancel_vers
,
6199 /* The only version we know about */
6200 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
,
6201 hdr
->drep
, hf_dcerpc_dg_cancel_id
,
6203 /*offset = */dissect_dcerpc_uint8(tvb
, offset
, pinfo
, dcerpc_tree
,
6204 hdr
->drep
, hf_dcerpc_dg_server_accepting_cancels
,
6211 dissect_dcerpc_dg_cancel(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
6212 proto_tree
*dcerpc_tree
,
6213 e_dce_dg_common_hdr_t
*hdr
)
6217 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
,
6218 hdr
->drep
, hf_dcerpc_dg_cancel_vers
,
6224 /* The only version we know about */
6225 /*offset = */dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
,
6226 hdr
->drep
, hf_dcerpc_dg_cancel_id
,
6228 /* XXX - are NDR Booleans 32 bits? */
6230 /* XXX - the RPC reference in chapter: "the cancel PDU" doesn't mention
6231 the accepting_cancels field (it's only in the cancel_ack PDU)! */
6232 /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
6233 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
6240 dissect_dcerpc_dg_fack(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
6241 proto_tree
*dcerpc_tree
,
6242 e_dce_dg_common_hdr_t
*hdr
)
6245 uint16_t serial_num
;
6246 uint16_t selack_len
;
6249 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, dcerpc_tree
,
6250 hdr
->drep
, hf_dcerpc_dg_fack_vers
,
6257 case 0: /* The only version documented in the DCE RPC 1.1 spec */
6258 case 1: /* This appears to be the same */
6259 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
,
6260 hdr
->drep
, hf_dcerpc_dg_fack_window_size
,
6262 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
,
6263 hdr
->drep
, hf_dcerpc_dg_fack_max_tsdu
,
6265 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
,
6266 hdr
->drep
, hf_dcerpc_dg_fack_max_frag_size
,
6268 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
,
6269 hdr
->drep
, hf_dcerpc_dg_fack_serial_num
,
6271 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " serial: %u",
6273 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
,
6274 hdr
->drep
, hf_dcerpc_dg_fack_selack_len
,
6276 for (i
= 0; i
< selack_len
; i
++) {
6277 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
,
6278 hdr
->drep
, hf_dcerpc_dg_fack_selack
,
6287 dissect_dcerpc_dg_reject_fault(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
6288 proto_tree
*dcerpc_tree
,
6289 e_dce_dg_common_hdr_t
*hdr
)
6293 /*offset = */dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
,
6294 hdr
->drep
, hf_dcerpc_dg_status
,
6297 col_append_fstr (pinfo
->cinfo
, COL_INFO
,
6299 val_to_str(status
, reject_status_vals
, "Unknown (0x%08x)"));
6303 dissect_dcerpc_dg_stub(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
6304 proto_tree
*dcerpc_tree
, proto_tree
*tree
,
6305 e_dce_dg_common_hdr_t
*hdr
, dcerpc_info
*di
)
6307 int length
, reported_length
, stub_length
;
6308 bool save_fragmented
;
6309 fragment_head
*fd_head
;
6312 proto_item
*parent_pi
;
6314 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " opnum: %u len: %u",
6315 di
->call_data
->opnum
, hdr
->frag_len
);
6317 length
= tvb_reported_length_remaining(tvb
, offset
);
6318 reported_length
= tvb_reported_length_remaining(tvb
, offset
);
6319 stub_length
= hdr
->frag_len
;
6320 if (length
> stub_length
)
6321 length
= stub_length
;
6322 if (reported_length
> stub_length
)
6323 reported_length
= stub_length
;
6325 save_fragmented
= pinfo
->fragmented
;
6327 /* If we don't have reassembly enabled, or this packet contains
6328 the entire PDU, or if this is a short frame (or a frame
6329 not reassembled at a lower layer) that doesn't include all
6330 the data in the fragment, just call the handoff directly if
6331 this is the first fragment or the PDU isn't fragmented. */
6332 if ( (!dcerpc_reassemble
) || !(hdr
->flags1
& PFCL1_FRAG
) ||
6333 !tvb_bytes_exist(tvb
, offset
, stub_length
) ) {
6334 if (hdr
->frag_num
== 0) {
6337 /* First fragment, possibly the only fragment */
6340 * XXX - authentication info?
6342 pinfo
->fragmented
= (hdr
->flags1
& PFCL1_FRAG
);
6343 next_tvb
= tvb_new_subset_length_caplen(tvb
, offset
, length
,
6345 dcerpc_try_handoff(pinfo
, tree
, dcerpc_tree
, next_tvb
, true, hdr
->drep
, di
, NULL
);
6347 /* PDU is fragmented and this isn't the first fragment */
6349 proto_tree_add_item(dcerpc_tree
, hf_dcerpc_fragment_data
, tvb
, offset
, stub_length
, ENC_NA
);
6353 /* Reassembly is enabled, the PDU is fragmented, and
6354 we have all the data in the fragment; the first two
6355 of those mean we should attempt reassembly, and the
6356 third means we can attempt reassembly. */
6358 proto_tree_add_item(dcerpc_tree
, hf_dcerpc_fragment_data
, tvb
, offset
, stub_length
, ENC_NA
);
6361 fd_head
= fragment_add_seq(&dcerpc_cl_reassembly_table
,
6363 pinfo
, hdr
->seqnum
, (void *)hdr
,
6364 hdr
->frag_num
, stub_length
,
6365 !(hdr
->flags1
& PFCL1_LASTFRAG
), 0);
6366 if (fd_head
!= NULL
) {
6367 /* We completed reassembly... */
6368 if (pinfo
->num
== fd_head
->reassembled_in
) {
6369 /* ...and this is the reassembled RPC PDU */
6370 next_tvb
= tvb_new_chain(tvb
, fd_head
->tvb_data
);
6371 add_new_data_source(pinfo
, next_tvb
, "Reassembled DCE/RPC");
6372 show_fragment_seq_tree(fd_head
, &dcerpc_frag_items
,
6373 tree
, pinfo
, next_tvb
, &pi
);
6376 * XXX - authentication info?
6378 pinfo
->fragmented
= false;
6379 dcerpc_try_handoff(pinfo
, tree
, dcerpc_tree
, next_tvb
, true, hdr
->drep
, di
, NULL
);
6381 /* ...and this isn't the reassembled RPC PDU */
6382 pi
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_reassembled_in
,
6383 tvb
, 0, 0, fd_head
->reassembled_in
);
6384 proto_item_set_generated(pi
);
6385 parent_pi
= proto_tree_get_parent(dcerpc_tree
);
6386 if (parent_pi
!= NULL
) {
6387 proto_item_append_text(parent_pi
, ", [Reas: #%u]", fd_head
->reassembled_in
);
6389 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
6390 " [DCE/RPC fragment, reas: #%u]", fd_head
->reassembled_in
);
6394 pinfo
->fragmented
= save_fragmented
;
6398 dissect_dcerpc_dg_rqst(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
6399 proto_tree
*dcerpc_tree
, proto_tree
*tree
,
6400 e_dce_dg_common_hdr_t
*hdr
, conversation_t
*conv
)
6403 dcerpc_call_value
*value
;
6404 dcerpc_matched_key matched_key
, *new_matched_key
;
6406 proto_item
*parent_pi
;
6408 if (!(pinfo
->fd
->visited
)) {
6409 dcerpc_call_value
*call_value
;
6410 dcerpc_dg_call_key
*call_key
;
6412 call_key
= wmem_new(wmem_file_scope(), dcerpc_dg_call_key
);
6413 call_key
->conv
= conv
;
6414 call_key
->seqnum
= hdr
->seqnum
;
6415 call_key
->act_id
= hdr
->act_id
;
6417 call_value
= wmem_new(wmem_file_scope(), dcerpc_call_value
);
6418 call_value
->uuid
= hdr
->if_id
;
6419 call_value
->ver
= hdr
->if_ver
;
6420 call_value
->object_uuid
= hdr
->obj_id
;
6421 call_value
->opnum
= hdr
->opnum
;
6422 call_value
->req_frame
= pinfo
->num
;
6423 call_value
->req_time
= pinfo
->abs_ts
;
6424 call_value
->rep_frame
= 0;
6425 call_value
->max_ptr
= 0;
6426 call_value
->se_data
= NULL
;
6427 call_value
->private_data
= NULL
;
6428 call_value
->pol
= NULL
;
6429 /* NDR64 is not available on dg transports ?*/
6430 call_value
->flags
= 0;
6432 wmem_map_insert(dcerpc_dg_calls
, call_key
, call_value
);
6434 new_matched_key
= wmem_new(wmem_file_scope(), dcerpc_matched_key
);
6435 new_matched_key
->frame
= pinfo
->num
;
6436 new_matched_key
->call_id
= hdr
->seqnum
;
6437 wmem_map_insert(dcerpc_matched
, new_matched_key
, call_value
);
6440 matched_key
.frame
= pinfo
->num
;
6441 matched_key
.call_id
= hdr
->seqnum
;
6442 value
= (dcerpc_call_value
*)wmem_map_lookup(dcerpc_matched
, &matched_key
);
6444 value
= wmem_new(pinfo
->pool
, dcerpc_call_value
);
6445 value
->uuid
= hdr
->if_id
;
6446 value
->ver
= hdr
->if_ver
;
6447 value
->object_uuid
= hdr
->obj_id
;
6448 value
->opnum
= hdr
->opnum
;
6449 value
->req_frame
= pinfo
->num
;
6450 value
->rep_frame
= 0;
6452 value
->se_data
= NULL
;
6453 value
->private_data
= NULL
;
6456 di
= wmem_new0(pinfo
->pool
, dcerpc_info
);
6457 di
->dcerpc_procedure_name
= "";
6459 di
->call_id
= hdr
->seqnum
;
6460 di
->transport_salt
= -1;
6461 di
->ptype
= PDU_REQ
;
6462 di
->call_data
= value
;
6464 if (value
->rep_frame
!= 0) {
6465 pi
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_response_in
,
6466 tvb
, 0, 0, value
->rep_frame
);
6467 proto_item_set_generated(pi
);
6468 parent_pi
= proto_tree_get_parent(dcerpc_tree
);
6469 if (parent_pi
!= NULL
) {
6470 proto_item_append_text(parent_pi
, ", [Resp: #%u]", value
->rep_frame
);
6473 dissect_dcerpc_dg_stub(tvb
, offset
, pinfo
, dcerpc_tree
, tree
, hdr
, di
);
6477 dissect_dcerpc_dg_resp(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
6478 proto_tree
*dcerpc_tree
, proto_tree
*tree
,
6479 e_dce_dg_common_hdr_t
*hdr
, conversation_t
*conv
)
6482 dcerpc_call_value
*value
;
6483 dcerpc_matched_key matched_key
, *new_matched_key
;
6485 proto_item
*parent_pi
;
6487 if (!(pinfo
->fd
->visited
)) {
6488 dcerpc_call_value
*call_value
;
6489 dcerpc_dg_call_key call_key
;
6491 call_key
.conv
= conv
;
6492 call_key
.seqnum
= hdr
->seqnum
;
6493 call_key
.act_id
= hdr
->act_id
;
6495 if ((call_value
= (dcerpc_call_value
*)wmem_map_lookup(dcerpc_dg_calls
, &call_key
))) {
6496 new_matched_key
= wmem_new(wmem_file_scope(), dcerpc_matched_key
);
6497 new_matched_key
->frame
= pinfo
->num
;
6498 new_matched_key
->call_id
= hdr
->seqnum
;
6499 wmem_map_insert(dcerpc_matched
, new_matched_key
, call_value
);
6500 if (call_value
->rep_frame
== 0) {
6501 call_value
->rep_frame
= pinfo
->num
;
6506 matched_key
.frame
= pinfo
->num
;
6507 matched_key
.call_id
= hdr
->seqnum
;
6508 value
= (dcerpc_call_value
*)wmem_map_lookup(dcerpc_matched
, &matched_key
);
6510 value
= wmem_new0(pinfo
->pool
, dcerpc_call_value
);
6511 value
->uuid
= hdr
->if_id
;
6512 value
->ver
= hdr
->if_ver
;
6513 value
->object_uuid
= hdr
->obj_id
;
6514 value
->opnum
= hdr
->opnum
;
6515 value
->rep_frame
= pinfo
->num
;
6518 di
= wmem_new0(pinfo
->pool
, dcerpc_info
);
6519 di
->dcerpc_procedure_name
= "";
6521 di
->transport_salt
= -1;
6522 di
->ptype
= PDU_RESP
;
6523 di
->call_data
= value
;
6525 if (value
->req_frame
!= 0) {
6527 pi
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_request_in
,
6528 tvb
, 0, 0, value
->req_frame
);
6529 proto_item_set_generated(pi
);
6530 parent_pi
= proto_tree_get_parent(dcerpc_tree
);
6531 if (parent_pi
!= NULL
) {
6532 proto_item_append_text(parent_pi
, ", [Req: #%u]", value
->req_frame
);
6534 nstime_delta(&delta_ts
, &pinfo
->abs_ts
, &value
->req_time
);
6535 pi
= proto_tree_add_time(dcerpc_tree
, hf_dcerpc_time
, tvb
, offset
, 0, &delta_ts
);
6536 proto_item_set_generated(pi
);
6538 proto_tree_add_expert(dcerpc_tree
, pinfo
, &ei_dcerpc_no_request_found
, tvb
, 0, 0);
6540 dissect_dcerpc_dg_stub(tvb
, offset
, pinfo
, dcerpc_tree
, tree
, hdr
, di
);
6544 dissect_dcerpc_dg_ping_ack(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
6545 proto_tree
*dcerpc_tree
,
6546 e_dce_dg_common_hdr_t
*hdr
, conversation_t
*conv
)
6548 proto_item
*parent_pi
;
6549 /* if (!(pinfo->fd->visited)) {*/
6550 dcerpc_call_value
*call_value
;
6551 dcerpc_dg_call_key call_key
;
6553 call_key
.conv
= conv
;
6554 call_key
.seqnum
= hdr
->seqnum
;
6555 call_key
.act_id
= hdr
->act_id
;
6557 if ((call_value
= (dcerpc_call_value
*)wmem_map_lookup(dcerpc_dg_calls
, &call_key
))) {
6561 pi
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_request_in
,
6562 tvb
, 0, 0, call_value
->req_frame
);
6563 proto_item_set_generated(pi
);
6564 parent_pi
= proto_tree_get_parent(dcerpc_tree
);
6565 if (parent_pi
!= NULL
) {
6566 proto_item_append_text(parent_pi
, ", [Req: #%u]", call_value
->req_frame
);
6569 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " [req: #%u]", call_value
->req_frame
);
6571 nstime_delta(&delta_ts
, &pinfo
->abs_ts
, &call_value
->req_time
);
6572 pi
= proto_tree_add_time(dcerpc_tree
, hf_dcerpc_time
, tvb
, offset
, 0, &delta_ts
);
6573 proto_item_set_generated(pi
);
6579 * DCERPC dissector for connectionless calls
6582 dissect_dcerpc_dg(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
6584 proto_item
*ti
= NULL
;
6585 proto_tree
*dcerpc_tree
= NULL
;
6586 e_dce_dg_common_hdr_t hdr
;
6588 conversation_t
*conv
;
6591 const char *uuid_name
= NULL
;
6592 static int * const hdr_flags1
[] = {
6593 &hf_dcerpc_dg_flags1_rsrvd_80
,
6594 &hf_dcerpc_dg_flags1_broadcast
,
6595 &hf_dcerpc_dg_flags1_idempotent
,
6596 &hf_dcerpc_dg_flags1_maybe
,
6597 &hf_dcerpc_dg_flags1_nofack
,
6598 &hf_dcerpc_dg_flags1_frag
,
6599 &hf_dcerpc_dg_flags1_last_frag
,
6600 &hf_dcerpc_dg_flags1_rsrvd_01
,
6604 static int * const hdr_flags2
[] = {
6605 &hf_dcerpc_dg_flags2_rsrvd_80
,
6606 &hf_dcerpc_dg_flags2_rsrvd_40
,
6607 &hf_dcerpc_dg_flags2_rsrvd_20
,
6608 &hf_dcerpc_dg_flags2_rsrvd_10
,
6609 &hf_dcerpc_dg_flags2_rsrvd_08
,
6610 &hf_dcerpc_dg_flags2_rsrvd_04
,
6611 &hf_dcerpc_dg_flags2_cancel_pending
,
6612 &hf_dcerpc_dg_flags2_rsrvd_01
,
6617 * Check if this looks like a CL DCERPC call. All dg packets
6618 * have an 80 byte header on them. Which starts with
6619 * version (4), pkt_type.
6621 if (tvb_reported_length(tvb
) < sizeof (hdr
)) {
6625 /* Version must be 4 */
6626 hdr
.rpc_ver
= tvb_get_uint8(tvb
, offset
++);
6627 if (hdr
.rpc_ver
!= 4)
6630 /* Type must be <= PDU_CANCEL_ACK or it's not connectionless DCE/RPC */
6631 hdr
.ptype
= tvb_get_uint8(tvb
, offset
++);
6632 if (hdr
.ptype
> PDU_CANCEL_ACK
)
6635 /* flags1 has bit 1 and 8 as reserved for implementations, with no
6636 indication that they must be set to 0, so we don't check them.
6638 hdr
.flags1
= tvb_get_uint8(tvb
, offset
++);
6640 /* flags2 has bit 1 reserved for implementations, bit 2 used,
6641 and the other bits reserved for future use and specified
6642 as "must be set to 0", so if any of the other bits are set
6643 it is probably not DCE/RPC.
6645 hdr
.flags2
= tvb_get_uint8(tvb
, offset
++);
6646 if (hdr
.flags2
&0xfc)
6649 tvb_memcpy(tvb
, (uint8_t *)hdr
.drep
, offset
, sizeof (hdr
.drep
));
6650 offset
+= (int)sizeof (hdr
.drep
);
6651 if (hdr
.drep
[0]&0xee)
6653 if (hdr
.drep
[1] > DCE_RPC_DREP_FP_IBM
)
6656 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "DCERPC");
6657 col_add_str(pinfo
->cinfo
, COL_INFO
, pckt_vals
[hdr
.ptype
].strptr
);
6659 hdr
.serial_hi
= tvb_get_uint8(tvb
, offset
++);
6660 dcerpc_tvb_get_uuid(tvb
, offset
, hdr
.drep
, &hdr
.obj_id
);
6662 dcerpc_tvb_get_uuid(tvb
, offset
, hdr
.drep
, &hdr
.if_id
);
6664 dcerpc_tvb_get_uuid(tvb
, offset
, hdr
.drep
, &hdr
.act_id
);
6666 hdr
.server_boot
= dcerpc_tvb_get_ntohl(tvb
, offset
, hdr
.drep
);
6668 hdr
.if_ver
= dcerpc_tvb_get_ntohl(tvb
, offset
, hdr
.drep
);
6670 hdr
.seqnum
= dcerpc_tvb_get_ntohl(tvb
, offset
, hdr
.drep
);
6672 hdr
.opnum
= dcerpc_tvb_get_ntohs(tvb
, offset
, hdr
.drep
);
6674 hdr
.ihint
= dcerpc_tvb_get_ntohs(tvb
, offset
, hdr
.drep
);
6676 hdr
.ahint
= dcerpc_tvb_get_ntohs(tvb
, offset
, hdr
.drep
);
6678 hdr
.frag_len
= dcerpc_tvb_get_ntohs(tvb
, offset
, hdr
.drep
);
6680 hdr
.frag_num
= dcerpc_tvb_get_ntohs(tvb
, offset
, hdr
.drep
);
6682 hdr
.auth_proto
= tvb_get_uint8(tvb
, offset
++);
6683 hdr
.serial_lo
= tvb_get_uint8(tvb
, offset
++);
6686 ti
= proto_tree_add_item(tree
, proto_dcerpc
, tvb
, 0, -1, ENC_NA
);
6688 dcerpc_tree
= proto_item_add_subtree(ti
, ett_dcerpc
);
6689 proto_item_append_text(ti
, " %s, Seq: %u, Serial: %u, Frag: %u, FragLen: %u",
6690 val_to_str(hdr
.ptype
, pckt_vals
, "Unknown (0x%02x)"),
6691 hdr
.seqnum
, hdr
.serial_hi
*256+hdr
.serial_lo
,
6692 hdr
.frag_num
, hdr
.frag_len
);
6697 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_ver
, tvb
, offset
, 1, hdr
.rpc_ver
);
6700 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_packet_type
, tvb
, offset
, 1, hdr
.ptype
);
6703 proto_tree_add_bitmask_value(dcerpc_tree
, tvb
, offset
, hf_dcerpc_dg_flags1
,
6704 ett_dcerpc_dg_flags1
, hdr_flags1
, hdr
.flags1
);
6707 proto_tree_add_bitmask_value(dcerpc_tree
, tvb
, offset
, hf_dcerpc_dg_flags2
,
6708 ett_dcerpc_dg_flags2
, hdr_flags2
, hdr
.flags2
);
6712 proto_tree_add_dcerpc_drep(dcerpc_tree
, tvb
, offset
, hdr
.drep
, (int)sizeof (hdr
.drep
));
6714 offset
+= (int)sizeof (hdr
.drep
);
6717 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_dg_serial_hi
, tvb
, offset
, 1, hdr
.serial_hi
);
6721 proto_tree_add_guid_format(dcerpc_tree
, hf_dcerpc_obj_id
, tvb
,
6722 offset
, 16, (e_guid_t
*) &hdr
.obj_id
, "Object UUID: %s",
6723 guid_to_str(pinfo
->pool
, (e_guid_t
*) &hdr
.obj_id
));
6728 uuid_str
= guid_to_str(pinfo
->pool
, (e_guid_t
*)&hdr
.if_id
);
6729 uuid_name
= guids_get_uuid_name(&hdr
.if_id
, pinfo
->pool
);
6731 proto_tree_add_guid_format(dcerpc_tree
, hf_dcerpc_dg_if_id
, tvb
,
6732 offset
, 16, (e_guid_t
*) &hdr
.if_id
, "Interface: %s UUID: %s", uuid_name
, uuid_str
);
6734 proto_tree_add_guid_format(dcerpc_tree
, hf_dcerpc_dg_if_id
, tvb
,
6735 offset
, 16, (e_guid_t
*) &hdr
.if_id
, "Interface UUID: %s", uuid_str
);
6741 proto_tree_add_guid_format(dcerpc_tree
, hf_dcerpc_dg_act_id
, tvb
,
6742 offset
, 16, (e_guid_t
*) &hdr
.act_id
, "Activity: %s",
6743 guid_to_str(pinfo
->pool
, (e_guid_t
*) &hdr
.act_id
));
6748 nstime_t server_boot
;
6750 server_boot
.secs
= hdr
.server_boot
;
6751 server_boot
.nsecs
= 0;
6753 if (hdr
.server_boot
== 0)
6754 proto_tree_add_time_format_value(dcerpc_tree
, hf_dcerpc_dg_server_boot
,
6755 tvb
, offset
, 4, &server_boot
,
6758 proto_tree_add_time(dcerpc_tree
, hf_dcerpc_dg_server_boot
,
6759 tvb
, offset
, 4, &server_boot
);
6764 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_dg_if_ver
, tvb
, offset
, 4, hdr
.if_ver
);
6768 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_dg_seqnum
, tvb
, offset
, 4, hdr
.seqnum
);
6769 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ": seq: %u", hdr
.seqnum
);
6773 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_opnum
, tvb
, offset
, 2, hdr
.opnum
);
6777 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_dg_ihint
, tvb
, offset
, 2, hdr
.ihint
);
6781 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_dg_ahint
, tvb
, offset
, 2, hdr
.ahint
);
6785 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_dg_frag_len
, tvb
, offset
, 2, hdr
.frag_len
);
6789 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_dg_frag_num
, tvb
, offset
, 2, hdr
.frag_num
);
6790 if (hdr
.flags1
& PFCL1_FRAG
) {
6791 /* Fragmented - put the fragment number into the Info column */
6792 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " frag: %u",
6798 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_dg_auth_proto
, tvb
, offset
, 1, hdr
.auth_proto
);
6802 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_dg_serial_lo
, tvb
, offset
, 1, hdr
.serial_lo
);
6803 if (hdr
.flags1
& PFCL1_FRAG
) {
6804 /* Fragmented - put the serial number into the Info column */
6805 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " serial: %u",
6806 (hdr
.serial_hi
<< 8) | hdr
.serial_lo
);
6812 * XXX - for Kerberos, we get a protection level; if it's
6813 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
6816 dissect_dcerpc_dg_auth(tvb
, offset
, dcerpc_tree
, &hdr
,
6821 * keeping track of the conversation shouldn't really be necessary
6822 * for connectionless packets, because everything we need to know
6823 * to dissect is in the header for each packet. Unfortunately,
6824 * Microsoft's implementation is buggy and often puts the
6825 * completely wrong if_id in the header. go figure. So, keep
6826 * track of the seqnum and use that if possible. Note: that's not
6827 * completely correct. It should really be done based on both the
6828 * activity_id and seqnum. I haven't seen anywhere that it would
6829 * make a difference, but for future reference...
6831 conv
= find_or_create_conversation(pinfo
);
6834 * Packet type specific stuff is next.
6837 switch (hdr
.ptype
) {
6839 case PDU_CANCEL_ACK
:
6840 /* Body is optional */
6841 /* XXX - we assume "frag_len" is the length of the body */
6842 if (hdr
.frag_len
!= 0)
6843 dissect_dcerpc_dg_cancel_ack(tvb
, offset
, pinfo
, dcerpc_tree
, &hdr
);
6848 * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
6849 * but in at least one capture none of the Cl_cancel PDUs had a
6852 /* XXX - we assume "frag_len" is the length of the body */
6853 if (hdr
.frag_len
!= 0)
6854 dissect_dcerpc_dg_cancel(tvb
, offset
, pinfo
, dcerpc_tree
, &hdr
);
6858 /* Body is optional; if present, it's the same as PDU_FACK */
6859 /* XXX - we assume "frag_len" is the length of the body */
6860 if (hdr
.frag_len
!= 0)
6861 dissect_dcerpc_dg_fack(tvb
, offset
, pinfo
, dcerpc_tree
, &hdr
);
6865 /* Body is optional */
6866 /* XXX - we assume "frag_len" is the length of the body */
6867 if (hdr
.frag_len
!= 0)
6868 dissect_dcerpc_dg_fack(tvb
, offset
, pinfo
, dcerpc_tree
, &hdr
);
6873 dissect_dcerpc_dg_reject_fault(tvb
, offset
, pinfo
, dcerpc_tree
, &hdr
);
6877 dissect_dcerpc_dg_rqst(tvb
, offset
, pinfo
, dcerpc_tree
, tree
, &hdr
, conv
);
6881 dissect_dcerpc_dg_resp(tvb
, offset
, pinfo
, dcerpc_tree
, tree
, &hdr
, conv
);
6884 /* these requests have no body */
6887 dissect_dcerpc_dg_ping_ack(tvb
, offset
, pinfo
, dcerpc_tree
, &hdr
, conv
);
6898 dcerpc_auth_subdissector_list_free(void *p
, void *user_data _U_
)
6904 dcerpc_shutdown(void)
6906 g_slist_foreach(dcerpc_auth_subdissector_list
, dcerpc_auth_subdissector_list_free
, NULL
);
6907 g_slist_free(dcerpc_auth_subdissector_list
);
6908 g_hash_table_destroy(dcerpc_uuids
);
6909 tvb_free(tvb_trailer_signature
);
6913 proto_register_dcerpc(void)
6915 static hf_register_info hf
[] = {
6916 { &hf_dcerpc_request_in
,
6917 { "Request in frame", "dcerpc.request_in", FT_FRAMENUM
, BASE_NONE
,
6918 FRAMENUM_TYPE(FT_FRAMENUM_REQUEST
), 0, "This packet is a response to the packet with this number", HFILL
}},
6919 { &hf_dcerpc_response_in
,
6920 { "Response in frame", "dcerpc.response_in", FT_FRAMENUM
, BASE_NONE
,
6921 FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE
), 0, "This packet will be responded in the packet with this number", HFILL
}},
6922 { &hf_dcerpc_referent_id32
,
6923 { "Referent ID", "dcerpc.referent_id", FT_UINT32
, BASE_HEX
,
6924 NULL
, 0, "Referent ID for this NDR encoded pointer", HFILL
}},
6925 { &hf_dcerpc_referent_id64
,
6926 { "Referent ID", "dcerpc.referent_id64", FT_UINT64
, BASE_HEX
,
6927 NULL
, 0, "Referent ID for this NDR encoded pointer", HFILL
}},
6929 { "Version", "dcerpc.ver", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
6930 { &hf_dcerpc_ver_minor
,
6931 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
6932 { &hf_dcerpc_packet_type
,
6933 { "Packet type", "dcerpc.pkt_type", FT_UINT8
, BASE_DEC
, VALS(pckt_vals
), 0x0, NULL
, HFILL
}},
6934 { &hf_dcerpc_cn_flags
,
6935 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
6936 { &hf_dcerpc_cn_flags_first_frag
,
6937 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFC_FIRST_FRAG
, NULL
, HFILL
}},
6938 { &hf_dcerpc_cn_flags_last_frag
,
6939 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFC_LAST_FRAG
, NULL
, HFILL
}},
6940 { &hf_dcerpc_cn_flags_cancel_pending
,
6941 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFC_PENDING_CANCEL
, NULL
, HFILL
}},
6942 { &hf_dcerpc_cn_flags_reserved
,
6943 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFC_RESERVED_1
, NULL
, HFILL
}},
6944 { &hf_dcerpc_cn_flags_mpx
,
6945 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFC_CONC_MPX
, NULL
, HFILL
}},
6946 { &hf_dcerpc_cn_flags_dne
,
6947 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFC_DID_NOT_EXECUTE
, NULL
, HFILL
}},
6948 { &hf_dcerpc_cn_flags_maybe
,
6949 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFC_MAYBE
, NULL
, HFILL
}},
6950 { &hf_dcerpc_cn_flags_object
,
6951 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFC_OBJECT_UUID
, NULL
, HFILL
}},
6953 { "Data Representation", "dcerpc.drep", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
6954 { &hf_dcerpc_drep_byteorder
,
6955 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8
, BASE_DEC
, VALS(drep_byteorder_vals
), 0x0, NULL
, HFILL
}},
6956 { &hf_dcerpc_ndr_padding
,
6957 { "NDR-Padding", "dcerpc.ndr_padding", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
6958 { &hf_dcerpc_drep_character
,
6959 { "Character", "dcerpc.drep.character", FT_UINT8
, BASE_DEC
, VALS(drep_character_vals
), 0x0, NULL
, HFILL
}},
6960 { &hf_dcerpc_drep_fp
,
6961 { "Floating-point", "dcerpc.drep.fp", FT_UINT8
, BASE_DEC
, VALS(drep_fp_vals
), 0x0, NULL
, HFILL
}},
6962 { &hf_dcerpc_cn_frag_len
,
6963 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
6964 { &hf_dcerpc_cn_auth_len
,
6965 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
6966 { &hf_dcerpc_cn_call_id
,
6967 { "Call ID", "dcerpc.cn_call_id", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
6968 { &hf_dcerpc_cn_max_xmit
,
6969 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
6970 { &hf_dcerpc_cn_max_recv
,
6971 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
6972 { &hf_dcerpc_cn_assoc_group
,
6973 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
6974 { &hf_dcerpc_cn_num_ctx_items
,
6975 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
6976 { &hf_dcerpc_cn_ctx_item
,
6977 { "Ctx Item", "dcerpc.cn_ctx_item", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
6978 { &hf_dcerpc_cn_ctx_id
,
6979 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
6980 { &hf_dcerpc_cn_num_trans_items
,
6981 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
6982 { &hf_dcerpc_cn_bind_abstract_syntax
,
6983 { "Abstract Syntax", "dcerpc.cn_bind_abstract_syntax", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
6984 { &hf_dcerpc_cn_bind_if_id
,
6985 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_GUID
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
6986 { &hf_dcerpc_cn_bind_if_ver
,
6987 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
6988 { &hf_dcerpc_cn_bind_if_ver_minor
,
6989 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
6990 { &hf_dcerpc_cn_bind_trans_syntax
,
6991 { "Transfer Syntax", "dcerpc.cn_bind_trans", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
6992 { &hf_dcerpc_cn_bind_trans_id
,
6993 { "ID", "dcerpc.cn_bind_trans_id", FT_GUID
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
6994 { &hf_dcerpc_cn_bind_trans_ver
,
6995 { "ver", "dcerpc.cn_bind_trans_ver", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
6996 { &hf_dcerpc_cn_bind_trans_btfn
, /* [MS-RPCE] 2.2.2.14 */
6997 {"Bind Time Features", "dcerpc.cn_bind_trans_btfn", FT_UINT16
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}},
6998 { &hf_dcerpc_cn_bind_trans_btfn_01
,
6999 { "Security Context Multiplexing Supported", "dcerpc.cn_bind_trans_btfn.01", FT_BOOLEAN
, 16, NULL
, 0x0001, NULL
, HFILL
}},
7000 { &hf_dcerpc_cn_bind_trans_btfn_02
,
7001 { "Keep Connection On Orphan Supported", "dcerpc.cn_bind_trans_btfn.02", FT_BOOLEAN
, 16, NULL
, 0x0002, NULL
, HFILL
}},
7002 { &hf_dcerpc_cn_bind_trans_btfn_04
,
7003 { "Support SHA512 PREAUTH Verification", "dcerpc.cn_bind_trans_btfn.04", FT_BOOLEAN
, 16, NULL
, 0x0004, NULL
, HFILL
}},
7004 { &hf_dcerpc_cn_bind_trans_btfn_08
,
7005 { "Support protection of all PDUs", "dcerpc.cn_bind_trans_btfn.08", FT_BOOLEAN
, 16, NULL
, 0x0008, NULL
, HFILL
}},
7006 { &hf_dcerpc_cn_alloc_hint
,
7007 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7008 { &hf_dcerpc_cn_sec_addr_len
,
7009 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7010 { &hf_dcerpc_cn_sec_addr
,
7011 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7012 { &hf_dcerpc_cn_num_results
,
7013 { "Num results", "dcerpc.cn_num_results", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7014 { &hf_dcerpc_cn_ack_result
,
7015 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16
, BASE_DEC
, VALS(p_cont_result_vals
), 0x0, NULL
, HFILL
}},
7016 { &hf_dcerpc_cn_ack_reason
,
7017 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16
, BASE_DEC
, VALS(p_provider_reason_vals
), 0x0, NULL
, HFILL
}},
7018 { &hf_dcerpc_cn_ack_trans_id
,
7019 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_GUID
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7020 { &hf_dcerpc_cn_ack_trans_ver
,
7021 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7022 { &hf_dcerpc_cn_reject_reason
,
7023 { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16
, BASE_DEC
, VALS(reject_reason_vals
), 0x0, NULL
, HFILL
}},
7024 { &hf_dcerpc_cn_num_protocols
,
7025 { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7026 { &hf_dcerpc_cn_protocol_ver_major
,
7027 { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7028 { &hf_dcerpc_cn_protocol_ver_minor
,
7029 { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7030 { &hf_dcerpc_cn_cancel_count
,
7031 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7032 { &hf_dcerpc_cn_fault_flags
,
7033 { "Fault flags", "dcerpc.cn_fault_flags", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7034 { &hf_dcerpc_cn_fault_flags_extended_error_info
,
7035 { "Extended error information present", "dcerpc.cn_fault_flags.extended_error", FT_BOOLEAN
, 8, NULL
, 0x1, NULL
, HFILL
}},
7036 { &hf_dcerpc_cn_status
,
7037 { "Status", "dcerpc.cn_status", FT_UINT32
, BASE_HEX
, VALS(reject_status_vals
), 0x0, NULL
, HFILL
}},
7038 { &hf_dcerpc_cn_deseg_req
,
7039 { "Desegmentation Required", "dcerpc.cn_deseg_req", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7040 { &hf_dcerpc_auth_type
,
7041 { "Auth type", "dcerpc.auth_type", FT_UINT8
, BASE_DEC
, VALS(authn_protocol_vals
), 0x0, NULL
, HFILL
}},
7042 { &hf_dcerpc_auth_level
,
7043 { "Auth level", "dcerpc.auth_level", FT_UINT8
, BASE_DEC
, VALS(authn_level_vals
), 0x0, NULL
, HFILL
}},
7044 { &hf_dcerpc_auth_pad_len
,
7045 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7046 { &hf_dcerpc_auth_rsrvd
,
7047 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7048 { &hf_dcerpc_auth_ctx_id
,
7049 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7050 { &hf_dcerpc_dg_flags1
,
7051 { "Flags1", "dcerpc.dg_flags1", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7052 { &hf_dcerpc_dg_flags1_rsrvd_01
,
7053 { "Reserved for implementation", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL1_RESERVED_01
, NULL
, HFILL
}},
7054 { &hf_dcerpc_dg_flags1_last_frag
,
7055 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL1_LASTFRAG
, NULL
, HFILL
}},
7056 { &hf_dcerpc_dg_flags1_frag
,
7057 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL1_FRAG
, NULL
, HFILL
}},
7058 { &hf_dcerpc_dg_flags1_nofack
,
7059 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL1_NOFACK
, NULL
, HFILL
}},
7060 { &hf_dcerpc_dg_flags1_maybe
,
7061 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL1_MAYBE
, NULL
, HFILL
}},
7062 { &hf_dcerpc_dg_flags1_idempotent
,
7063 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL1_IDEMPOTENT
, NULL
, HFILL
}},
7064 { &hf_dcerpc_dg_flags1_broadcast
,
7065 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL1_BROADCAST
, NULL
, HFILL
}},
7066 { &hf_dcerpc_dg_flags1_rsrvd_80
,
7067 { "Reserved for implementation", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL1_RESERVED_80
, NULL
, HFILL
}},
7068 { &hf_dcerpc_dg_flags2
,
7069 { "Flags2", "dcerpc.dg_flags2", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7070 { &hf_dcerpc_dg_flags2_rsrvd_01
,
7071 { "Reserved for implementation", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL2_RESERVED_01
, NULL
, HFILL
}},
7072 { &hf_dcerpc_dg_flags2_cancel_pending
,
7073 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL2_CANCEL_PENDING
, NULL
, HFILL
}},
7074 { &hf_dcerpc_dg_flags2_rsrvd_04
,
7075 { "Reserved for future use (MBZ)", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL2_RESERVED_04
, NULL
, HFILL
}},
7076 { &hf_dcerpc_dg_flags2_rsrvd_08
,
7077 { "Reserved for future use (MBZ)", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL2_RESERVED_08
, NULL
, HFILL
}},
7078 { &hf_dcerpc_dg_flags2_rsrvd_10
,
7079 { "Reserved for future use (MBZ)", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL2_RESERVED_10
, NULL
, HFILL
}},
7080 { &hf_dcerpc_dg_flags2_rsrvd_20
,
7081 { "Reserved for future use (MBZ)", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL2_RESERVED_20
, NULL
, HFILL
}},
7082 { &hf_dcerpc_dg_flags2_rsrvd_40
,
7083 { "Reserved for future use (MBZ)", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL2_RESERVED_40
, NULL
, HFILL
}},
7084 { &hf_dcerpc_dg_flags2_rsrvd_80
,
7085 { "Reserved for future use (MBZ)", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL2_RESERVED_80
, NULL
, HFILL
}},
7086 { &hf_dcerpc_dg_serial_lo
,
7087 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7088 { &hf_dcerpc_dg_serial_hi
,
7089 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7090 { &hf_dcerpc_dg_ahint
,
7091 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7092 { &hf_dcerpc_dg_ihint
,
7093 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7094 { &hf_dcerpc_dg_frag_len
,
7095 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7096 { &hf_dcerpc_dg_frag_num
,
7097 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7098 { &hf_dcerpc_dg_auth_proto
,
7099 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8
, BASE_DEC
, VALS(authn_protocol_vals
), 0x0, NULL
, HFILL
}},
7100 { &hf_dcerpc_dg_seqnum
,
7101 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7102 { &hf_dcerpc_dg_server_boot
,
7103 { "Server boot time", "dcerpc.dg_server_boot", FT_ABSOLUTE_TIME
, ABSOLUTE_TIME_LOCAL
, NULL
, 0x0, NULL
, HFILL
}},
7104 { &hf_dcerpc_dg_if_ver
,
7105 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7106 { &hf_dcerpc_krb5_av_prot_level
,
7107 { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8
, BASE_DEC
, VALS(authn_level_vals
), 0x0, NULL
, HFILL
}},
7108 { &hf_dcerpc_krb5_av_key_vers_num
,
7109 { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7110 { &hf_dcerpc_krb5_av_key_auth_verifier
,
7111 { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7112 { &hf_dcerpc_obj_id
,
7113 { "Object", "dcerpc.obj_id", FT_GUID
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7114 { &hf_dcerpc_dg_if_id
,
7115 { "Interface", "dcerpc.dg_if_id", FT_GUID
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7116 { &hf_dcerpc_dg_act_id
,
7117 { "Activity", "dcerpc.dg_act_id", FT_GUID
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7119 { "Opnum", "dcerpc.opnum", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7121 { &hf_dcerpc_dg_cancel_vers
,
7122 { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7124 { &hf_dcerpc_dg_cancel_id
,
7125 { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7127 { &hf_dcerpc_dg_server_accepting_cancels
,
7128 { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7130 { &hf_dcerpc_dg_fack_vers
,
7131 { "FACK Version", "dcerpc.fack_vers", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7133 { &hf_dcerpc_dg_fack_window_size
,
7134 { "Window Size", "dcerpc.fack_window_size", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7136 { &hf_dcerpc_dg_fack_max_tsdu
,
7137 { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7139 { &hf_dcerpc_dg_fack_max_frag_size
,
7140 { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7142 { &hf_dcerpc_dg_fack_serial_num
,
7143 { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7145 { &hf_dcerpc_dg_fack_selack_len
,
7146 { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7148 { &hf_dcerpc_dg_fack_selack
,
7149 { "Selective ACK", "dcerpc.fack_selack", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7151 { &hf_dcerpc_dg_status
,
7152 { "Status", "dcerpc.dg_status", FT_UINT32
, BASE_HEX
, VALS(reject_status_vals
), 0x0, NULL
, HFILL
}},
7154 { &hf_dcerpc_array_max_count
,
7155 { "Max Count", "dcerpc.array.max_count", FT_UINT32
, BASE_DEC
, NULL
, 0x0, "Maximum Count: Number of elements in the array", HFILL
}},
7157 { &hf_dcerpc_array_offset
,
7158 { "Offset", "dcerpc.array.offset", FT_UINT32
, BASE_DEC
, NULL
, 0x0, "Offset for first element in array", HFILL
}},
7160 { &hf_dcerpc_array_actual_count
,
7161 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32
, BASE_DEC
, NULL
, 0x0, "Actual Count: Actual number of elements in the array", HFILL
}},
7164 { "Operation", "dcerpc.op", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7166 { &hf_dcerpc_null_pointer
,
7167 { "NULL Pointer", "dcerpc.null_pointer", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7169 { &hf_dcerpc_fragments
,
7170 { "Reassembled DCE/RPC Fragments", "dcerpc.fragments", FT_NONE
, BASE_NONE
,
7171 NULL
, 0x0, NULL
, HFILL
}},
7173 { &hf_dcerpc_fragment
,
7174 { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM
, BASE_NONE
,
7175 NULL
, 0x0, NULL
, HFILL
}},
7177 { &hf_dcerpc_fragment_overlap
,
7178 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN
, BASE_NONE
,
7179 NULL
, 0x0, "Fragment overlaps with other fragments", HFILL
}},
7181 { &hf_dcerpc_fragment_overlap_conflict
,
7182 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN
, BASE_NONE
,
7183 NULL
, 0x0, "Overlapping fragments contained conflicting data", HFILL
}},
7185 { &hf_dcerpc_fragment_multiple_tails
,
7186 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN
, BASE_NONE
,
7187 NULL
, 0x0, "Several tails were found when defragmenting the packet", HFILL
}},
7189 { &hf_dcerpc_fragment_too_long_fragment
,
7190 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN
, BASE_NONE
,
7191 NULL
, 0x0, "Fragment contained data past end of packet", HFILL
}},
7193 { &hf_dcerpc_fragment_error
,
7194 { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM
, BASE_NONE
,
7195 NULL
, 0x0, "Defragmentation error due to illegal fragments", HFILL
}},
7197 { &hf_dcerpc_fragment_count
,
7198 { "Fragment count", "dcerpc.fragment.count", FT_UINT32
, BASE_DEC
,
7199 NULL
, 0x0, NULL
, HFILL
}},
7202 { "Time from request", "dcerpc.time", FT_RELATIVE_TIME
, BASE_NONE
,
7203 NULL
, 0, "Time between Request and Response for DCE-RPC calls", HFILL
}},
7205 { &hf_dcerpc_reassembled_in
,
7206 { "Reassembled PDU in frame", "dcerpc.reassembled_in", FT_FRAMENUM
, BASE_NONE
,
7207 NULL
, 0x0, "The DCE/RPC PDU is completely reassembled in the packet with this number", HFILL
}},
7209 { &hf_dcerpc_reassembled_length
,
7210 { "Reassembled DCE/RPC length", "dcerpc.reassembled.length", FT_UINT32
, BASE_DEC
,
7211 NULL
, 0x0, "The total length of the reassembled payload", HFILL
}},
7213 { &hf_dcerpc_unknown_if_id
,
7214 { "Unknown DCERPC interface id", "dcerpc.unknown_if_id", FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7216 { &hf_dcerpc_cn_rts_flags
,
7217 { "RTS Flags", "dcerpc.cn_rts_flags", FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7218 { &hf_dcerpc_cn_rts_flags_ping
,
7219 { "Ping", "dcerpc.cn_rts.flags.ping", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), RTS_FLAG_PING
, NULL
, HFILL
}},
7220 { &hf_dcerpc_cn_rts_flags_other_cmd
,
7221 { "Other Cmd", "dcerpc.cn_rts_flags.other_cmd", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), RTS_FLAG_OTHER_CMD
, NULL
, HFILL
}},
7222 { &hf_dcerpc_cn_rts_flags_recycle_channel
,
7223 { "Recycle Channel", "dcerpc.cn_rts_flags.recycle_channel", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), RTS_FLAG_RECYCLE_CHANNEL
, NULL
, HFILL
}},
7224 { &hf_dcerpc_cn_rts_flags_in_channel
,
7225 { "In Channel", "dcerpc.cn_rts_flags.in_channel", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), RTS_FLAG_IN_CHANNEL
, NULL
, HFILL
}},
7226 { &hf_dcerpc_cn_rts_flags_out_channel
,
7227 { "Out Channel", "dcerpc.cn_rts_flags.out_channel", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), RTS_FLAG_OUT_CHANNEL
, NULL
, HFILL
}},
7228 { &hf_dcerpc_cn_rts_flags_eof
,
7229 { "EOF", "dcerpc.cn_rts_flags.eof", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), RTS_FLAG_EOF
, NULL
, HFILL
}},
7230 { &hf_dcerpc_cn_rts_commands_nb
,
7231 { "RTS Number of Commands", "dcerpc.cn_rts_commands_nb", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7232 { &hf_dcerpc_cn_rts_command
,
7233 { "RTS Command", "dcerpc.cn_rts_command", FT_UINT32
, BASE_HEX
, VALS(rts_command_vals
), 0x0, NULL
, HFILL
}},
7234 { &hf_dcerpc_cn_rts_command_receivewindowsize
,
7235 {"Receive Window Size", "dcerpc.cn_rts_command.receivewindowsize", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7236 { &hf_dcerpc_cn_rts_command_fack_bytesreceived
,
7237 {"Bytes Received", "dcerpc.cn_rts_command.fack.bytesreceived", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7238 { &hf_dcerpc_cn_rts_command_fack_availablewindow
,
7239 {"Available Window", "dcerpc.cn_rts_command.fack.availablewindow", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7240 { &hf_dcerpc_cn_rts_command_fack_channelcookie
,
7241 {"Channel Cookie", "dcerpc.cn_rts_command.fack.channelcookie", FT_GUID
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7242 { &hf_dcerpc_cn_rts_command_connectiontimeout
,
7243 {"Connection Timeout", "dcerpc.cn_rts_command.connectiontimeout", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7244 { &hf_dcerpc_cn_rts_command_cookie
,
7245 {"Cookie", "dcerpc.cn_rts_command.cookie", FT_GUID
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7246 { &hf_dcerpc_cn_rts_command_channellifetime
,
7247 {"Channel Lifetime", "dcerpc.cn_rts_command.channellifetime", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7248 { &hf_dcerpc_cn_rts_command_clientkeepalive
,
7249 {"Client Keepalive", "dcerpc.cn_rts_command.clientkeepalive", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7250 { &hf_dcerpc_cn_rts_command_version
,
7251 {"Version", "dcerpc.cn_rts_command.version", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7252 { &hf_dcerpc_cn_rts_command_conformancecount
,
7253 {"Conformance Count", "dcerpc.cn_rts_command.padding.conformancecount", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7254 { &hf_dcerpc_cn_rts_command_padding
,
7255 { "Padding", "dcerpc.cn_rts_command.padding.padding", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7256 { &hf_dcerpc_cn_rts_command_addrtype
,
7257 { "Address Type", "dcerpc.cn_rts_command.addrtype", FT_UINT32
, BASE_DEC
, VALS(rts_addresstype_vals
), 0x0, NULL
, HFILL
}},
7258 { &hf_dcerpc_cn_rts_command_associationgroupid
,
7259 {"Association Group ID", "dcerpc.cn_rts_command.associationgroupid", FT_GUID
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7260 { &hf_dcerpc_cn_rts_command_forwarddestination
,
7261 {"Forward Destination", "dcerpc.cn_rts_command.forwarddestination", FT_UINT32
, BASE_DEC
, VALS(rts_forward_destination_vals
), 0x0, NULL
, HFILL
}},
7262 { &hf_dcerpc_cn_rts_command_pingtrafficsentnotify
,
7263 {"Ping Traffic Sent Notify", "dcerpc.cn_rts_command.pingtrafficsentnotify", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7264 { &hf_dcerpc_sec_vt_signature
,
7265 {"SEC_VT_SIGNATURE", "dcerpc.rpc_sec_vt.signature", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7266 { &hf_dcerpc_sec_vt_command_end
,
7267 {"SEC_VT_COMMAND_END", "dcerpc.rpc_sec_vt.command.end", FT_BOOLEAN
, 16, NULL
, 0x4000, NULL
, HFILL
}},
7268 { &hf_dcerpc_sec_vt_command_must
,
7269 {"SEC_VT_MUST_PROCESS_COMMAND", "dcerpc.rpc_sec_vt.command.must_process", FT_BOOLEAN
, 16, NULL
, 0x8000, NULL
, HFILL
}},
7270 { &hf_dcerpc_sec_vt_command_cmd
,
7271 {"Cmd", "dcerpc.rpc_sec_vt.command.cmd", FT_UINT16
, BASE_HEX
, VALS(sec_vt_command_cmd_vals
), 0x3fff, NULL
, HFILL
}},
7272 { &hf_dcerpc_sec_vt_command
,
7273 {"Command", "dcerpc.rpc_sec_vt.command", FT_UINT16
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}},
7274 { &hf_dcerpc_sec_vt_command_length
,
7275 {"Length", "dcerpc.rpc_sec_vt.command.length", FT_UINT16
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}},
7276 { &hf_dcerpc_sec_vt_bitmask
,
7277 {"rpc_sec_vt_bitmask", "dcerpc.rpc_sec_vt.bitmask", FT_UINT32
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}},
7278 { &hf_dcerpc_sec_vt_bitmask_sign
,
7279 {"CLIENT_SUPPORT_HEADER_SIGNING", "dcerpc.rpc_sec_vt.bitmask.sign", FT_BOOLEAN
, 32, NULL
, 0x1, NULL
, HFILL
}},
7280 { &hf_dcerpc_sec_vt_pcontext_uuid
,
7281 {"UUID", "dcerpc.rpc_sec_vt.pcontext.interface.uuid", FT_GUID
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}},
7282 { &hf_dcerpc_sec_vt_pcontext_ver
,
7283 {"Version", "dcerpc.rpc_sec_vt.pcontext.interface.ver", FT_UINT32
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}},
7284 { &hf_dcerpc_sec_vt_preauth_salt
,
7285 {"Salt", "dcerpc.rpc_sec_vt.preauth.salt", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7286 { &hf_dcerpc_sec_vt_preauth_sha512
,
7287 {"SHA512 Hash", "dcerpc.rpc_sec_vt.preauth.sha512", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7288 { &hf_dcerpc_reserved
,
7289 {"Reserved", "dcerpc.reserved", FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}},
7290 { &hf_dcerpc_unknown
,
7291 {"Unknown", "dcerpc.unknown", FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}},
7292 { &hf_dcerpc_missalign
,
7293 {"missalign", "dcerpc.missalign", FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}},
7294 /* Generated from convert_proto_tree_add_text.pl */
7295 { &hf_dcerpc_duplicate_ptr
, { "duplicate PTR", "dcerpc.duplicate_ptr", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7296 { &hf_dcerpc_encrypted_stub_data
, { "Encrypted stub data", "dcerpc.encrypted_stub_data", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7297 { &hf_dcerpc_decrypted_stub_data
, { "Decrypted stub data", "dcerpc.decrypted_stub_data", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7298 { &hf_dcerpc_payload_stub_data
, { "Payload stub data", "dcerpc.payload_stub_data", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7299 { &hf_dcerpc_stub_data_with_sec_vt
, { "Stub data with rpc_sec_verification_trailer", "dcerpc.stub_data_with_sec_vt", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7300 { &hf_dcerpc_stub_data
, { "Stub data", "dcerpc.stub_data", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7301 { &hf_dcerpc_auth_padding
, { "Auth Padding", "dcerpc.auth_padding", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7302 { &hf_dcerpc_auth_info
, { "Auth Info", "dcerpc.auth_info", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7303 { &hf_dcerpc_auth_credentials
, { "Auth Credentials", "dcerpc.auth_credentials", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7304 { &hf_dcerpc_fault_stub_data
, { "Fault stub data", "dcerpc.fault_stub_data", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7305 { &hf_dcerpc_fragment_data
, { "Fragment data", "dcerpc.fragment_data", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7306 { &hf_dcerpc_cmd_client_ipv4
, { "RTS Client address", "dcerpc.cmd_client_ipv4", FT_IPv4
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7307 { &hf_dcerpc_cmd_client_ipv6
, { "RTS Client address", "dcerpc.cmd_client_ipv6", FT_IPv6
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7308 { &hf_dcerpc_authentication_verifier
, { "Authentication verifier", "dcerpc.authentication_verifier", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7310 static int *ett
[] = {
7312 &ett_dcerpc_cn_flags
,
7314 &ett_dcerpc_cn_iface
,
7315 &ett_dcerpc_cn_trans_syntax
,
7316 &ett_dcerpc_cn_trans_btfn
,
7317 &ett_dcerpc_cn_bind_trans_btfn
,
7318 &ett_dcerpc_cn_rts_flags
,
7319 &ett_dcerpc_cn_rts_command
,
7320 &ett_dcerpc_cn_rts_pdu
,
7322 &ett_dcerpc_dg_flags1
,
7323 &ett_dcerpc_dg_flags2
,
7324 &ett_dcerpc_pointer_data
,
7326 &ett_dcerpc_fragments
,
7327 &ett_dcerpc_fragment
,
7328 &ett_dcerpc_krb5_auth_verf
,
7329 &ett_dcerpc_auth_info
,
7330 &ett_dcerpc_verification_trailer
,
7331 &ett_dcerpc_sec_vt_command
,
7332 &ett_dcerpc_sec_vt_bitmask
,
7333 &ett_dcerpc_sec_vt_pcontext
,
7334 &ett_dcerpc_sec_vt_header
,
7335 &ett_dcerpc_sec_vt_preauth
,
7336 &ett_dcerpc_complete_stub_data
,
7337 &ett_dcerpc_fault_flags
,
7338 &ett_dcerpc_fault_stub_data
,
7341 static ei_register_info ei
[] = {
7342 { &ei_dcerpc_fragment
, { "dcerpc.fragment.reassemble", PI_REASSEMBLE
, PI_CHAT
, "Fragment", EXPFILL
}},
7343 { &ei_dcerpc_fragment_reassembled
, { "dcerpc.fragment_reassembled", PI_REASSEMBLE
, PI_CHAT
, "Fragment, reassembled", EXPFILL
}},
7344 { &ei_dcerpc_cn_ctx_id_no_bind
, { "dcerpc.cn_ctx_id.no_bind", PI_UNDECODED
, PI_NOTE
, "No bind info for interface Context ID", EXPFILL
}},
7345 { &ei_dcerpc_no_request_found
, { "dcerpc.no_request_found", PI_SEQUENCE
, PI_NOTE
, "No request to this DCE/RPC call found", EXPFILL
}},
7346 { &ei_dcerpc_cn_status
, { "dcerpc.cn_status.expert", PI_RESPONSE_CODE
, PI_NOTE
, "Fault", EXPFILL
}},
7347 { &ei_dcerpc_fragment_multiple
, { "dcerpc.fragment_multiple", PI_SEQUENCE
, PI_CHAT
, "Multiple DCE/RPC fragments/PDU's in one packet", EXPFILL
}},
7348 #if 0 /* XXX - too much "output noise", removed for now */
7349 { &ei_dcerpc_context_change
, { "dcerpc.context_change", PI_SEQUENCE
, PI_CHAT
, "Context change", EXPFILL
}},
7351 { &ei_dcerpc_bind_not_acknowledged
, { "dcerpc.bind_not_acknowledged", PI_SEQUENCE
, PI_WARN
, "Bind not acknowledged", EXPFILL
}},
7352 { &ei_dcerpc_verifier_unavailable
, { "dcerpc.verifier_unavailable", PI_UNDECODED
, PI_WARN
, "Verifier unavailable", EXPFILL
}},
7353 { &ei_dcerpc_invalid_pdu_authentication_attempt
, { "dcerpc.invalid_pdu_authentication_attempt", PI_UNDECODED
, PI_WARN
, "Invalid authentication attempt", EXPFILL
}},
7354 /* Generated from convert_proto_tree_add_text.pl */
7355 { &ei_dcerpc_long_frame
, { "dcerpc.long_frame", PI_PROTOCOL
, PI_WARN
, "Long frame", EXPFILL
}},
7356 { &ei_dcerpc_cn_rts_command
, { "dcerpc.cn_rts_command.unknown", PI_PROTOCOL
, PI_WARN
, "unknown RTS command number", EXPFILL
}},
7357 { &ei_dcerpc_not_implemented
, { "dcerpc.not_implemented", PI_UNDECODED
, PI_WARN
, "dissection not implemented", EXPFILL
}},
7360 /* Decode As handling */
7361 static build_valid_func dcerpc_da_build_value
[1] = {dcerpc_value
};
7362 static decode_as_value_t dcerpc_da_values
= {dcerpc_prompt
, 1, dcerpc_da_build_value
};
7363 static decode_as_t dcerpc_da
= {"dcerpc", "dcerpc.uuid",
7364 1, 0, &dcerpc_da_values
, NULL
, NULL
,
7365 dcerpc_populate_list
, decode_dcerpc_binding_reset
, dcerpc_decode_as_change
, dcerpc_decode_as_free
};
7367 module_t
*dcerpc_module
;
7368 expert_module_t
* expert_dcerpc
;
7370 proto_dcerpc
= proto_register_protocol("Distributed Computing Environment / Remote Procedure Call (DCE/RPC)", "DCERPC", "dcerpc");
7371 proto_register_field_array(proto_dcerpc
, hf
, array_length(hf
));
7372 proto_register_subtree_array(ett
, array_length(ett
));
7373 expert_dcerpc
= expert_register_protocol(proto_dcerpc
);
7374 expert_register_field_array(expert_dcerpc
, ei
, array_length(ei
));
7376 uuid_dissector_table
= register_dissector_table(DCERPC_TABLE_NAME
, "DCE/RPC UUIDs", proto_dcerpc
, FT_GUID
, BASE_HEX
);
7379 * structures and data for
7381 * - per presentation context (bind)
7382 * - per authentication context
7384 dcerpc_connections
= wmem_map_new_autoreset(wmem_epan_scope(),
7386 dcerpc_connection_hash
,
7387 dcerpc_connection_equal
);
7389 dcerpc_binds
= wmem_map_new_autoreset(wmem_epan_scope(),
7394 dcerpc_auths
= wmem_map_new_autoreset(wmem_epan_scope(),
7396 dcerpc_auth_context_hash
,
7397 dcerpc_auth_context_equal
);
7399 /* structures and data for CALL */
7400 dcerpc_cn_calls
= wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), dcerpc_cn_call_hash
, dcerpc_cn_call_equal
);
7401 dcerpc_dg_calls
= wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), dcerpc_dg_call_hash
, dcerpc_dg_call_equal
);
7403 /* structure and data for MATCHED */
7404 dcerpc_matched
= wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), dcerpc_matched_hash
, dcerpc_matched_equal
);
7406 register_init_routine(decode_dcerpc_inject_bindings
);
7408 dcerpc_module
= prefs_register_protocol(proto_dcerpc
, NULL
);
7409 prefs_register_bool_preference(dcerpc_module
,
7411 "Reassemble DCE/RPC messages spanning multiple TCP segments",
7412 "Whether the DCE/RPC dissector should reassemble messages"
7413 " spanning multiple TCP segments."
7414 " To use this option, you must also enable"
7415 " \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
7416 &dcerpc_cn_desegment
);
7417 prefs_register_bool_preference(dcerpc_module
,
7418 "reassemble_dcerpc",
7419 "Reassemble DCE/RPC fragments",
7420 "Whether the DCE/RPC dissector should reassemble fragmented DCE/RPC PDUs",
7421 &dcerpc_reassemble
);
7424 * XXX - addresses_ports_reassembly_table_functions?
7425 * Or can a single connection-oriented DCE RPC session persist
7426 * over multiple transport layer connections?
7428 reassembly_table_register(&dcerpc_co_reassembly_table
,
7429 &addresses_reassembly_table_functions
);
7430 reassembly_table_register(&dcerpc_cl_reassembly_table
,
7431 &dcerpc_cl_reassembly_table_functions
);
7433 dcerpc_uuids
= g_hash_table_new_full(dcerpc_uuid_hash
, dcerpc_uuid_equal
, g_free
, g_free
);
7434 dcerpc_tap
= register_tap("dcerpc");
7436 register_decode_as(&dcerpc_da
);
7438 register_srt_table(proto_dcerpc
, NULL
, 1, dcerpcstat_packet
, dcerpcstat_init
, dcerpcstat_param
);
7440 tvb_trailer_signature
= tvb_new_real_data(TRAILER_SIGNATURE
,
7441 sizeof(TRAILER_SIGNATURE
),
7442 sizeof(TRAILER_SIGNATURE
));
7444 dcerpc_tcp_handle
= register_dissector("dcerpc.tcp", dissect_dcerpc_tcp
, proto_dcerpc
);
7446 register_shutdown_routine(dcerpc_shutdown
);
7450 proto_reg_handoff_dcerpc(void)
7452 heur_dissector_add("tcp", dissect_dcerpc_tcp_heur
, "DCE/RPC over TCP", "dcerpc_tcp", proto_dcerpc
, HEURISTIC_ENABLE
);
7453 heur_dissector_add("netbios", dissect_dcerpc_cn_pk
, "DCE/RPC over NetBios", "dcerpc_netbios", proto_dcerpc
, HEURISTIC_ENABLE
);
7454 heur_dissector_add("udp", dissect_dcerpc_dg
, "DCE/RPC over UDP", "dcerpc_udp", proto_dcerpc
, HEURISTIC_ENABLE
);
7455 heur_dissector_add("smb_transact", dissect_dcerpc_cn_smbpipe
, "DCE/RPC over SMB", "dcerpc_smb_transact", proto_dcerpc
, HEURISTIC_ENABLE
);
7456 heur_dissector_add("smb2_pipe_subdissectors", dissect_dcerpc_cn_smb2
, "DCE/RPC over SMB2", "dcerpc_smb2", proto_dcerpc
, HEURISTIC_ENABLE
);
7457 heur_dissector_add("http", dissect_dcerpc_cn_bs
, "DCE/RPC over HTTP", "dcerpc_http", proto_dcerpc
, HEURISTIC_ENABLE
);
7458 dcerpc_smb_init(proto_dcerpc
);
7460 dissector_add_for_decode_as("tcp.port", dcerpc_tcp_handle
);
7462 guids_add_uuid(&uuid_data_repr_proto
, "32bit NDR");
7463 guids_add_uuid(&uuid_ndr64
, "64bit NDR");
7464 guids_add_uuid(&uuid_asyncemsmdb
, "async MAPI");
7468 * Editor modelines - https://www.wireshark.org/tools/modelines.html
7473 * indent-tabs-mode: nil
7476 * vi: set shiftwidth=4 tabstop=8 expandtab:
7477 * :indentSize=4:tabSize=8:noTabs=true: