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_with_data(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
;
4026 auth_info
->session_key
= NULL
;
4029 * The authentication information is at the *end* of the PDU; in
4030 * request and response PDUs, the request and response stub data
4033 * Is there any authentication data (i.e., is the authentication length
4034 * non-zero), and is the authentication length valid (i.e., is it, plus
4035 * 8 bytes for the type/level/pad length/reserved/context id, less than
4036 * or equal to the fragment length minus the starting offset of the
4041 && ((hdr
->auth_len
+ 8) <= (hdr
->frag_len
- stub_offset
))) {
4044 * Yes, there is authentication data, and the length is valid.
4045 * Do we have all the bytes of stub data?
4046 * (If not, we'd throw an exception dissecting *that*, so don't
4047 * bother trying to dissect the authentication information and
4048 * throwing another exception there.)
4050 offset
= hdr
->frag_len
- (hdr
->auth_len
+ 8);
4051 if (offset
== 0 || tvb_offset_exists(tvb
, offset
- 1)) {
4052 dcerpc_connection
*connection
= NULL
;
4053 dcerpc_auth_context
*auth_context
= NULL
;
4054 int auth_offset
= offset
;
4056 /* Compute the size of the auth block. Note that this should not
4057 include auth padding, since when NTLMSSP encryption is used, the
4058 padding is actually inside the encrypted stub */
4059 auth_info
->auth_size
= hdr
->auth_len
+ 8;
4061 auth_info
->auth_item
= proto_tree_add_item(dcerpc_tree
, hf_dcerpc_auth_info
,
4062 tvb
, offset
, auth_info
->auth_size
, ENC_NA
);
4063 auth_info
->auth_tree
= proto_item_add_subtree(auth_info
->auth_item
, ett_dcerpc_auth_info
);
4066 * Either there's no stub data, or the last byte of the stub
4067 * data is present in the captured data, so we shouldn't
4068 * get a BoundsError dissecting the stub data.
4070 * Try dissecting the authentication data.
4071 * Catch all exceptions, so that even if the auth info is bad
4072 * or we don't have all of it, we still show the stuff we
4073 * dissect after this, such as stub data.
4076 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, auth_info
->auth_tree
, hdr
->drep
,
4077 hf_dcerpc_auth_type
,
4078 &auth_info
->auth_type
);
4079 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, auth_info
->auth_tree
, hdr
->drep
,
4080 hf_dcerpc_auth_level
,
4081 &auth_info
->auth_level
);
4083 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, auth_info
->auth_tree
, hdr
->drep
,
4084 hf_dcerpc_auth_pad_len
,
4085 &auth_info
->auth_pad_len
);
4086 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, auth_info
->auth_tree
, hdr
->drep
,
4087 hf_dcerpc_auth_rsrvd
, NULL
);
4088 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, auth_info
->auth_tree
, hdr
->drep
,
4089 hf_dcerpc_auth_ctx_id
,
4090 &auth_info
->auth_context_id
);
4092 proto_item_append_text(auth_info
->auth_item
,
4093 ": %s, %s, AuthContextId(%d)",
4094 val_to_str(auth_info
->auth_type
,
4095 authn_protocol_vals
,
4097 val_to_str(auth_info
->auth_level
,
4100 auth_info
->auth_context_id
);
4103 * Dissect the authentication data.
4105 auth_info
->auth_hdr_tvb
= tvb_new_subset_length_caplen(tvb
, auth_offset
, 8, 8);
4106 auth_info
->auth_tvb
= tvb_new_subset_length_caplen(tvb
, offset
,
4107 MIN(hdr
->auth_len
,tvb_reported_length_remaining(tvb
, offset
)),
4110 connection
= find_or_create_dcerpc_connection(pinfo
);
4111 auth_context
= find_or_create_dcerpc_auth_context(pinfo
, auth_info
);
4112 if (auth_context
!= NULL
) {
4113 if (hdr
->ptype
== PDU_BIND
|| hdr
->ptype
== PDU_ALTER
) {
4114 if (auth_context
->first_frame
== pinfo
->fd
->num
) {
4115 auth_context
->hdr_signing
= (hdr
->flags
& PFC_HDR_SIGNING
);
4116 if (auth_context
->hdr_signing
&& connection
!= NULL
) {
4117 connection
->hdr_signing_negotiated
= true;
4121 if (connection
!= NULL
&& connection
->hdr_signing_negotiated
) {
4122 auth_context
->hdr_signing
= true;
4125 auth_info
->hdr_signing
= auth_context
->hdr_signing
;
4128 auth_info
->auth_fns
= get_auth_subdissector_fns(auth_info
->auth_level
,
4129 auth_info
->auth_type
);
4130 if (auth_info
->auth_fns
!= NULL
)
4131 dissect_auth_verf(pinfo
, hdr
, auth_info
);
4133 proto_tree_add_item(auth_info
->auth_tree
,
4134 hf_dcerpc_auth_credentials
,
4135 auth_info
->auth_tvb
, 0,
4136 hdr
->auth_len
, ENC_NA
);
4138 } CATCH_BOUNDS_ERRORS
{
4139 show_exception(tvb
, pinfo
, dcerpc_tree
, EXCEPT_CODE
, GET_MESSAGE
);
4146 /* We need to hash in the SMB fid number to generate a unique hash table
4147 * key as DCERPC over SMB allows several pipes over the same TCP/IP
4149 * We pass this function the transport type here to make sure we only look
4150 * at this function if it came across an SMB pipe.
4151 * Other transports might need to mix in their own extra multiplexing data
4152 * as well in the future.
4156 dcerpc_get_transport_salt(packet_info
*pinfo
)
4158 dcerpc_decode_as_data
* decode_data
= dcerpc_get_decode_data(pinfo
);
4160 switch (decode_data
->dcetransporttype
) {
4161 case DCE_CN_TRANSPORT_SMBPIPE
:
4162 /* DCERPC over smb */
4163 return decode_data
->dcetransportsalt
;
4166 /* Some other transport... */
4171 dcerpc_set_transport_salt(uint64_t dcetransportsalt
, packet_info
*pinfo
)
4173 dcerpc_decode_as_data
* decode_data
= dcerpc_get_decode_data(pinfo
);
4175 decode_data
->dcetransportsalt
= dcetransportsalt
;
4179 * Connection oriented packet types
4183 dissect_dcerpc_cn_bind(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
4184 proto_tree
*dcerpc_tree
, e_dce_cn_common_hdr_t
*hdr
)
4186 conversation_t
*conv
= find_or_create_conversation(pinfo
);
4187 uint8_t num_ctx_items
= 0;
4190 uint8_t num_trans_items
;
4195 uint16_t if_ver
, if_ver_minor
;
4196 dcerpc_auth_info auth_info
;
4198 const char *uuid_name
= NULL
;
4199 proto_item
*iface_item
= NULL
;
4200 dcerpc_decode_as_data
* decode_data
= dcerpc_get_decode_data(pinfo
);
4202 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4203 hf_dcerpc_cn_max_xmit
, NULL
);
4205 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4206 hf_dcerpc_cn_max_recv
, NULL
);
4208 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4209 hf_dcerpc_cn_assoc_group
, NULL
);
4211 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4212 hf_dcerpc_cn_num_ctx_items
, &num_ctx_items
);
4217 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", %u context items:", num_ctx_items
);
4219 for (i
= 0; i
< num_ctx_items
; i
++) {
4220 proto_item
*ctx_item
= NULL
;
4221 proto_tree
*ctx_tree
= NULL
, *iface_tree
= NULL
;
4222 int ctx_offset
= offset
;
4224 dissect_dcerpc_uint16(tvb
, offset
, pinfo
, NULL
, hdr
->drep
,
4225 hf_dcerpc_cn_ctx_id
, &ctx_id
);
4227 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
4228 /* (if we have multiple contexts, this might cause "decode as"
4229 * to behave unpredictably) */
4230 decode_data
->dcectxid
= ctx_id
;
4233 ctx_item
= proto_tree_add_item(dcerpc_tree
, hf_dcerpc_cn_ctx_item
,
4236 ctx_tree
= proto_item_add_subtree(ctx_item
, ett_dcerpc_cn_ctx
);
4239 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, ctx_tree
, hdr
->drep
,
4240 hf_dcerpc_cn_ctx_id
, &ctx_id
);
4241 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, ctx_tree
, hdr
->drep
,
4242 hf_dcerpc_cn_num_trans_items
, &num_trans_items
);
4245 proto_item_append_text(ctx_item
, "[%u]: Context ID:%u", i
+1, ctx_id
);
4251 dcerpc_tvb_get_uuid(tvb
, offset
, hdr
->drep
, &if_id
);
4254 iface_item
= proto_tree_add_item(ctx_tree
, hf_dcerpc_cn_bind_abstract_syntax
, tvb
, offset
, 0, ENC_NA
);
4255 iface_tree
= proto_item_add_subtree(iface_item
, ett_dcerpc_cn_iface
);
4257 uuid_str
= guid_to_str(pinfo
->pool
, (e_guid_t
*)&if_id
);
4258 uuid_name
= guids_get_uuid_name(&if_id
, pinfo
->pool
);
4260 proto_tree_add_guid_format(iface_tree
, hf_dcerpc_cn_bind_if_id
, tvb
,
4261 offset
, 16, (e_guid_t
*) &if_id
, "Interface: %s UUID: %s", uuid_name
, uuid_str
);
4262 proto_item_append_text(iface_item
, ": %s", uuid_name
);
4263 proto_item_append_text(ctx_item
, ", %s", uuid_name
);
4265 proto_tree_add_guid_format(iface_tree
, hf_dcerpc_cn_bind_if_id
, tvb
,
4266 offset
, 16, (e_guid_t
*) &if_id
, "Interface UUID: %s", uuid_str
);
4267 proto_item_append_text(iface_item
, ": %s", uuid_str
);
4268 proto_item_append_text(ctx_item
, ", %s", uuid_str
);
4273 if (hdr
->drep
[0] & DREP_LITTLE_ENDIAN
) {
4274 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, iface_tree
, hdr
->drep
,
4275 hf_dcerpc_cn_bind_if_ver
, &if_ver
);
4276 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, iface_tree
, hdr
->drep
,
4277 hf_dcerpc_cn_bind_if_ver_minor
, &if_ver_minor
);
4279 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, iface_tree
, hdr
->drep
,
4280 hf_dcerpc_cn_bind_if_ver_minor
, &if_ver_minor
);
4281 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, iface_tree
, hdr
->drep
,
4282 hf_dcerpc_cn_bind_if_ver
, &if_ver
);
4286 proto_item_append_text(iface_item
, " V%u.%u", if_ver
, if_ver_minor
);
4287 proto_item_set_len(iface_item
, 20);
4290 memset(&trans_id
, 0, sizeof(trans_id
));
4291 for (j
= 0; j
< num_trans_items
; j
++) {
4292 proto_tree
*trans_tree
= NULL
;
4293 proto_item
*trans_item
= NULL
;
4295 dcerpc_tvb_get_uuid(tvb
, offset
, hdr
->drep
, &trans_id
);
4298 trans_item
= proto_tree_add_item(ctx_tree
, hf_dcerpc_cn_bind_trans_syntax
, tvb
, offset
, 0, ENC_NA
);
4299 trans_tree
= proto_item_add_subtree(trans_item
, ett_dcerpc_cn_trans_syntax
);
4301 uuid_str
= guid_to_str(pinfo
->pool
, (e_guid_t
*) &trans_id
);
4302 uuid_name
= guids_get_uuid_name(&trans_id
, pinfo
->pool
);
4304 /* check for [MS-RPCE] 3.3.1.5.3 Bind Time Feature Negotiation */
4305 if (trans_id
.data1
== 0x6cb71c2c && trans_id
.data2
== 0x9812 && trans_id
.data3
== 0x4540) {
4306 proto_tree_add_guid_format(trans_tree
, hf_dcerpc_cn_bind_trans_id
,
4307 tvb
, offset
, 16, (e_guid_t
*) &trans_id
,
4308 "Transfer Syntax: Bind Time Feature Negotiation UUID:%s",
4310 proto_tree_add_bitmask(trans_tree
, tvb
, offset
+ 8,
4311 hf_dcerpc_cn_bind_trans_btfn
,
4312 ett_dcerpc_cn_bind_trans_btfn
,
4313 dcerpc_cn_bind_trans_btfn_fields
,
4315 proto_item_append_text(trans_item
, "[%u]: Bind Time Feature Negotiation", j
+1);
4316 proto_item_append_text(ctx_item
, ", Bind Time Feature Negotiation");
4317 } else if (uuid_name
) {
4318 proto_tree_add_guid_format(trans_tree
, hf_dcerpc_cn_bind_trans_id
,
4319 tvb
, offset
, 16, (e_guid_t
*) &trans_id
,
4320 "Transfer Syntax: %s UUID:%s", uuid_name
, uuid_str
);
4321 proto_item_append_text(trans_item
, "[%u]: %s", j
+1, uuid_name
);
4322 proto_item_append_text(ctx_item
, ", %s", uuid_name
);
4324 proto_tree_add_guid_format(trans_tree
, hf_dcerpc_cn_bind_trans_id
,
4325 tvb
, offset
, 16, (e_guid_t
*) &trans_id
,
4326 "Transfer Syntax: %s", uuid_str
);
4327 proto_item_append_text(trans_item
, "[%u]: %s", j
+1, uuid_str
);
4328 proto_item_append_text(ctx_item
, ", %s", uuid_str
);
4334 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, trans_tree
, hdr
->drep
,
4335 hf_dcerpc_cn_bind_trans_ver
, &trans_ver
);
4337 proto_item_set_len(trans_item
, 20);
4338 proto_item_append_text(trans_item
, " V%u", trans_ver
);
4342 /* if this is the first time we've seen this packet, we need to
4343 update the dcerpc_binds table so that any later calls can
4344 match to the interface.
4345 XXX We assume that BINDs will NEVER be fragmented.
4347 if (!(pinfo
->fd
->visited
)) {
4348 dcerpc_bind_key
*key
;
4349 dcerpc_bind_value
*value
;
4351 key
= wmem_new(wmem_file_scope(), dcerpc_bind_key
);
4353 key
->ctx_id
= ctx_id
;
4354 key
->transport_salt
= dcerpc_get_transport_salt(pinfo
);
4356 value
= wmem_new(wmem_file_scope(), dcerpc_bind_value
);
4357 value
->uuid
= if_id
;
4358 value
->ver
= if_ver
;
4359 value
->transport
= trans_id
;
4361 /* add this entry to the bind table */
4362 wmem_map_insert(dcerpc_binds
, key
, value
);
4366 col_append_str(pinfo
->cinfo
, COL_INFO
, ",");
4368 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " %s V%u.%u (%s)",
4369 guids_resolve_guid_to_str(&if_id
, pinfo
->pool
), if_ver
, if_ver_minor
,
4370 guids_resolve_guid_to_str(&trans_id
, pinfo
->pool
));
4373 proto_item_set_len(ctx_item
, offset
- ctx_offset
);
4378 * XXX - we should save the authentication type *if* we have
4379 * an authentication header, and associate it with an authentication
4380 * context, so subsequent PDUs can use that context.
4382 dissect_dcerpc_cn_auth(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
, &auth_info
);
4386 dissect_dcerpc_cn_bind_ack(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
4387 proto_tree
*dcerpc_tree
, e_dce_cn_common_hdr_t
*hdr
)
4389 uint16_t max_xmit
, max_recv
;
4390 uint16_t sec_addr_len
;
4391 uint8_t num_results
;
4393 uint16_t result
= 0;
4394 uint16_t reason
= 0;
4397 dcerpc_auth_info auth_info
;
4398 const char *uuid_name
= NULL
;
4399 const char *result_str
= NULL
;
4401 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4402 hf_dcerpc_cn_max_xmit
, &max_xmit
);
4404 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4405 hf_dcerpc_cn_max_recv
, &max_recv
);
4407 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4408 hf_dcerpc_cn_assoc_group
, NULL
);
4410 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4411 hf_dcerpc_cn_sec_addr_len
, &sec_addr_len
);
4412 if (sec_addr_len
!= 0) {
4413 proto_tree_add_item(dcerpc_tree
, hf_dcerpc_cn_sec_addr
, tvb
, offset
,
4414 sec_addr_len
, ENC_ASCII
);
4415 offset
+= sec_addr_len
;
4419 offset
+= 4 - offset
% 4;
4422 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4423 hf_dcerpc_cn_num_results
, &num_results
);
4428 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", max_xmit: %u max_recv: %u, %u results:",
4429 max_xmit
, max_recv
, num_results
);
4431 for (i
= 0; i
< num_results
; i
++) {
4432 proto_tree
*ctx_tree
= NULL
;
4433 proto_item
*ctx_item
= NULL
;
4436 ctx_tree
= proto_tree_add_subtree_format(dcerpc_tree
, tvb
, offset
, 24, ett_dcerpc_cn_ctx
, &ctx_item
, "Ctx Item[%u]:", i
+1);
4439 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, ctx_tree
,
4440 hdr
->drep
, hf_dcerpc_cn_ack_result
,
4443 /* [MS-RPCE] 3.3.1.5.3 check if this Ctx Item is the response to a Bind Time Feature Negotiation request */
4445 proto_tree_add_bitmask(ctx_tree
, tvb
, offset
,
4446 hf_dcerpc_cn_bind_trans_btfn
,
4447 ett_dcerpc_cn_bind_trans_btfn
,
4448 dcerpc_cn_bind_trans_btfn_fields
,
4451 } else if (result
!= 0) {
4452 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, ctx_tree
,
4453 hdr
->drep
, hf_dcerpc_cn_ack_reason
,
4457 * The reason for rejection isn't meaningful, and often isn't
4458 * set, when the syntax was accepted.
4463 result_str
= val_to_str(result
, p_cont_result_vals
, "Unknown result (%u)");
4466 dcerpc_tvb_get_uuid(tvb
, offset
, hdr
->drep
, &trans_id
);
4467 uuid_name
= guids_get_uuid_name(&trans_id
, pinfo
->pool
);
4469 uuid_name
= guid_to_str(pinfo
->pool
, (e_guid_t
*) &trans_id
);
4471 proto_tree_add_guid_format(ctx_tree
, hf_dcerpc_cn_ack_trans_id
, tvb
,
4472 offset
, 16, (e_guid_t
*) &trans_id
, "Transfer Syntax: %s",
4474 proto_item_append_text(ctx_item
, " %s, %s", result_str
, uuid_name
);
4478 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, ctx_tree
, hdr
->drep
,
4479 hf_dcerpc_cn_ack_trans_ver
, &trans_ver
);
4482 col_append_str(pinfo
->cinfo
, COL_INFO
, ",");
4484 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " %s", result_str
);
4488 * XXX - do we need to do anything with the authentication level
4489 * we get back from this?
4491 dissect_dcerpc_cn_auth(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
, &auth_info
);
4495 dissect_dcerpc_cn_bind_nak(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
4496 proto_tree
*dcerpc_tree
, e_dce_cn_common_hdr_t
*hdr
)
4499 uint8_t num_protocols
;
4502 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
,
4503 hdr
->drep
, hf_dcerpc_cn_reject_reason
,
4506 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " reason: %s",
4507 val_to_str(reason
, reject_reason_vals
, "Unknown (%u)"));
4509 if (reason
== PROTOCOL_VERSION_NOT_SUPPORTED
) {
4510 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4511 hf_dcerpc_cn_num_protocols
,
4514 for (i
= 0; i
< num_protocols
; i
++) {
4515 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, dcerpc_tree
,
4516 hdr
->drep
, hf_dcerpc_cn_protocol_ver_major
,
4518 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, dcerpc_tree
,
4519 hdr
->drep
, hf_dcerpc_cn_protocol_ver_minor
,
4525 /* Return a string describing a DCE/RPC fragment as first, middle, or end
4528 #define PFC_FRAG_MASK 0x03
4531 fragment_type(uint8_t flags
)
4533 static const char* t
[4] = {
4539 return t
[flags
& PFC_FRAG_MASK
];
4542 /* Dissect stub data (payload) of a DCERPC packet. */
4545 dissect_dcerpc_cn_stub(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
4546 proto_tree
*dcerpc_tree
, proto_tree
*tree
,
4547 e_dce_cn_common_hdr_t
*hdr
, dcerpc_info
*di
,
4548 dcerpc_auth_info
*auth_info
, uint32_t alloc_hint _U_
,
4551 int length
, reported_length
;
4552 bool save_fragmented
;
4553 fragment_head
*fd_head
= NULL
;
4555 tvbuff_t
*header_tvb
= NULL
, *trailer_tvb
= NULL
;
4556 tvbuff_t
*payload_tvb
, *decrypted_tvb
= NULL
;
4558 proto_item
*parent_pi
;
4559 proto_item
*dcerpc_tree_item
;
4561 save_fragmented
= pinfo
->fragmented
;
4563 length
= tvb_reported_length_remaining(tvb
, offset
);
4564 reported_length
= tvb_reported_length_remaining(tvb
, offset
);
4565 if (reported_length
< 0 ||
4566 (uint32_t)reported_length
< auth_info
->auth_size
) {
4567 /* We don't even have enough bytes for the authentication
4571 reported_length
-= auth_info
->auth_size
;
4572 if (length
> reported_length
)
4573 length
= reported_length
;
4574 header_tvb
= tvb_new_subset_length_caplen(tvb
, 0, offset
, offset
);
4575 payload_tvb
= tvb_new_subset_length_caplen(tvb
, offset
, length
, reported_length
);
4576 trailer_tvb
= auth_info
->auth_hdr_tvb
;
4578 /* Decrypt the PDU if it is encrypted */
4580 if (auth_info
->auth_type
&&
4581 (auth_info
->auth_level
== DCE_C_AUTHN_LEVEL_PKT_PRIVACY
)) {
4583 /* Start out assuming we won't succeed in decrypting. */
4585 if (auth_info
->auth_fns
!= NULL
) {
4588 result
= decode_encrypted_data(header_tvb
, payload_tvb
, trailer_tvb
,
4589 pinfo
, hdr
, auth_info
);
4591 di
->auth_session_key
= auth_info
->session_key
;
4592 proto_tree_add_item(dcerpc_tree
, hf_dcerpc_encrypted_stub_data
, payload_tvb
, 0, -1, ENC_NA
);
4594 add_new_data_source(
4595 pinfo
, result
, "Decrypted stub data");
4598 decrypted_tvb
= result
;
4602 decrypted_tvb
= payload_tvb
;
4604 /* if this packet is not fragmented, just dissect it and exit */
4605 if (PFC_NOT_FRAGMENTED(hdr
)) {
4606 pinfo
->fragmented
= false;
4608 dcerpc_try_handoff(pinfo
, tree
, dcerpc_tree
,
4609 ((decrypted_tvb
!= NULL
) ? decrypted_tvb
: payload_tvb
),
4610 ((decrypted_tvb
!= NULL
) ? true : false),
4611 hdr
->drep
, di
, auth_info
);
4613 pinfo
->fragmented
= save_fragmented
;
4617 /* The packet is fragmented. */
4618 pinfo
->fragmented
= true;
4620 /* debug output of essential fragment data. */
4621 /* leave it here for future debugging sessions */
4622 /*printf("DCE num:%u offset:%u frag_len:%u tvb_len:%u\n",
4623 pinfo->num, offset, hdr->frag_len, tvb_reported_length(decrypted_tvb));*/
4625 /* if we are not doing reassembly and this is the first fragment
4626 then just dissect it and exit
4627 XXX - if we're not doing reassembly, can we decrypt an
4630 if ( (!dcerpc_reassemble
) && (hdr
->flags
& PFC_FIRST_FRAG
) ) {
4632 dcerpc_try_handoff(pinfo
, tree
, dcerpc_tree
,
4633 ((decrypted_tvb
!= NULL
) ? decrypted_tvb
: payload_tvb
),
4634 ((decrypted_tvb
!= NULL
) ? true : false),
4635 hdr
->drep
, di
, auth_info
);
4637 expert_add_info_format(pinfo
, NULL
, &ei_dcerpc_fragment
, "%s fragment", fragment_type(hdr
->flags
));
4639 pinfo
->fragmented
= save_fragmented
;
4643 /* if we have already seen this packet, see if it was reassembled
4644 and if so dissect the full pdu.
4647 if (pinfo
->fd
->visited
) {
4648 fd_head
= fragment_get_reassembled_id(&dcerpc_co_reassembly_table
, pinfo
, frame
);
4652 /* if we are not doing reassembly and it was neither a complete PDU
4653 nor the first fragment then there is nothing more we can do
4654 so we just have to exit
4656 if ( !dcerpc_reassemble
|| (tvb_captured_length(tvb
) != tvb_reported_length(tvb
)) )
4659 /* if we didn't get 'frame' we don't know where the PDU started and thus
4660 it is pointless to continue
4665 /* from now on we must attempt to reassemble the PDU
4668 /* if we get here we know it is the first time we see the packet
4669 and we also know it is only a fragment and not a full PDU,
4670 thus we must reassemble it.
4673 /* Do we have any non-encrypted data to reassemble? */
4674 if (decrypted_tvb
== NULL
) {
4675 /* No. We can't even try to reassemble. */
4679 /* defragmentation is a bit tricky, as there's no offset of the fragment
4680 * in the protocol data.
4682 * just use fragment_add_seq_next() and hope that TCP/SMB segments coming
4683 * in with the correct sequence.
4685 fd_head
= fragment_add_seq_next(&dcerpc_co_reassembly_table
,
4686 decrypted_tvb
, 0, pinfo
, frame
, NULL
,
4687 tvb_reported_length(decrypted_tvb
),
4688 !(hdr
->flags
& PFC_LAST_FRAG
) /* more_frags */);
4692 /* if reassembly is complete and this is the last fragment
4693 * (multiple fragments in one PDU are possible!)
4694 * dissect the full PDU
4696 if (fd_head
&& (fd_head
->flags
& FD_DEFRAGMENTED
) ) {
4698 if ((pinfo
->num
== fd_head
->reassembled_in
) && (hdr
->flags
& PFC_LAST_FRAG
) ) {
4700 proto_item
*frag_tree_item
;
4702 next_tvb
= tvb_new_chain((decrypted_tvb
)?decrypted_tvb
:payload_tvb
,
4705 add_new_data_source(pinfo
, next_tvb
, "Reassembled DCE/RPC");
4706 show_fragment_tree(fd_head
, &dcerpc_frag_items
,
4707 tree
, pinfo
, next_tvb
, &frag_tree_item
);
4708 /* the toplevel fragment subtree is now behind all desegmented data,
4709 * move it right behind the DCE/RPC tree */
4710 dcerpc_tree_item
= proto_tree_get_parent(dcerpc_tree
);
4711 if (frag_tree_item
&& dcerpc_tree_item
) {
4712 proto_tree_move_item(tree
, dcerpc_tree_item
, frag_tree_item
);
4715 pinfo
->fragmented
= false;
4717 expert_add_info_format(pinfo
, frag_tree_item
, &ei_dcerpc_fragment_reassembled
, "%s fragment, reassembled", fragment_type(hdr
->flags
));
4719 dcerpc_try_handoff(pinfo
, tree
, dcerpc_tree
, next_tvb
, true, hdr
->drep
, di
, auth_info
);
4722 if (decrypted_tvb
) {
4723 pi
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_reassembled_in
,
4724 decrypted_tvb
, 0, 0, fd_head
->reassembled_in
);
4726 pi
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_reassembled_in
,
4727 payload_tvb
, 0, 0, fd_head
->reassembled_in
);
4729 proto_item_set_generated(pi
);
4730 parent_pi
= proto_tree_get_parent(dcerpc_tree
);
4731 if (parent_pi
!= NULL
) {
4732 proto_item_append_text(parent_pi
, ", [Reas: #%u]", fd_head
->reassembled_in
);
4734 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
4735 " [DCE/RPC %s fragment, reas: #%u]", fragment_type(hdr
->flags
), fd_head
->reassembled_in
);
4736 expert_add_info_format(pinfo
, NULL
, &ei_dcerpc_fragment_reassembled
, "%s fragment, reassembled in #%u", fragment_type(hdr
->flags
), fd_head
->reassembled_in
);
4739 /* Reassembly not complete - some fragments
4740 are missing. Just show the stub data. */
4741 expert_add_info_format(pinfo
, NULL
, &ei_dcerpc_fragment
, "%s fragment", fragment_type(hdr
->flags
));
4743 if (decrypted_tvb
) {
4744 show_stub_data(pinfo
, decrypted_tvb
, 0, tree
, auth_info
, false);
4746 show_stub_data(pinfo
, payload_tvb
, 0, tree
, auth_info
, true);
4750 pinfo
->fragmented
= save_fragmented
;
4754 dissect_dcerpc_cn_rqst(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
4755 proto_tree
*dcerpc_tree
, proto_tree
*tree
,
4756 e_dce_cn_common_hdr_t
*hdr
)
4758 conversation_t
*conv
;
4761 e_guid_t obj_id
= DCERPC_UUID_NULL
;
4762 dcerpc_auth_info auth_info
;
4763 uint32_t alloc_hint
;
4765 proto_item
*parent_pi
;
4766 dcerpc_decode_as_data
* decode_data
= dcerpc_get_decode_data(pinfo
);
4768 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4769 hf_dcerpc_cn_alloc_hint
, &alloc_hint
);
4771 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4772 hf_dcerpc_cn_ctx_id
, &ctx_id
);
4773 parent_pi
= proto_tree_get_parent(dcerpc_tree
);
4774 if (parent_pi
!= NULL
) {
4775 proto_item_append_text(parent_pi
, ", Ctx: %u", ctx_id
);
4778 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4779 hf_dcerpc_opnum
, &opnum
);
4781 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
4782 decode_data
->dcectxid
= ctx_id
;
4784 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", opnum: %u, Ctx: %u",
4787 if (hdr
->flags
& PFC_OBJECT_UUID
) {
4788 dcerpc_tvb_get_uuid(tvb
, offset
, hdr
->drep
, &obj_id
);
4790 proto_tree_add_guid_format(dcerpc_tree
, hf_dcerpc_obj_id
, tvb
,
4791 offset
, 16, (e_guid_t
*) &obj_id
, "Object UUID: %s",
4792 guid_to_str(pinfo
->pool
, (e_guid_t
*) &obj_id
));
4798 * XXX - what if this was set when the connection was set up,
4799 * and we just have a security context?
4801 dissect_dcerpc_cn_auth(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
, &auth_info
);
4803 conv
= find_conversation_pinfo(pinfo
, 0);
4805 show_stub_data(pinfo
, tvb
, offset
, dcerpc_tree
, &auth_info
, true);
4807 dcerpc_matched_key matched_key
, *new_matched_key
;
4808 dcerpc_call_value
*value
;
4810 /* !!! we can NOT check visited here since this will interact
4811 badly with when SMB handles (i.e. calls the subdissector)
4812 and desegmented pdu's .
4813 Instead we check if this pdu is already in the matched table or not
4815 matched_key
.frame
= pinfo
->num
;
4816 matched_key
.call_id
= hdr
->call_id
;
4817 value
= (dcerpc_call_value
*)wmem_map_lookup(dcerpc_matched
, &matched_key
);
4819 dcerpc_bind_key bind_key
;
4820 dcerpc_bind_value
*bind_value
;
4822 bind_key
.conv
= conv
;
4823 bind_key
.ctx_id
= ctx_id
;
4824 bind_key
.transport_salt
= dcerpc_get_transport_salt(pinfo
);
4826 if ((bind_value
= (dcerpc_bind_value
*)wmem_map_lookup(dcerpc_binds
, &bind_key
)) ) {
4827 if (!(hdr
->flags
&PFC_FIRST_FRAG
)) {
4828 dcerpc_cn_call_key call_key
;
4829 dcerpc_call_value
*call_value
;
4831 call_key
.conv
= conv
;
4832 call_key
.call_id
= hdr
->call_id
;
4833 call_key
.transport_salt
= dcerpc_get_transport_salt(pinfo
);
4834 if ((call_value
= (dcerpc_call_value
*)wmem_map_lookup(dcerpc_cn_calls
, &call_key
))) {
4835 new_matched_key
= wmem_new(wmem_file_scope(), dcerpc_matched_key
);
4836 *new_matched_key
= matched_key
;
4837 wmem_map_insert(dcerpc_matched
, new_matched_key
, call_value
);
4841 dcerpc_cn_call_key
*call_key
;
4842 dcerpc_call_value
*call_value
;
4844 /* We found the binding and it is the first fragment
4845 (or a complete PDU) of a dcerpc pdu so just add
4846 the call to both the call table and the
4849 call_key
= wmem_new(wmem_file_scope(), dcerpc_cn_call_key
);
4850 call_key
->conv
= conv
;
4851 call_key
->call_id
= hdr
->call_id
;
4852 call_key
->transport_salt
= dcerpc_get_transport_salt(pinfo
);
4854 /* if there is already a matching call in the table
4855 remove it so it is replaced with the new one */
4856 if (wmem_map_lookup(dcerpc_cn_calls
, call_key
)) {
4857 wmem_map_remove(dcerpc_cn_calls
, call_key
);
4860 call_value
= wmem_new(wmem_file_scope(), dcerpc_call_value
);
4861 call_value
->uuid
= bind_value
->uuid
;
4862 call_value
->ver
= bind_value
->ver
;
4863 call_value
->object_uuid
= obj_id
;
4864 call_value
->opnum
= opnum
;
4865 call_value
->req_frame
= pinfo
->num
;
4866 call_value
->req_time
= pinfo
->abs_ts
;
4867 call_value
->rep_frame
= 0;
4868 call_value
->max_ptr
= 0;
4869 call_value
->se_data
= NULL
;
4870 call_value
->private_data
= NULL
;
4871 call_value
->pol
= NULL
;
4872 call_value
->flags
= 0;
4873 if (!memcmp(&bind_value
->transport
, &uuid_ndr64
, sizeof(uuid_ndr64
))) {
4874 call_value
->flags
|= DCERPC_IS_NDR64
;
4877 wmem_map_insert(dcerpc_cn_calls
, call_key
, call_value
);
4879 new_matched_key
= wmem_new(wmem_file_scope(), dcerpc_matched_key
);
4880 *new_matched_key
= matched_key
;
4881 wmem_map_insert(dcerpc_matched
, new_matched_key
, call_value
);
4890 di
= wmem_new0(pinfo
->pool
, dcerpc_info
);
4891 /* handoff this call */
4892 di
->dcerpc_procedure_name
= "";
4894 di
->call_id
= hdr
->call_id
;
4895 di
->transport_salt
= dcerpc_get_transport_salt(pinfo
);
4896 di
->ptype
= PDU_REQ
;
4897 di
->call_data
= value
;
4900 if (value
->rep_frame
!= 0) {
4901 pi
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_response_in
,
4902 tvb
, 0, 0, value
->rep_frame
);
4903 proto_item_set_generated(pi
);
4904 if (parent_pi
!= NULL
) {
4905 proto_item_append_text(parent_pi
, ", [Resp: #%u]", value
->rep_frame
);
4909 dissect_dcerpc_cn_stub(tvb
, offset
, pinfo
, dcerpc_tree
, tree
,
4910 hdr
, di
, &auth_info
, alloc_hint
,
4913 /* no bind information, simply show stub data */
4914 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
);
4915 show_stub_data(pinfo
, tvb
, offset
, dcerpc_tree
, &auth_info
, true);
4920 * Move the auth_info subtree to the end,
4921 * as it's also at the end of the pdu on the wire.
4923 dissect_dcerpc_cn_auth_move(&auth_info
, dcerpc_tree
);
4927 dissect_dcerpc_cn_resp(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
4928 proto_tree
*dcerpc_tree
, proto_tree
*tree
,
4929 e_dce_cn_common_hdr_t
*hdr
)
4931 dcerpc_call_value
*value
= NULL
;
4932 conversation_t
*conv
;
4934 dcerpc_auth_info auth_info
;
4935 uint32_t alloc_hint
;
4937 proto_item
*parent_pi
;
4938 e_guid_t obj_id_null
= DCERPC_UUID_NULL
;
4939 dcerpc_decode_as_data
* decode_data
= dcerpc_get_decode_data(pinfo
);
4941 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4942 hf_dcerpc_cn_alloc_hint
, &alloc_hint
);
4944 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4945 hf_dcerpc_cn_ctx_id
, &ctx_id
);
4946 parent_pi
= proto_tree_get_parent(dcerpc_tree
);
4947 if (parent_pi
!= NULL
) {
4948 proto_item_append_text(parent_pi
, ", Ctx: %u", ctx_id
);
4951 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
4952 decode_data
->dcectxid
= ctx_id
;
4954 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", Ctx: %u", ctx_id
);
4956 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4957 hf_dcerpc_cn_cancel_count
, NULL
);
4962 * XXX - what if this was set when the connection was set up,
4963 * and we just have a security context?
4965 dissect_dcerpc_cn_auth(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
, &auth_info
);
4967 conv
= find_conversation_pinfo(pinfo
, 0);
4970 /* no point in creating one here, really */
4971 show_stub_data(pinfo
, tvb
, offset
, dcerpc_tree
, &auth_info
, true);
4973 dcerpc_matched_key matched_key
, *new_matched_key
;
4975 /* !!! we can NOT check visited here since this will interact
4976 badly with when SMB handles (i.e. calls the subdissector)
4977 and desegmented pdu's .
4978 Instead we check if this pdu is already in the matched table or not
4980 matched_key
.frame
= pinfo
->num
;
4981 matched_key
.call_id
= hdr
->call_id
;
4982 value
= (dcerpc_call_value
*)wmem_map_lookup(dcerpc_matched
, &matched_key
);
4984 dcerpc_cn_call_key call_key
;
4985 dcerpc_call_value
*call_value
;
4987 call_key
.conv
= conv
;
4988 call_key
.call_id
= hdr
->call_id
;
4989 call_key
.transport_salt
= dcerpc_get_transport_salt(pinfo
);
4991 if ((call_value
= (dcerpc_call_value
*)wmem_map_lookup(dcerpc_cn_calls
, &call_key
))) {
4992 /* extra sanity check, only match them if the reply
4993 came after the request */
4994 if (call_value
->req_frame
<pinfo
->num
) {
4995 new_matched_key
= wmem_new(wmem_file_scope(), dcerpc_matched_key
);
4996 *new_matched_key
= matched_key
;
4997 wmem_map_insert(dcerpc_matched
, new_matched_key
, call_value
);
4999 if (call_value
->rep_frame
== 0) {
5000 call_value
->rep_frame
= pinfo
->num
;
5009 di
= wmem_new0(pinfo
->pool
, dcerpc_info
);
5010 /* handoff this call */
5011 di
->dcerpc_procedure_name
= "";
5013 di
->call_id
= hdr
->call_id
;
5014 di
->transport_salt
= dcerpc_get_transport_salt(pinfo
);
5015 di
->ptype
= PDU_RESP
;
5016 di
->call_data
= value
;
5018 pi
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_opnum
, tvb
, 0, 0, value
->opnum
);
5019 proto_item_set_generated(pi
);
5021 /* (optional) "Object UUID" from request */
5022 if (dcerpc_tree
&& (memcmp(&value
->object_uuid
, &obj_id_null
, sizeof(obj_id_null
)) != 0)) {
5023 pi
= proto_tree_add_guid_format(dcerpc_tree
, hf_dcerpc_obj_id
, tvb
,
5024 offset
, 0, (e_guid_t
*) &value
->object_uuid
, "Object UUID: %s",
5025 guid_to_str(pinfo
->pool
, (e_guid_t
*) &value
->object_uuid
));
5026 proto_item_set_generated(pi
);
5030 if (value
->req_frame
!= 0) {
5032 pi
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_request_in
,
5033 tvb
, 0, 0, value
->req_frame
);
5034 proto_item_set_generated(pi
);
5035 if (parent_pi
!= NULL
) {
5036 proto_item_append_text(parent_pi
, ", [Req: #%u]", value
->req_frame
);
5038 nstime_delta(&delta_ts
, &pinfo
->abs_ts
, &value
->req_time
);
5039 pi
= proto_tree_add_time(dcerpc_tree
, hf_dcerpc_time
, tvb
, offset
, 0, &delta_ts
);
5040 proto_item_set_generated(pi
);
5042 proto_tree_add_expert(dcerpc_tree
, pinfo
, &ei_dcerpc_no_request_found
, tvb
, 0, 0);
5045 dissect_dcerpc_cn_stub(tvb
, offset
, pinfo
, dcerpc_tree
, tree
,
5046 hdr
, di
, &auth_info
, alloc_hint
,
5049 /* no bind information, simply show stub data */
5050 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
);
5051 show_stub_data(pinfo
, tvb
, offset
, dcerpc_tree
, &auth_info
, true);
5056 * Move the auth_info subtree to the end,
5057 * as it's also at the end of the pdu on the wire.
5059 dissect_dcerpc_cn_auth_move(&auth_info
, dcerpc_tree
);
5063 dissect_dcerpc_cn_fault(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
5064 proto_tree
*dcerpc_tree
, e_dce_cn_common_hdr_t
*hdr
)
5066 dcerpc_call_value
*value
= NULL
;
5067 conversation_t
*conv
;
5070 uint32_t alloc_hint
;
5071 dcerpc_auth_info auth_info
;
5072 int length
, reported_length
;
5073 tvbuff_t
*stub_tvb
= NULL
;
5074 proto_item
*pi
= NULL
;
5075 dcerpc_decode_as_data
* decode_data
= dcerpc_get_decode_data(pinfo
);
5077 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
5078 hf_dcerpc_cn_alloc_hint
, &alloc_hint
);
5080 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
5081 hf_dcerpc_cn_ctx_id
, &ctx_id
);
5083 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
5084 hf_dcerpc_cn_cancel_count
, NULL
);
5085 proto_tree_add_bitmask(dcerpc_tree
, tvb
, offset
,
5086 hf_dcerpc_cn_fault_flags
,
5087 ett_dcerpc_fault_flags
,
5088 dcerpc_cn_fault_flags_fields
,
5089 DREP_ENC_INTEGER(hdr
->drep
));
5093 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
5094 hf_dcerpc_cn_status
, &status
);
5096 status
= ((hdr
->drep
[0] & DREP_LITTLE_ENDIAN
)
5097 ? tvb_get_letohl(tvb
, offset
)
5098 : tvb_get_ntohl(tvb
, offset
));
5100 pi
= proto_tree_add_item(dcerpc_tree
, hf_dcerpc_cn_status
, tvb
, offset
, 4, DREP_ENC_INTEGER(hdr
->drep
));
5103 expert_add_info_format(pinfo
, pi
, &ei_dcerpc_cn_status
, "Fault: %s", val_to_str(status
, reject_status_vals
, "Unknown (0x%08x)"));
5105 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
5106 decode_data
->dcectxid
= ctx_id
;
5108 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
5109 ", Ctx: %u, status: %s", ctx_id
,
5110 val_to_str(status
, reject_status_vals
,
5111 "Unknown (0x%08x)"));
5114 proto_tree_add_item(dcerpc_tree
, hf_dcerpc_reserved
, tvb
, offset
, 4, ENC_NA
);
5118 * XXX - what if this was set when the connection was set up,
5119 * and we just have a security context?
5121 dissect_dcerpc_cn_auth(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
, &auth_info
);
5123 length
= tvb_captured_length_remaining(tvb
, offset
);
5124 reported_length
= tvb_reported_length_remaining(tvb
, offset
);
5125 if (reported_length
< 0 ||
5126 (uint32_t)reported_length
< auth_info
.auth_size
) {
5127 /* We don't even have enough bytes for the authentication
5131 reported_length
-= auth_info
.auth_size
;
5132 if (length
> reported_length
)
5133 length
= reported_length
;
5134 stub_tvb
= tvb_new_subset_length_caplen(tvb
, offset
, length
, reported_length
);
5136 conv
= find_conversation_pinfo(pinfo
, 0);
5138 /* no point in creating one here, really */
5140 dcerpc_matched_key matched_key
, *new_matched_key
;
5142 /* !!! we can NOT check visited here since this will interact
5143 badly with when SMB handles (i.e. calls the subdissector)
5144 and desegmented pdu's .
5145 Instead we check if this pdu is already in the matched table or not
5147 matched_key
.frame
= pinfo
->num
;
5148 matched_key
.call_id
= hdr
->call_id
;
5149 value
= (dcerpc_call_value
*)wmem_map_lookup(dcerpc_matched
, &matched_key
);
5151 dcerpc_cn_call_key call_key
;
5152 dcerpc_call_value
*call_value
;
5154 call_key
.conv
= conv
;
5155 call_key
.call_id
= hdr
->call_id
;
5156 call_key
.transport_salt
= dcerpc_get_transport_salt(pinfo
);
5158 if ((call_value
= (dcerpc_call_value
*)wmem_map_lookup(dcerpc_cn_calls
, &call_key
))) {
5159 new_matched_key
= wmem_new(wmem_file_scope(), dcerpc_matched_key
);
5160 *new_matched_key
= matched_key
;
5161 wmem_map_insert(dcerpc_matched
, new_matched_key
, call_value
);
5164 if (call_value
->rep_frame
== 0) {
5165 call_value
->rep_frame
= pinfo
->num
;
5172 proto_tree
*stub_tree
= NULL
;
5175 proto_item
*parent_pi
;
5177 di
= wmem_new0(pinfo
->pool
, dcerpc_info
);
5178 /* handoff this call */
5179 di
->dcerpc_procedure_name
= "";
5181 di
->call_id
= hdr
->call_id
;
5182 di
->transport_salt
= dcerpc_get_transport_salt(pinfo
);
5183 di
->ptype
= PDU_FAULT
;
5184 di
->call_data
= value
;
5186 pi
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_opnum
, tvb
, 0, 0, value
->opnum
);
5187 proto_item_set_generated(pi
);
5188 if (value
->req_frame
!= 0) {
5190 pi
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_request_in
,
5191 tvb
, 0, 0, value
->req_frame
);
5192 proto_item_set_generated(pi
);
5193 parent_pi
= proto_tree_get_parent(dcerpc_tree
);
5194 if (parent_pi
!= NULL
) {
5195 proto_item_append_text(parent_pi
, ", [Req: #%u]", value
->req_frame
);
5197 nstime_delta(&delta_ts
, &pinfo
->abs_ts
, &value
->req_time
);
5198 pi
= proto_tree_add_time(dcerpc_tree
, hf_dcerpc_time
, tvb
, offset
, 0, &delta_ts
);
5199 proto_item_set_generated(pi
);
5201 proto_tree_add_expert(dcerpc_tree
, pinfo
, &ei_dcerpc_no_request_found
, tvb
, 0, 0);
5204 length
= tvb_reported_length_remaining(stub_tvb
, 0);
5205 /* as we now create a tvb in dissect_dcerpc_cn() containing only the
5206 * stub_data, the following calculation is no longer valid:
5207 * stub_length = hdr->frag_len - offset - auth_info.auth_size;
5208 * simply use the remaining length of the tvb instead.
5209 * XXX - or better use the reported_length?!?
5211 stub_length
= length
;
5213 stub_tree
= proto_tree_add_subtree_format(dcerpc_tree
,
5214 stub_tvb
, 0, stub_length
,
5215 ett_dcerpc_fault_stub_data
, NULL
,
5216 "Fault stub data (%d byte%s)", stub_length
,
5217 plurality(stub_length
, "", "s"));
5219 /* If we don't have reassembly enabled, or this packet contains
5220 the entire PDU, or if we don't have all the data in this
5221 fragment, just call the handoff directly if this is the
5222 first fragment or the PDU isn't fragmented. */
5223 if ( (!dcerpc_reassemble
) || PFC_NOT_FRAGMENTED(hdr
) ||
5224 !tvb_bytes_exist(stub_tvb
, 0, stub_length
) ) {
5225 if (hdr
->flags
&PFC_FIRST_FRAG
) {
5226 /* First fragment, possibly the only fragment */
5228 * XXX - should there be a third routine for each
5229 * function in an RPC subdissector, to handle
5230 * fault responses? The DCE RPC 1.1 spec says
5231 * three's "stub data" here, which I infer means
5232 * that it's protocol-specific and call-specific.
5234 * It should probably get passed the status code
5235 * as well, as that might be protocol-specific.
5237 if (stub_length
> 0) {
5238 proto_tree_add_item(stub_tree
, hf_dcerpc_fault_stub_data
, stub_tvb
, 0, stub_length
, ENC_NA
);
5241 /* PDU is fragmented and this isn't the first fragment */
5242 if (stub_length
> 0) {
5243 proto_tree_add_item(stub_tree
, hf_dcerpc_fragment_data
, stub_tvb
, 0, stub_length
, ENC_NA
);
5247 /* Reassembly is enabled, the PDU is fragmented, and
5248 we have all the data in the fragment; the first two
5249 of those mean we should attempt reassembly, and the
5250 third means we can attempt reassembly. */
5253 proto_tree_add_item(stub_tree
, hf_dcerpc_fragment_data
, stub_tvb
, 0, stub_length
, ENC_NA
);
5256 if (hdr
->flags
&PFC_FIRST_FRAG
) { /* FIRST fragment */
5257 if ( (!pinfo
->fd
->visited
) && value
->rep_frame
) {
5258 fragment_add_seq_next(&dcerpc_co_reassembly_table
,
5260 pinfo
, value
->rep_frame
, NULL
,
5264 } else if (hdr
->flags
&PFC_LAST_FRAG
) { /* LAST fragment */
5265 if ( value
->rep_frame
) {
5266 fragment_head
*fd_head
;
5268 fd_head
= fragment_add_seq_next(&dcerpc_co_reassembly_table
,
5270 pinfo
, value
->rep_frame
, NULL
,
5275 /* We completed reassembly */
5277 proto_item
*frag_tree_item
;
5279 next_tvb
= tvb_new_chain(stub_tvb
, fd_head
->tvb_data
);
5280 add_new_data_source(pinfo
, next_tvb
, "Reassembled DCE/RPC");
5281 show_fragment_tree(fd_head
, &dcerpc_frag_items
,
5282 dcerpc_tree
, pinfo
, next_tvb
, &frag_tree_item
);
5285 * XXX - should there be a third routine for each
5286 * function in an RPC subdissector, to handle
5287 * fault responses? The DCE RPC 1.1 spec says
5288 * three's "stub data" here, which I infer means
5289 * that it's protocol-specific and call-specific.
5291 * It should probably get passed the status code
5292 * as well, as that might be protocol-specific.
5296 proto_tree_add_item(dcerpc_tree
, hf_dcerpc_stub_data
, stub_tvb
, 0, stub_length
, ENC_NA
);
5301 } else { /* MIDDLE fragment(s) */
5302 if ( (!pinfo
->fd
->visited
) && value
->rep_frame
) {
5303 fragment_add_seq_next(&dcerpc_co_reassembly_table
,
5305 pinfo
, value
->rep_frame
, NULL
,
5315 * Move the auth_info subtree to the end,
5316 * as it's also at the end of the pdu on the wire.
5318 dissect_dcerpc_cn_auth_move(&auth_info
, dcerpc_tree
);
5322 dissect_dcerpc_cn_rts(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
5323 proto_tree
*dcerpc_tree
, e_dce_cn_common_hdr_t
*hdr
)
5325 proto_item
*tf
= NULL
;
5326 proto_item
*parent_pi
= NULL
;
5327 proto_tree
*cn_rts_pdu_tree
= NULL
;
5329 uint16_t commands_nb
= 0;
5332 const char *info_str
= NULL
;
5333 static int * const flags
[] = {
5334 &hf_dcerpc_cn_rts_flags_ping
,
5335 &hf_dcerpc_cn_rts_flags_other_cmd
,
5336 &hf_dcerpc_cn_rts_flags_recycle_channel
,
5337 &hf_dcerpc_cn_rts_flags_in_channel
,
5338 &hf_dcerpc_cn_rts_flags_out_channel
,
5339 &hf_dcerpc_cn_rts_flags_eof
,
5343 /* Dissect specific RTS header */
5344 rts_flags
= dcerpc_tvb_get_ntohs(tvb
, offset
, hdr
->drep
);
5345 proto_tree_add_bitmask_value_with_flags(dcerpc_tree
, tvb
, offset
, hf_dcerpc_cn_rts_flags
,
5346 ett_dcerpc_cn_rts_flags
, flags
, rts_flags
, BMT_NO_APPEND
);
5349 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
5350 hf_dcerpc_cn_rts_commands_nb
, &commands_nb
);
5352 /* Create the RTS PDU tree - we do not yet know its name */
5353 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
);
5355 cmd
= (uint32_t *)wmem_alloc(pinfo
->pool
, sizeof (uint32_t) * (commands_nb
+ 1));
5357 /* Dissect commands */
5358 for (i
= 0; i
< commands_nb
; ++i
) {
5359 proto_tree
*cn_rts_command_tree
= NULL
;
5360 const uint32_t command
= dcerpc_tvb_get_ntohl(tvb
, offset
, hdr
->drep
);
5362 tf
= proto_tree_add_uint(cn_rts_pdu_tree
, hf_dcerpc_cn_rts_command
, tvb
, offset
, 4, command
);
5363 cn_rts_command_tree
= proto_item_add_subtree(tf
, ett_dcerpc_cn_rts_command
);
5366 case RTS_CMD_RECEIVEWINDOWSIZE
:
5367 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_receivewindowsize
, NULL
);
5369 case RTS_CMD_FLOWCONTROLACK
:
5370 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_fack_bytesreceived
, NULL
);
5371 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_fack_availablewindow
, NULL
);
5372 offset
= dissect_dcerpc_uuid_t(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_fack_channelcookie
, NULL
);
5374 case RTS_CMD_CONNECTIONTIMEOUT
:
5375 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_connectiontimeout
, NULL
);
5377 case RTS_CMD_COOKIE
:
5378 offset
= dissect_dcerpc_uuid_t(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_cookie
, NULL
);
5380 case RTS_CMD_CHANNELLIFETIME
:
5381 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_channellifetime
, NULL
);
5383 case RTS_CMD_CLIENTKEEPALIVE
:
5384 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_clientkeepalive
, NULL
);
5386 case RTS_CMD_VERSION
:
5387 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_version
, NULL
);
5391 case RTS_CMD_PADDING
: {
5393 const uint32_t conformance_count
= dcerpc_tvb_get_ntohl(tvb
, offset
, hdr
->drep
);
5394 proto_tree_add_uint(cn_rts_command_tree
, hf_dcerpc_cn_rts_command_conformancecount
, tvb
, offset
, 4, conformance_count
);
5396 padding
= (uint8_t *)tvb_memdup(pinfo
->pool
, tvb
, offset
, conformance_count
);
5397 proto_tree_add_bytes(cn_rts_command_tree
, hf_dcerpc_cn_rts_command_padding
, tvb
, offset
, conformance_count
, padding
);
5398 offset
+= conformance_count
;
5400 case RTS_CMD_NEGATIVEANCE
:
5404 case RTS_CMD_CLIENTADDRESS
: {
5406 const uint32_t addrtype
= dcerpc_tvb_get_ntohl(tvb
, offset
, hdr
->drep
);
5407 proto_tree_add_uint(cn_rts_command_tree
, hf_dcerpc_cn_rts_command_addrtype
, tvb
, offset
, 4, addrtype
);
5411 const uint32_t addr4
= tvb_get_ipv4(tvb
, offset
);
5412 proto_tree_add_ipv4_format_value(cn_rts_command_tree
, hf_dcerpc_cmd_client_ipv4
, tvb
, offset
, 4, addr4
, "%s", get_hostname(addr4
));
5417 tvb_get_ipv6(tvb
, offset
, &addr6
);
5418 proto_tree_add_ipv6_format_value(cn_rts_command_tree
, hf_dcerpc_cmd_client_ipv6
, tvb
, offset
, 16, &addr6
, "%s", get_hostname6(&addr6
));
5422 padding
= (uint8_t *)tvb_memdup(pinfo
->pool
, tvb
, offset
, 12);
5423 proto_tree_add_bytes(cn_rts_command_tree
, hf_dcerpc_cn_rts_command_padding
, tvb
, offset
, 12, padding
);
5426 case RTS_CMD_ASSOCIATIONGROUPID
:
5427 offset
= dissect_dcerpc_uuid_t(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_associationgroupid
, NULL
);
5429 case RTS_CMD_DESTINATION
:
5430 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_forwarddestination
, NULL
);
5432 case RTS_CMD_PINGTRAFFICSENTNOTIFY
:
5433 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_pingtrafficsentnotify
, NULL
);
5436 expert_add_info(pinfo
, tf
, &ei_dcerpc_cn_rts_command
);
5441 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "RPCH");
5443 /* Define which PDU Body we are dealing with */
5444 info_str
= "unknown RTS PDU";
5446 switch (rts_flags
) {
5448 switch (commands_nb
) {
5450 if (cmd
[0] == 0x2) {
5451 info_str
= "CONN/A3";
5452 } else if (cmd
[0] == 0x3) {
5453 info_str
= "IN_R1/A5,IN_R1/A6,IN_R2/A2,IN_R2/A5,OUT_R2/A4";
5454 } else if (cmd
[0] == 0x7) {
5455 info_str
= "IN_R1/B1";
5456 } else if (cmd
[0] == 0x0) {
5457 info_str
= "IN_R1/B2";
5458 } else if (cmd
[0] == 0xD) {
5459 info_str
= "IN_R2/A3,IN_R2/A4";
5460 } else if (cmd
[0] == 0xA) {
5461 info_str
= "OUT_R1/A9,OUT_R1/A10,OUT_R1/A11,OUT_R2/B1,OUT_R2/B2";
5465 if ((cmd
[0] == 0x0) && (cmd
[1] == 0x6)) {
5466 info_str
= "CONN/B3";
5467 } else if ((cmd
[0] == 0xD) && (cmd
[1] == 0xA)) {
5468 info_str
= "OUT_R2/A5,OUT_R2/A6";
5472 if ((cmd
[0] == 0x6) && (cmd
[1] == 0x0) && (cmd
[2] == 0x2)) {
5473 info_str
= "CONN/C1,CONN/C2";
5477 if ((cmd
[0] == 0x6) && (cmd
[1] == 0x3) && (cmd
[2] == 0x3) && (cmd
[3] == 0x0)) {
5478 info_str
= "CONN/A1";
5479 } else if ((cmd
[0] == 0xD) && (cmd
[1] == 0x6) && (cmd
[2] == 0x0) && (cmd
[3] == 0x2)) {
5480 info_str
= "IN_R1/A3,IN_R1/A4";
5484 if ((cmd
[0] == 0x6) && (cmd
[1] == 0x3) && (cmd
[2] == 0x3) && (cmd
[3] == 0x4) && (cmd
[4] == 0x5) && (cmd
[5] == 0xC)) {
5485 info_str
= "CONN/B1";
5493 switch (commands_nb
) {
5498 if ((cmd
[0] == 0x7) || (cmd
[0] == 0x8)) {
5499 info_str
= "OUT_R2/C1";
5506 case RTS_FLAG_OTHER_CMD
:
5507 switch (commands_nb
) {
5509 if (cmd
[0] == 0x5) {
5510 info_str
= "Keep-Alive";
5511 } else if (cmd
[0] == 0xE) {
5512 info_str
= "PingTrafficSentNotify";
5513 } else if (cmd
[0] == 0x1) {
5514 info_str
= "FlowControlAck";
5518 if ((cmd
[0] == 0xD) && (cmd
[1] == 0x1)) {
5519 info_str
= "FlowControlAckWithDestination";
5526 case RTS_FLAG_RECYCLE_CHANNEL
:
5527 switch (commands_nb
) {
5529 if (cmd
[0] == 0xD) {
5530 info_str
= "OUT_R1/A1,OUT_R1/A2,OUT_R2/A1,OUT_R2/A2";
5534 if ((cmd
[0] == 0x6) && (cmd
[1] == 0x3) && (cmd
[2] == 0x3) && (cmd
[3] == 0x3)) {
5535 info_str
= "IN_R1/A1,IN_R2/A1";
5539 if ((cmd
[0] == 0x6) && (cmd
[1] == 0x3) && (cmd
[2] == 0x3) && (cmd
[3] == 0x3) && (cmd
[4] == 0x0)) {
5540 info_str
= "OUT_R1/A3,OUT_R2/A3";
5547 case RTS_FLAG_IN_CHANNEL
|RTS_FLAG_RECYCLE_CHANNEL
:
5548 switch (commands_nb
) {
5550 if ((cmd
[0] == 0x6) && (cmd
[1] == 0x3) && (cmd
[2] == 0x3) && (cmd
[3] == 0x3) && (cmd
[4] == 0x0) && (cmd
[5] == 0x2)) {
5551 info_str
= "IN_R1/A2";
5558 case RTS_FLAG_IN_CHANNEL
:
5559 switch (commands_nb
) {
5561 if ((cmd
[0] == 0x6) && (cmd
[1] == 0x3) && (cmd
[2] == 0x3) && (cmd
[3] == 0x0) && (cmd
[4] == 0x2) && (cmd
[5] == 0xC) && (cmd
[6] == 0xB)) {
5562 info_str
= "CONN/B2";
5569 case RTS_FLAG_OUT_CHANNEL
|RTS_FLAG_RECYCLE_CHANNEL
:
5570 switch (commands_nb
) {
5572 if ((cmd
[0] == 0x6) && (cmd
[1] == 0x3) && (cmd
[2] == 0x3) && (cmd
[3] == 0x3) && (cmd
[4] == 0x4) && (cmd
[5] == 0) && (cmd
[6] == 0x2)) {
5573 info_str
= "OUT_R1/A4";
5580 case RTS_FLAG_OUT_CHANNEL
:
5581 switch (commands_nb
) {
5583 if ((cmd
[0] == 0xD) && (cmd
[1] == 0x3)) {
5584 info_str
= "OUT_R1/A7,OUT_R1/A8,OUT_R2/A8";
5588 if ((cmd
[0] == 0xD) && (cmd
[1] == 0x6) && (cmd
[2] == 0x2)) {
5589 info_str
= "OUT_R1/A5,OUT_R1/A6";
5590 } else if ((cmd
[0] == 0xD) && (cmd
[1] == 0x3) && (cmd
[2] == 0x6)) {
5591 info_str
= "OUT_R2/A7";
5595 if ((cmd
[0] == 0x6) && (cmd
[1] == 0x3) && (cmd
[2] == 0x3) && (cmd
[3] == 0x4) && (cmd
[4] == 0x0)) {
5596 info_str
= "CONN/A2";
5604 switch (commands_nb
) {
5606 if (cmd
[0] == 0xA) {
5607 info_str
= "OUT_R2/B3";
5615 switch (commands_nb
) {
5627 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "%s, ", info_str
);
5628 col_set_fence(pinfo
->cinfo
,COL_INFO
);
5630 parent_pi
= proto_tree_get_parent(dcerpc_tree
);
5631 if (parent_pi
!= NULL
) {
5632 proto_item_append_text(parent_pi
, ", %s", info_str
);
5636 /* Test to see if this looks like a connection oriented PDU */
5638 is_dcerpc(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo _U_
)
5641 uint8_t rpc_ver_minor
;
5646 if (!tvb_bytes_exist(tvb
, offset
, sizeof(e_dce_cn_common_hdr_t
)))
5647 return false; /* not enough information to check */
5649 rpc_ver
= tvb_get_uint8(tvb
, offset
++);
5652 rpc_ver_minor
= tvb_get_uint8(tvb
, offset
++);
5653 if ((rpc_ver_minor
!= 0) && (rpc_ver_minor
!= 1))
5655 ptype
= tvb_get_uint8(tvb
, offset
++);
5656 if (ptype
> PDU_RTS
)
5658 /* Skip flags, nothing good to check */
5661 tvb_memcpy(tvb
, (uint8_t *)drep
, offset
, sizeof (drep
));
5664 if (drep
[1] > DCE_RPC_DREP_FP_IBM
)
5666 offset
+= (int)sizeof(drep
);
5667 frag_len
= dcerpc_tvb_get_ntohs(tvb
, offset
, drep
);
5668 if (frag_len
< sizeof(e_dce_cn_common_hdr_t
)) {
5676 * DCERPC dissector for connection oriented calls.
5679 dissect_dcerpc_cn(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
5680 proto_tree
*tree
, bool can_desegment
, int *pkt_len
)
5682 static const uint8_t nulls
[4] = { 0 };
5686 proto_item
*ti
= NULL
;
5687 proto_item
*tf
= NULL
;
5688 proto_tree
*dcerpc_tree
= NULL
;
5689 e_dce_cn_common_hdr_t hdr
;
5690 dcerpc_auth_info auth_info
;
5691 tvbuff_t
*fragment_tvb
;
5692 dcerpc_decode_as_data
* decode_data
= dcerpc_get_decode_data(pinfo
);
5693 static int * const hdr_flags
[] = {
5694 &hf_dcerpc_cn_flags_object
,
5695 &hf_dcerpc_cn_flags_maybe
,
5696 &hf_dcerpc_cn_flags_dne
,
5697 &hf_dcerpc_cn_flags_mpx
,
5698 &hf_dcerpc_cn_flags_reserved
,
5699 &hf_dcerpc_cn_flags_cancel_pending
,
5700 &hf_dcerpc_cn_flags_last_frag
,
5701 &hf_dcerpc_cn_flags_first_frag
,
5706 * when done over nbt, dcerpc requests are padded with 4 bytes of null
5707 * data for some reason.
5709 * XXX - if that's always the case, the right way to do this would
5710 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
5711 * the 4 bytes of null padding, and make that the dissector
5712 * used for "netbios".
5714 if (tvb_memeql(tvb
, offset
, nulls
, 4) == 0) {
5723 * Check if this looks like a C/O DCERPC call
5725 if (!is_dcerpc(tvb
, offset
, pinfo
))
5728 start_offset
= offset
;
5729 hdr
.rpc_ver
= tvb_get_uint8(tvb
, offset
++);
5730 hdr
.rpc_ver_minor
= tvb_get_uint8(tvb
, offset
++);
5731 hdr
.ptype
= tvb_get_uint8(tvb
, offset
++);
5733 hdr
.flags
= tvb_get_uint8(tvb
, offset
++);
5734 tvb_memcpy(tvb
, (uint8_t *)hdr
.drep
, offset
, sizeof (hdr
.drep
));
5735 offset
+= (int)sizeof (hdr
.drep
);
5737 hdr
.frag_len
= dcerpc_tvb_get_ntohs(tvb
, offset
, hdr
.drep
);
5739 hdr
.auth_len
= dcerpc_tvb_get_ntohs(tvb
, offset
, hdr
.drep
);
5741 hdr
.call_id
= dcerpc_tvb_get_ntohl(tvb
, offset
, hdr
.drep
);
5744 if (can_desegment
&& pinfo
->can_desegment
5745 && !tvb_bytes_exist(tvb
, start_offset
, hdr
.frag_len
)) {
5746 pinfo
->desegment_offset
= start_offset
;
5747 pinfo
->desegment_len
= hdr
.frag_len
- tvb_reported_length_remaining(tvb
, start_offset
);
5748 *pkt_len
= 0; /* desegmentation required */
5752 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "DCERPC");
5754 if (decode_data
->dcectxid
!= 0) {
5755 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
5756 * append a delimiter and set a column fence */
5757 col_append_str(pinfo
->cinfo
, COL_INFO
, " # ");
5758 col_set_fence(pinfo
->cinfo
,COL_INFO
);
5760 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "%s: call_id: %u",
5761 pckt_vals
[hdr
.ptype
].strptr
, hdr
.call_id
);
5763 if (decode_data
->dcectxid
!= 0) {
5764 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU */
5765 expert_add_info(pinfo
, NULL
, &ei_dcerpc_fragment_multiple
);
5768 offset
= start_offset
;
5769 tvb_ensure_bytes_exist(tvb
, offset
, 16);
5771 ti
= proto_tree_add_item(tree
, proto_dcerpc
, tvb
, offset
, hdr
.frag_len
, ENC_NA
);
5772 dcerpc_tree
= proto_item_add_subtree(ti
, ett_dcerpc
);
5775 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_ver
, tvb
, offset
, 1, hdr
.rpc_ver
);
5778 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_ver_minor
, tvb
, offset
, 1, hdr
.rpc_ver_minor
);
5781 tf
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_packet_type
, tvb
, offset
, 1, hdr
.ptype
);
5784 #if 0 /* XXX - too much "output noise", removed for now */
5785 if (hdr
.ptype
== PDU_BIND
|| hdr
.ptype
== PDU_ALTER
||
5786 hdr
.ptype
== PDU_BIND_ACK
|| hdr
.ptype
== PDU_ALTER_ACK
)
5787 expert_add_info_format(pinfo
, tf
, &ei_dcerpc_context_change
, "Context change: %s", val_to_str(hdr
.ptype
, pckt_vals
, "(0x%x)"));
5789 if (hdr
.ptype
== PDU_BIND_NAK
)
5790 expert_add_info(pinfo
, tf
, &ei_dcerpc_bind_not_acknowledged
);
5793 proto_item_append_text(ti
, " %s, Fragment: %s",
5794 val_to_str(hdr
.ptype
, pckt_vals
, "Unknown (0x%02x)"),
5795 fragment_type(hdr
.flags
));
5798 proto_tree_add_bitmask_value_with_flags(dcerpc_tree
, tvb
, offset
, hf_dcerpc_cn_flags
,
5799 ett_dcerpc_cn_flags
, hdr_flags
, hdr
.flags
, BMT_NO_APPEND
);
5802 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", Fragment: %s", fragment_type(hdr
.flags
));
5804 proto_tree_add_dcerpc_drep(dcerpc_tree
, tvb
, offset
, hdr
.drep
, (int)sizeof (hdr
.drep
));
5805 offset
+= (int)sizeof (hdr
.drep
);
5807 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_cn_frag_len
, tvb
, offset
, 2, hdr
.frag_len
);
5810 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_cn_auth_len
, tvb
, offset
, 2, hdr
.auth_len
);
5813 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_cn_call_id
, tvb
, offset
, 4, hdr
.call_id
);
5817 proto_item_append_text(ti
, ", FragLen: %u, Call: %u", hdr
.frag_len
, hdr
.call_id
);
5821 * None of the stuff done above should throw an exception, because
5822 * we would have rejected this as "not DCE RPC" if we didn't have all
5823 * of it. (XXX - perhaps we should request reassembly if we have
5824 * enough of the header to consider it DCE RPC but not enough to
5825 * get the fragment length; in that case the stuff still wouldn't
5826 * throw an exception.)
5828 * The rest of the stuff might, so return the PDU length to our caller.
5829 * XXX - should we construct a tvbuff containing only the PDU and
5830 * use that? Or should we have separate "is this a DCE RPC PDU",
5831 * "how long is it", and "dissect it" routines - which might let us
5832 * do most of the work in "tcp_dissect_pdus()"?
5834 if (pkt_len
!= NULL
)
5835 *pkt_len
= hdr
.frag_len
+ padding
;
5837 /* The remaining bytes in the current tvb might contain multiple
5838 * DCE/RPC fragments, so create a new tvb subset for this fragment.
5839 * Only limit the end of the fragment, but not the offset start,
5840 * as the authentication function dissect_dcerpc_cn_auth() will fail
5841 * (and other functions might fail as well) computing the right start
5844 subtvb_len
= MIN(hdr
.frag_len
, tvb_reported_length(tvb
));
5845 fragment_tvb
= tvb_new_subset_length_caplen(tvb
, start_offset
,
5846 subtvb_len
/* length */,
5847 hdr
.frag_len
/* reported_length */);
5850 * Packet type specific stuff is next.
5852 switch (hdr
.ptype
) {
5855 dissect_dcerpc_cn_bind(fragment_tvb
, MIN(offset
- start_offset
, subtvb_len
), pinfo
, dcerpc_tree
, &hdr
);
5860 dissect_dcerpc_cn_bind_ack(fragment_tvb
, MIN(offset
- start_offset
, subtvb_len
), pinfo
, dcerpc_tree
, &hdr
);
5865 * Nothing after the common header other than credentials.
5867 dissect_dcerpc_cn_auth(fragment_tvb
, MIN(offset
- start_offset
, subtvb_len
), pinfo
, dcerpc_tree
, &hdr
,
5872 dissect_dcerpc_cn_rqst(fragment_tvb
, MIN(offset
- start_offset
, subtvb_len
), pinfo
, dcerpc_tree
, tree
, &hdr
);
5876 dissect_dcerpc_cn_resp(fragment_tvb
, MIN(offset
- start_offset
, subtvb_len
), pinfo
, dcerpc_tree
, tree
, &hdr
);
5880 dissect_dcerpc_cn_fault(fragment_tvb
, MIN(offset
- start_offset
, subtvb_len
), pinfo
, dcerpc_tree
, &hdr
);
5884 dissect_dcerpc_cn_bind_nak(fragment_tvb
, MIN(offset
- start_offset
, subtvb_len
), pinfo
, dcerpc_tree
, &hdr
);
5890 * Nothing after the common header other than an authentication
5893 dissect_dcerpc_cn_auth(fragment_tvb
, MIN(offset
- start_offset
, subtvb_len
), pinfo
, dcerpc_tree
, &hdr
,
5899 * Nothing after the common header, not even an authentication
5904 dissect_dcerpc_cn_rts(fragment_tvb
, MIN(offset
- start_offset
, subtvb_len
), pinfo
, dcerpc_tree
, &hdr
);
5908 /* might as well dissect the auth info */
5909 dissect_dcerpc_cn_auth(fragment_tvb
, MIN(offset
- start_offset
, subtvb_len
), pinfo
, dcerpc_tree
, &hdr
,
5917 * DCERPC dissector for connection oriented calls over packet-oriented
5921 dissect_dcerpc_cn_pk(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
5923 dcerpc_decode_as_data
* decode_data
= dcerpc_get_decode_data(pinfo
);
5926 * Only one PDU per transport packet, and only one transport
5929 decode_data
->dcetransporttype
= DCE_TRANSPORT_UNKNOWN
;
5930 if (!dissect_dcerpc_cn(tvb
, 0, pinfo
, tree
, false, NULL
)) {
5932 * It wasn't a DCERPC PDU.
5944 * DCERPC dissector for connection oriented calls over byte-stream
5946 * we need to distinguish here between SMB and non-TCP (more in the future?)
5947 * to be able to know what kind of private_data structure to expect.
5950 dissect_dcerpc_cn_bs_body(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
5952 volatile int offset
= 0;
5954 volatile int dcerpc_pdus
= 0;
5955 volatile bool ret
= false;
5958 * There may be multiple PDUs per transport packet; keep
5961 while (tvb_reported_length_remaining(tvb
, offset
) != 0) {
5964 if (dissect_dcerpc_cn(tvb
, offset
, pinfo
, tree
,
5965 dcerpc_cn_desegment
, &pdu_len
)) {
5968 } CATCH_NONFATAL_ERRORS
{
5970 * Somebody threw an exception that means that there
5971 * was a problem dissecting the payload; that means
5972 * that a dissector was found, so we don't need to
5973 * dissect the payload as data or update the protocol
5976 * Just show the exception and then continue dissecting
5979 show_exception(tvb
, pinfo
, tree
, EXCEPT_CODE
, GET_MESSAGE
);
5981 * Presumably it looked enough like a DCE RPC PDU that we
5982 * dissected enough of it to throw an exception.
5987 if (dcerpc_pdus
== 0) {
5988 bool try_desegment
= false;
5989 if (dcerpc_cn_desegment
&& pinfo
->can_desegment
&&
5990 !tvb_bytes_exist(tvb
, offset
, sizeof(e_dce_cn_common_hdr_t
))) {
5991 /* look for a previous occurrence of the DCE-RPC protocol */
5992 wmem_list_frame_t
*cur
;
5993 cur
= wmem_list_frame_prev(wmem_list_tail(pinfo
->layers
));
5994 while (cur
!= NULL
) {
5995 if (proto_dcerpc
== (int)GPOINTER_TO_UINT(wmem_list_frame_data(cur
))) {
5996 try_desegment
= true;
5999 cur
= wmem_list_frame_prev(cur
);
6003 if (try_desegment
) {
6004 /* It didn't look like DCE-RPC but we already had one DCE-RPC
6005 * layer in this packet and what we have is short. Assume that
6006 * it was just too short to tell and ask the TCP layer for more
6008 pinfo
->desegment_offset
= offset
;
6009 pinfo
->desegment_len
= (uint32_t)(sizeof(e_dce_cn_common_hdr_t
) - tvb_reported_length_remaining(tvb
, offset
));
6011 /* Really not DCE-RPC */
6017 * Well, we've seen at least one DCERPC PDU.
6021 /* if we had more than one Req/Resp in this PDU change the protocol column */
6022 /* this will formerly contain the last interface name, which may not be the same for all Req/Resp */
6023 if (dcerpc_pdus
>= 2)
6024 col_add_fstr(pinfo
->cinfo
, COL_PROTOCOL
, "%u*DCERPC", dcerpc_pdus
);
6028 * Desegmentation required - bail now, but give the user a hint that desegmentation might be done later.
6030 proto_tree_add_uint_format(tree
, hf_dcerpc_cn_deseg_req
, tvb
, offset
,
6032 tvb_reported_length_remaining(tvb
, offset
),
6033 "[DCE RPC: %u byte%s left, desegmentation might follow]",
6034 tvb_reported_length_remaining(tvb
, offset
),
6035 plurality(tvb_reported_length_remaining(tvb
, offset
), "", "s"));
6040 * Step to the next PDU.
6048 dissect_dcerpc_cn_bs(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
6050 dcerpc_decode_as_data
* decode_data
= dcerpc_get_decode_data(pinfo
);
6052 decode_data
->dcetransporttype
= DCE_TRANSPORT_UNKNOWN
;
6053 return dissect_dcerpc_cn_bs_body(tvb
, pinfo
, tree
);
6057 get_dcerpc_pdu_len(packet_info
*pinfo _U_
, tvbuff_t
*tvb
,
6058 int offset
, void *data _U_
)
6063 tvb_memcpy(tvb
, (uint8_t *)drep
, offset
+4, sizeof(drep
));
6064 frag_len
= dcerpc_tvb_get_ntohs(tvb
, offset
+8, drep
);
6067 /* tcp_dissect_pdus() interprets a 0 return value as meaning
6068 * "a PDU starts here, but the length cannot be determined yet, so
6069 * we need at least one more segment." However, a frag_len of 0 here
6070 * is instead a bogus length. Instead return 1, another bogus length
6071 * also less than our fixed length, so that the TCP dissector will
6072 * correctly interpret it as a bogus and report an error.
6080 dissect_dcerpc_pdu(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
6083 dissect_dcerpc_cn(tvb
, 0, pinfo
, tree
,
6084 /* Desegment is already handled by TCP, don't confuse it */
6091 dissect_dcerpc_tcp_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
6093 dcerpc_decode_as_data
* decode_data
;
6095 if (!is_dcerpc(tvb
, 0, pinfo
))
6098 decode_data
= dcerpc_get_decode_data(pinfo
);
6099 decode_data
->dcetransporttype
= DCE_TRANSPORT_UNKNOWN
;
6101 tcp_dissect_pdus(tvb
, pinfo
, tree
, dcerpc_cn_desegment
, sizeof(e_dce_cn_common_hdr_t
), get_dcerpc_pdu_len
, dissect_dcerpc_pdu
, data
);
6106 dissect_dcerpc_tcp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
6108 dcerpc_decode_as_data
* decode_data
;
6110 decode_data
= dcerpc_get_decode_data(pinfo
);
6111 decode_data
->dcetransporttype
= DCE_TRANSPORT_UNKNOWN
;
6113 tcp_dissect_pdus(tvb
, pinfo
, tree
, dcerpc_cn_desegment
, sizeof(e_dce_cn_common_hdr_t
), get_dcerpc_pdu_len
, dissect_dcerpc_pdu
, data
);
6114 return tvb_captured_length(tvb
);
6118 dissect_dcerpc_cn_smbpipe(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
6120 dcerpc_decode_as_data
* decode_data
= dcerpc_get_decode_data(pinfo
);
6122 decode_data
->dcetransporttype
= DCE_CN_TRANSPORT_SMBPIPE
;
6123 return dissect_dcerpc_cn_bs_body(tvb
, pinfo
, tree
);
6127 dissect_dcerpc_cn_smb2(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
6129 dcerpc_decode_as_data
* decode_data
= dcerpc_get_decode_data(pinfo
);
6131 decode_data
->dcetransporttype
= DCE_CN_TRANSPORT_SMBPIPE
;
6132 return dissect_dcerpc_cn_bs_body(tvb
, pinfo
, tree
);
6138 dissect_dcerpc_dg_auth(tvbuff_t
*tvb
, int offset
, proto_tree
*dcerpc_tree
,
6139 e_dce_dg_common_hdr_t
*hdr
, int *auth_level_p
)
6141 proto_tree
*auth_tree
= NULL
;
6142 uint8_t protection_level
;
6145 * Initially set "*auth_level_p" to -1 to indicate that we haven't
6146 * yet seen any authentication level information.
6148 if (auth_level_p
!= NULL
)
6152 * The authentication information is at the *end* of the PDU; in
6153 * request and response PDUs, the request and response stub data
6156 * If the full packet is here, and there's data past the end of the
6157 * packet body, then dissect the auth info.
6159 offset
+= hdr
->frag_len
;
6160 if (tvb_reported_length_remaining(tvb
, offset
) > 0) {
6161 switch (hdr
->auth_proto
) {
6163 case DCE_C_RPC_AUTHN_PROTOCOL_KRB5
:
6164 auth_tree
= proto_tree_add_subtree(dcerpc_tree
, tvb
, offset
, -1, ett_dcerpc_krb5_auth_verf
, NULL
, "Kerberos authentication verifier");
6165 protection_level
= tvb_get_uint8(tvb
, offset
);
6166 if (auth_level_p
!= NULL
)
6167 *auth_level_p
= protection_level
;
6168 proto_tree_add_uint(auth_tree
, hf_dcerpc_krb5_av_prot_level
, tvb
, offset
, 1, protection_level
);
6170 proto_tree_add_item(auth_tree
, hf_dcerpc_krb5_av_key_vers_num
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
6172 if (protection_level
== DCE_C_AUTHN_LEVEL_PKT_PRIVACY
)
6173 offset
+= 6; /* 6 bytes of padding */
6175 offset
+= 2; /* 2 bytes of padding */
6176 proto_tree_add_item(auth_tree
, hf_dcerpc_krb5_av_key_auth_verifier
, tvb
, offset
, 16, ENC_NA
);
6181 proto_tree_add_item(dcerpc_tree
, hf_dcerpc_authentication_verifier
, tvb
, offset
, -1, ENC_NA
);
6188 dissect_dcerpc_dg_cancel_ack(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
6189 proto_tree
*dcerpc_tree
,
6190 e_dce_dg_common_hdr_t
*hdr
)
6194 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
,
6195 hdr
->drep
, hf_dcerpc_dg_cancel_vers
,
6201 /* The only version we know about */
6202 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
,
6203 hdr
->drep
, hf_dcerpc_dg_cancel_id
,
6205 /*offset = */dissect_dcerpc_uint8(tvb
, offset
, pinfo
, dcerpc_tree
,
6206 hdr
->drep
, hf_dcerpc_dg_server_accepting_cancels
,
6213 dissect_dcerpc_dg_cancel(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
6214 proto_tree
*dcerpc_tree
,
6215 e_dce_dg_common_hdr_t
*hdr
)
6219 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
,
6220 hdr
->drep
, hf_dcerpc_dg_cancel_vers
,
6226 /* The only version we know about */
6227 /*offset = */dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
,
6228 hdr
->drep
, hf_dcerpc_dg_cancel_id
,
6230 /* XXX - are NDR Booleans 32 bits? */
6232 /* XXX - the RPC reference in chapter: "the cancel PDU" doesn't mention
6233 the accepting_cancels field (it's only in the cancel_ack PDU)! */
6234 /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
6235 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
6242 dissect_dcerpc_dg_fack(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
6243 proto_tree
*dcerpc_tree
,
6244 e_dce_dg_common_hdr_t
*hdr
)
6247 uint16_t serial_num
;
6248 uint16_t selack_len
;
6251 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, dcerpc_tree
,
6252 hdr
->drep
, hf_dcerpc_dg_fack_vers
,
6259 case 0: /* The only version documented in the DCE RPC 1.1 spec */
6260 case 1: /* This appears to be the same */
6261 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
,
6262 hdr
->drep
, hf_dcerpc_dg_fack_window_size
,
6264 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
,
6265 hdr
->drep
, hf_dcerpc_dg_fack_max_tsdu
,
6267 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
,
6268 hdr
->drep
, hf_dcerpc_dg_fack_max_frag_size
,
6270 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
,
6271 hdr
->drep
, hf_dcerpc_dg_fack_serial_num
,
6273 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " serial: %u",
6275 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
,
6276 hdr
->drep
, hf_dcerpc_dg_fack_selack_len
,
6278 for (i
= 0; i
< selack_len
; i
++) {
6279 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
,
6280 hdr
->drep
, hf_dcerpc_dg_fack_selack
,
6289 dissect_dcerpc_dg_reject_fault(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
6290 proto_tree
*dcerpc_tree
,
6291 e_dce_dg_common_hdr_t
*hdr
)
6295 /*offset = */dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
,
6296 hdr
->drep
, hf_dcerpc_dg_status
,
6299 col_append_fstr (pinfo
->cinfo
, COL_INFO
,
6301 val_to_str(status
, reject_status_vals
, "Unknown (0x%08x)"));
6305 dissect_dcerpc_dg_stub(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
6306 proto_tree
*dcerpc_tree
, proto_tree
*tree
,
6307 e_dce_dg_common_hdr_t
*hdr
, dcerpc_info
*di
)
6309 int length
, reported_length
, stub_length
;
6310 bool save_fragmented
;
6311 fragment_head
*fd_head
;
6314 proto_item
*parent_pi
;
6316 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " opnum: %u len: %u",
6317 di
->call_data
->opnum
, hdr
->frag_len
);
6319 length
= tvb_reported_length_remaining(tvb
, offset
);
6320 reported_length
= tvb_reported_length_remaining(tvb
, offset
);
6321 stub_length
= hdr
->frag_len
;
6322 if (length
> stub_length
)
6323 length
= stub_length
;
6324 if (reported_length
> stub_length
)
6325 reported_length
= stub_length
;
6327 save_fragmented
= pinfo
->fragmented
;
6329 /* If we don't have reassembly enabled, or this packet contains
6330 the entire PDU, or if this is a short frame (or a frame
6331 not reassembled at a lower layer) that doesn't include all
6332 the data in the fragment, just call the handoff directly if
6333 this is the first fragment or the PDU isn't fragmented. */
6334 if ( (!dcerpc_reassemble
) || !(hdr
->flags1
& PFCL1_FRAG
) ||
6335 !tvb_bytes_exist(tvb
, offset
, stub_length
) ) {
6336 if (hdr
->frag_num
== 0) {
6339 /* First fragment, possibly the only fragment */
6342 * XXX - authentication info?
6344 pinfo
->fragmented
= (hdr
->flags1
& PFCL1_FRAG
);
6345 next_tvb
= tvb_new_subset_length_caplen(tvb
, offset
, length
,
6347 dcerpc_try_handoff(pinfo
, tree
, dcerpc_tree
, next_tvb
, true, hdr
->drep
, di
, NULL
);
6349 /* PDU is fragmented and this isn't the first fragment */
6351 proto_tree_add_item(dcerpc_tree
, hf_dcerpc_fragment_data
, tvb
, offset
, stub_length
, ENC_NA
);
6355 /* Reassembly is enabled, the PDU is fragmented, and
6356 we have all the data in the fragment; the first two
6357 of those mean we should attempt reassembly, and the
6358 third means we can attempt reassembly. */
6360 proto_tree_add_item(dcerpc_tree
, hf_dcerpc_fragment_data
, tvb
, offset
, stub_length
, ENC_NA
);
6363 fd_head
= fragment_add_seq(&dcerpc_cl_reassembly_table
,
6365 pinfo
, hdr
->seqnum
, (void *)hdr
,
6366 hdr
->frag_num
, stub_length
,
6367 !(hdr
->flags1
& PFCL1_LASTFRAG
), 0);
6368 if (fd_head
!= NULL
) {
6369 /* We completed reassembly... */
6370 if (pinfo
->num
== fd_head
->reassembled_in
) {
6371 /* ...and this is the reassembled RPC PDU */
6372 next_tvb
= tvb_new_chain(tvb
, fd_head
->tvb_data
);
6373 add_new_data_source(pinfo
, next_tvb
, "Reassembled DCE/RPC");
6374 show_fragment_seq_tree(fd_head
, &dcerpc_frag_items
,
6375 tree
, pinfo
, next_tvb
, &pi
);
6378 * XXX - authentication info?
6380 pinfo
->fragmented
= false;
6381 dcerpc_try_handoff(pinfo
, tree
, dcerpc_tree
, next_tvb
, true, hdr
->drep
, di
, NULL
);
6383 /* ...and this isn't the reassembled RPC PDU */
6384 pi
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_reassembled_in
,
6385 tvb
, 0, 0, fd_head
->reassembled_in
);
6386 proto_item_set_generated(pi
);
6387 parent_pi
= proto_tree_get_parent(dcerpc_tree
);
6388 if (parent_pi
!= NULL
) {
6389 proto_item_append_text(parent_pi
, ", [Reas: #%u]", fd_head
->reassembled_in
);
6391 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
6392 " [DCE/RPC fragment, reas: #%u]", fd_head
->reassembled_in
);
6396 pinfo
->fragmented
= save_fragmented
;
6400 dissect_dcerpc_dg_rqst(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
6401 proto_tree
*dcerpc_tree
, proto_tree
*tree
,
6402 e_dce_dg_common_hdr_t
*hdr
, conversation_t
*conv
)
6405 dcerpc_call_value
*value
;
6406 dcerpc_matched_key matched_key
, *new_matched_key
;
6408 proto_item
*parent_pi
;
6410 if (!(pinfo
->fd
->visited
)) {
6411 dcerpc_call_value
*call_value
;
6412 dcerpc_dg_call_key
*call_key
;
6414 call_key
= wmem_new(wmem_file_scope(), dcerpc_dg_call_key
);
6415 call_key
->conv
= conv
;
6416 call_key
->seqnum
= hdr
->seqnum
;
6417 call_key
->act_id
= hdr
->act_id
;
6419 call_value
= wmem_new(wmem_file_scope(), dcerpc_call_value
);
6420 call_value
->uuid
= hdr
->if_id
;
6421 call_value
->ver
= hdr
->if_ver
;
6422 call_value
->object_uuid
= hdr
->obj_id
;
6423 call_value
->opnum
= hdr
->opnum
;
6424 call_value
->req_frame
= pinfo
->num
;
6425 call_value
->req_time
= pinfo
->abs_ts
;
6426 call_value
->rep_frame
= 0;
6427 call_value
->max_ptr
= 0;
6428 call_value
->se_data
= NULL
;
6429 call_value
->private_data
= NULL
;
6430 call_value
->pol
= NULL
;
6431 /* NDR64 is not available on dg transports ?*/
6432 call_value
->flags
= 0;
6434 wmem_map_insert(dcerpc_dg_calls
, call_key
, call_value
);
6436 new_matched_key
= wmem_new(wmem_file_scope(), dcerpc_matched_key
);
6437 new_matched_key
->frame
= pinfo
->num
;
6438 new_matched_key
->call_id
= hdr
->seqnum
;
6439 wmem_map_insert(dcerpc_matched
, new_matched_key
, call_value
);
6442 matched_key
.frame
= pinfo
->num
;
6443 matched_key
.call_id
= hdr
->seqnum
;
6444 value
= (dcerpc_call_value
*)wmem_map_lookup(dcerpc_matched
, &matched_key
);
6446 value
= wmem_new(pinfo
->pool
, dcerpc_call_value
);
6447 value
->uuid
= hdr
->if_id
;
6448 value
->ver
= hdr
->if_ver
;
6449 value
->object_uuid
= hdr
->obj_id
;
6450 value
->opnum
= hdr
->opnum
;
6451 value
->req_frame
= pinfo
->num
;
6452 value
->rep_frame
= 0;
6454 value
->se_data
= NULL
;
6455 value
->private_data
= NULL
;
6458 di
= wmem_new0(pinfo
->pool
, dcerpc_info
);
6459 di
->dcerpc_procedure_name
= "";
6461 di
->call_id
= hdr
->seqnum
;
6462 di
->transport_salt
= -1;
6463 di
->ptype
= PDU_REQ
;
6464 di
->call_data
= value
;
6466 if (value
->rep_frame
!= 0) {
6467 pi
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_response_in
,
6468 tvb
, 0, 0, value
->rep_frame
);
6469 proto_item_set_generated(pi
);
6470 parent_pi
= proto_tree_get_parent(dcerpc_tree
);
6471 if (parent_pi
!= NULL
) {
6472 proto_item_append_text(parent_pi
, ", [Resp: #%u]", value
->rep_frame
);
6475 dissect_dcerpc_dg_stub(tvb
, offset
, pinfo
, dcerpc_tree
, tree
, hdr
, di
);
6479 dissect_dcerpc_dg_resp(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
6480 proto_tree
*dcerpc_tree
, proto_tree
*tree
,
6481 e_dce_dg_common_hdr_t
*hdr
, conversation_t
*conv
)
6484 dcerpc_call_value
*value
;
6485 dcerpc_matched_key matched_key
, *new_matched_key
;
6487 proto_item
*parent_pi
;
6489 if (!(pinfo
->fd
->visited
)) {
6490 dcerpc_call_value
*call_value
;
6491 dcerpc_dg_call_key call_key
;
6493 call_key
.conv
= conv
;
6494 call_key
.seqnum
= hdr
->seqnum
;
6495 call_key
.act_id
= hdr
->act_id
;
6497 if ((call_value
= (dcerpc_call_value
*)wmem_map_lookup(dcerpc_dg_calls
, &call_key
))) {
6498 new_matched_key
= wmem_new(wmem_file_scope(), dcerpc_matched_key
);
6499 new_matched_key
->frame
= pinfo
->num
;
6500 new_matched_key
->call_id
= hdr
->seqnum
;
6501 wmem_map_insert(dcerpc_matched
, new_matched_key
, call_value
);
6502 if (call_value
->rep_frame
== 0) {
6503 call_value
->rep_frame
= pinfo
->num
;
6508 matched_key
.frame
= pinfo
->num
;
6509 matched_key
.call_id
= hdr
->seqnum
;
6510 value
= (dcerpc_call_value
*)wmem_map_lookup(dcerpc_matched
, &matched_key
);
6512 value
= wmem_new0(pinfo
->pool
, dcerpc_call_value
);
6513 value
->uuid
= hdr
->if_id
;
6514 value
->ver
= hdr
->if_ver
;
6515 value
->object_uuid
= hdr
->obj_id
;
6516 value
->opnum
= hdr
->opnum
;
6517 value
->rep_frame
= pinfo
->num
;
6520 di
= wmem_new0(pinfo
->pool
, dcerpc_info
);
6521 di
->dcerpc_procedure_name
= "";
6523 di
->transport_salt
= -1;
6524 di
->ptype
= PDU_RESP
;
6525 di
->call_data
= value
;
6527 if (value
->req_frame
!= 0) {
6529 pi
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_request_in
,
6530 tvb
, 0, 0, value
->req_frame
);
6531 proto_item_set_generated(pi
);
6532 parent_pi
= proto_tree_get_parent(dcerpc_tree
);
6533 if (parent_pi
!= NULL
) {
6534 proto_item_append_text(parent_pi
, ", [Req: #%u]", value
->req_frame
);
6536 nstime_delta(&delta_ts
, &pinfo
->abs_ts
, &value
->req_time
);
6537 pi
= proto_tree_add_time(dcerpc_tree
, hf_dcerpc_time
, tvb
, offset
, 0, &delta_ts
);
6538 proto_item_set_generated(pi
);
6540 proto_tree_add_expert(dcerpc_tree
, pinfo
, &ei_dcerpc_no_request_found
, tvb
, 0, 0);
6542 dissect_dcerpc_dg_stub(tvb
, offset
, pinfo
, dcerpc_tree
, tree
, hdr
, di
);
6546 dissect_dcerpc_dg_ping_ack(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
6547 proto_tree
*dcerpc_tree
,
6548 e_dce_dg_common_hdr_t
*hdr
, conversation_t
*conv
)
6550 proto_item
*parent_pi
;
6551 /* if (!(pinfo->fd->visited)) {*/
6552 dcerpc_call_value
*call_value
;
6553 dcerpc_dg_call_key call_key
;
6555 call_key
.conv
= conv
;
6556 call_key
.seqnum
= hdr
->seqnum
;
6557 call_key
.act_id
= hdr
->act_id
;
6559 if ((call_value
= (dcerpc_call_value
*)wmem_map_lookup(dcerpc_dg_calls
, &call_key
))) {
6563 pi
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_request_in
,
6564 tvb
, 0, 0, call_value
->req_frame
);
6565 proto_item_set_generated(pi
);
6566 parent_pi
= proto_tree_get_parent(dcerpc_tree
);
6567 if (parent_pi
!= NULL
) {
6568 proto_item_append_text(parent_pi
, ", [Req: #%u]", call_value
->req_frame
);
6571 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " [req: #%u]", call_value
->req_frame
);
6573 nstime_delta(&delta_ts
, &pinfo
->abs_ts
, &call_value
->req_time
);
6574 pi
= proto_tree_add_time(dcerpc_tree
, hf_dcerpc_time
, tvb
, offset
, 0, &delta_ts
);
6575 proto_item_set_generated(pi
);
6581 * DCERPC dissector for connectionless calls
6584 dissect_dcerpc_dg(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
6586 proto_item
*ti
= NULL
;
6587 proto_tree
*dcerpc_tree
= NULL
;
6588 e_dce_dg_common_hdr_t hdr
;
6590 conversation_t
*conv
;
6593 const char *uuid_name
= NULL
;
6594 static int * const hdr_flags1
[] = {
6595 &hf_dcerpc_dg_flags1_rsrvd_80
,
6596 &hf_dcerpc_dg_flags1_broadcast
,
6597 &hf_dcerpc_dg_flags1_idempotent
,
6598 &hf_dcerpc_dg_flags1_maybe
,
6599 &hf_dcerpc_dg_flags1_nofack
,
6600 &hf_dcerpc_dg_flags1_frag
,
6601 &hf_dcerpc_dg_flags1_last_frag
,
6602 &hf_dcerpc_dg_flags1_rsrvd_01
,
6606 static int * const hdr_flags2
[] = {
6607 &hf_dcerpc_dg_flags2_rsrvd_80
,
6608 &hf_dcerpc_dg_flags2_rsrvd_40
,
6609 &hf_dcerpc_dg_flags2_rsrvd_20
,
6610 &hf_dcerpc_dg_flags2_rsrvd_10
,
6611 &hf_dcerpc_dg_flags2_rsrvd_08
,
6612 &hf_dcerpc_dg_flags2_rsrvd_04
,
6613 &hf_dcerpc_dg_flags2_cancel_pending
,
6614 &hf_dcerpc_dg_flags2_rsrvd_01
,
6619 * Check if this looks like a CL DCERPC call. All dg packets
6620 * have an 80 byte header on them. Which starts with
6621 * version (4), pkt_type.
6623 if (tvb_reported_length(tvb
) < sizeof (hdr
)) {
6627 /* Version must be 4 */
6628 hdr
.rpc_ver
= tvb_get_uint8(tvb
, offset
++);
6629 if (hdr
.rpc_ver
!= 4)
6632 /* Type must be <= PDU_CANCEL_ACK or it's not connectionless DCE/RPC */
6633 hdr
.ptype
= tvb_get_uint8(tvb
, offset
++);
6634 if (hdr
.ptype
> PDU_CANCEL_ACK
)
6637 /* flags1 has bit 1 and 8 as reserved for implementations, with no
6638 indication that they must be set to 0, so we don't check them.
6640 hdr
.flags1
= tvb_get_uint8(tvb
, offset
++);
6642 /* flags2 has bit 1 reserved for implementations, bit 2 used,
6643 and the other bits reserved for future use and specified
6644 as "must be set to 0", so if any of the other bits are set
6645 it is probably not DCE/RPC.
6647 hdr
.flags2
= tvb_get_uint8(tvb
, offset
++);
6648 if (hdr
.flags2
&0xfc)
6651 tvb_memcpy(tvb
, (uint8_t *)hdr
.drep
, offset
, sizeof (hdr
.drep
));
6652 offset
+= (int)sizeof (hdr
.drep
);
6653 if (hdr
.drep
[0]&0xee)
6655 if (hdr
.drep
[1] > DCE_RPC_DREP_FP_IBM
)
6658 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "DCERPC");
6659 col_add_str(pinfo
->cinfo
, COL_INFO
, pckt_vals
[hdr
.ptype
].strptr
);
6661 hdr
.serial_hi
= tvb_get_uint8(tvb
, offset
++);
6662 dcerpc_tvb_get_uuid(tvb
, offset
, hdr
.drep
, &hdr
.obj_id
);
6664 dcerpc_tvb_get_uuid(tvb
, offset
, hdr
.drep
, &hdr
.if_id
);
6666 dcerpc_tvb_get_uuid(tvb
, offset
, hdr
.drep
, &hdr
.act_id
);
6668 hdr
.server_boot
= dcerpc_tvb_get_ntohl(tvb
, offset
, hdr
.drep
);
6670 hdr
.if_ver
= dcerpc_tvb_get_ntohl(tvb
, offset
, hdr
.drep
);
6672 hdr
.seqnum
= dcerpc_tvb_get_ntohl(tvb
, offset
, hdr
.drep
);
6674 hdr
.opnum
= dcerpc_tvb_get_ntohs(tvb
, offset
, hdr
.drep
);
6676 hdr
.ihint
= dcerpc_tvb_get_ntohs(tvb
, offset
, hdr
.drep
);
6678 hdr
.ahint
= dcerpc_tvb_get_ntohs(tvb
, offset
, hdr
.drep
);
6680 hdr
.frag_len
= dcerpc_tvb_get_ntohs(tvb
, offset
, hdr
.drep
);
6682 hdr
.frag_num
= dcerpc_tvb_get_ntohs(tvb
, offset
, hdr
.drep
);
6684 hdr
.auth_proto
= tvb_get_uint8(tvb
, offset
++);
6685 hdr
.serial_lo
= tvb_get_uint8(tvb
, offset
++);
6688 ti
= proto_tree_add_item(tree
, proto_dcerpc
, tvb
, 0, -1, ENC_NA
);
6690 dcerpc_tree
= proto_item_add_subtree(ti
, ett_dcerpc
);
6691 proto_item_append_text(ti
, " %s, Seq: %u, Serial: %u, Frag: %u, FragLen: %u",
6692 val_to_str(hdr
.ptype
, pckt_vals
, "Unknown (0x%02x)"),
6693 hdr
.seqnum
, hdr
.serial_hi
*256+hdr
.serial_lo
,
6694 hdr
.frag_num
, hdr
.frag_len
);
6699 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_ver
, tvb
, offset
, 1, hdr
.rpc_ver
);
6702 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_packet_type
, tvb
, offset
, 1, hdr
.ptype
);
6705 proto_tree_add_bitmask_value(dcerpc_tree
, tvb
, offset
, hf_dcerpc_dg_flags1
,
6706 ett_dcerpc_dg_flags1
, hdr_flags1
, hdr
.flags1
);
6709 proto_tree_add_bitmask_value(dcerpc_tree
, tvb
, offset
, hf_dcerpc_dg_flags2
,
6710 ett_dcerpc_dg_flags2
, hdr_flags2
, hdr
.flags2
);
6714 proto_tree_add_dcerpc_drep(dcerpc_tree
, tvb
, offset
, hdr
.drep
, (int)sizeof (hdr
.drep
));
6716 offset
+= (int)sizeof (hdr
.drep
);
6719 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_dg_serial_hi
, tvb
, offset
, 1, hdr
.serial_hi
);
6723 proto_tree_add_guid_format(dcerpc_tree
, hf_dcerpc_obj_id
, tvb
,
6724 offset
, 16, (e_guid_t
*) &hdr
.obj_id
, "Object UUID: %s",
6725 guid_to_str(pinfo
->pool
, (e_guid_t
*) &hdr
.obj_id
));
6730 uuid_str
= guid_to_str(pinfo
->pool
, (e_guid_t
*)&hdr
.if_id
);
6731 uuid_name
= guids_get_uuid_name(&hdr
.if_id
, pinfo
->pool
);
6733 proto_tree_add_guid_format(dcerpc_tree
, hf_dcerpc_dg_if_id
, tvb
,
6734 offset
, 16, (e_guid_t
*) &hdr
.if_id
, "Interface: %s UUID: %s", uuid_name
, uuid_str
);
6736 proto_tree_add_guid_format(dcerpc_tree
, hf_dcerpc_dg_if_id
, tvb
,
6737 offset
, 16, (e_guid_t
*) &hdr
.if_id
, "Interface UUID: %s", uuid_str
);
6743 proto_tree_add_guid_format(dcerpc_tree
, hf_dcerpc_dg_act_id
, tvb
,
6744 offset
, 16, (e_guid_t
*) &hdr
.act_id
, "Activity: %s",
6745 guid_to_str(pinfo
->pool
, (e_guid_t
*) &hdr
.act_id
));
6750 nstime_t server_boot
;
6752 server_boot
.secs
= hdr
.server_boot
;
6753 server_boot
.nsecs
= 0;
6755 if (hdr
.server_boot
== 0)
6756 proto_tree_add_time_format_value(dcerpc_tree
, hf_dcerpc_dg_server_boot
,
6757 tvb
, offset
, 4, &server_boot
,
6760 proto_tree_add_time(dcerpc_tree
, hf_dcerpc_dg_server_boot
,
6761 tvb
, offset
, 4, &server_boot
);
6766 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_dg_if_ver
, tvb
, offset
, 4, hdr
.if_ver
);
6770 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_dg_seqnum
, tvb
, offset
, 4, hdr
.seqnum
);
6771 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ": seq: %u", hdr
.seqnum
);
6775 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_opnum
, tvb
, offset
, 2, hdr
.opnum
);
6779 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_dg_ihint
, tvb
, offset
, 2, hdr
.ihint
);
6783 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_dg_ahint
, tvb
, offset
, 2, hdr
.ahint
);
6787 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_dg_frag_len
, tvb
, offset
, 2, hdr
.frag_len
);
6791 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_dg_frag_num
, tvb
, offset
, 2, hdr
.frag_num
);
6792 if (hdr
.flags1
& PFCL1_FRAG
) {
6793 /* Fragmented - put the fragment number into the Info column */
6794 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " frag: %u",
6800 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_dg_auth_proto
, tvb
, offset
, 1, hdr
.auth_proto
);
6804 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_dg_serial_lo
, tvb
, offset
, 1, hdr
.serial_lo
);
6805 if (hdr
.flags1
& PFCL1_FRAG
) {
6806 /* Fragmented - put the serial number into the Info column */
6807 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " serial: %u",
6808 (hdr
.serial_hi
<< 8) | hdr
.serial_lo
);
6814 * XXX - for Kerberos, we get a protection level; if it's
6815 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
6818 dissect_dcerpc_dg_auth(tvb
, offset
, dcerpc_tree
, &hdr
,
6823 * keeping track of the conversation shouldn't really be necessary
6824 * for connectionless packets, because everything we need to know
6825 * to dissect is in the header for each packet. Unfortunately,
6826 * Microsoft's implementation is buggy and often puts the
6827 * completely wrong if_id in the header. go figure. So, keep
6828 * track of the seqnum and use that if possible. Note: that's not
6829 * completely correct. It should really be done based on both the
6830 * activity_id and seqnum. I haven't seen anywhere that it would
6831 * make a difference, but for future reference...
6833 conv
= find_or_create_conversation(pinfo
);
6836 * Packet type specific stuff is next.
6839 switch (hdr
.ptype
) {
6841 case PDU_CANCEL_ACK
:
6842 /* Body is optional */
6843 /* XXX - we assume "frag_len" is the length of the body */
6844 if (hdr
.frag_len
!= 0)
6845 dissect_dcerpc_dg_cancel_ack(tvb
, offset
, pinfo
, dcerpc_tree
, &hdr
);
6850 * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
6851 * but in at least one capture none of the Cl_cancel PDUs had a
6854 /* XXX - we assume "frag_len" is the length of the body */
6855 if (hdr
.frag_len
!= 0)
6856 dissect_dcerpc_dg_cancel(tvb
, offset
, pinfo
, dcerpc_tree
, &hdr
);
6860 /* Body is optional; if present, it's the same as PDU_FACK */
6861 /* XXX - we assume "frag_len" is the length of the body */
6862 if (hdr
.frag_len
!= 0)
6863 dissect_dcerpc_dg_fack(tvb
, offset
, pinfo
, dcerpc_tree
, &hdr
);
6867 /* Body is optional */
6868 /* XXX - we assume "frag_len" is the length of the body */
6869 if (hdr
.frag_len
!= 0)
6870 dissect_dcerpc_dg_fack(tvb
, offset
, pinfo
, dcerpc_tree
, &hdr
);
6875 dissect_dcerpc_dg_reject_fault(tvb
, offset
, pinfo
, dcerpc_tree
, &hdr
);
6879 dissect_dcerpc_dg_rqst(tvb
, offset
, pinfo
, dcerpc_tree
, tree
, &hdr
, conv
);
6883 dissect_dcerpc_dg_resp(tvb
, offset
, pinfo
, dcerpc_tree
, tree
, &hdr
, conv
);
6886 /* these requests have no body */
6889 dissect_dcerpc_dg_ping_ack(tvb
, offset
, pinfo
, dcerpc_tree
, &hdr
, conv
);
6900 dcerpc_auth_subdissector_list_free(void *p
, void *user_data _U_
)
6906 dcerpc_shutdown(void)
6908 g_slist_foreach(dcerpc_auth_subdissector_list
, dcerpc_auth_subdissector_list_free
, NULL
);
6909 g_slist_free(dcerpc_auth_subdissector_list
);
6910 g_hash_table_destroy(dcerpc_uuids
);
6911 tvb_free(tvb_trailer_signature
);
6915 proto_register_dcerpc(void)
6917 static hf_register_info hf
[] = {
6918 { &hf_dcerpc_request_in
,
6919 { "Request in frame", "dcerpc.request_in", FT_FRAMENUM
, BASE_NONE
,
6920 FRAMENUM_TYPE(FT_FRAMENUM_REQUEST
), 0, "This packet is a response to the packet with this number", HFILL
}},
6921 { &hf_dcerpc_response_in
,
6922 { "Response in frame", "dcerpc.response_in", FT_FRAMENUM
, BASE_NONE
,
6923 FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE
), 0, "This packet will be responded in the packet with this number", HFILL
}},
6924 { &hf_dcerpc_referent_id32
,
6925 { "Referent ID", "dcerpc.referent_id", FT_UINT32
, BASE_HEX
,
6926 NULL
, 0, "Referent ID for this NDR encoded pointer", HFILL
}},
6927 { &hf_dcerpc_referent_id64
,
6928 { "Referent ID", "dcerpc.referent_id64", FT_UINT64
, BASE_HEX
,
6929 NULL
, 0, "Referent ID for this NDR encoded pointer", HFILL
}},
6931 { "Version", "dcerpc.ver", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
6932 { &hf_dcerpc_ver_minor
,
6933 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
6934 { &hf_dcerpc_packet_type
,
6935 { "Packet type", "dcerpc.pkt_type", FT_UINT8
, BASE_DEC
, VALS(pckt_vals
), 0x0, NULL
, HFILL
}},
6936 { &hf_dcerpc_cn_flags
,
6937 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
6938 { &hf_dcerpc_cn_flags_first_frag
,
6939 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFC_FIRST_FRAG
, NULL
, HFILL
}},
6940 { &hf_dcerpc_cn_flags_last_frag
,
6941 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFC_LAST_FRAG
, NULL
, HFILL
}},
6942 { &hf_dcerpc_cn_flags_cancel_pending
,
6943 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFC_PENDING_CANCEL
, NULL
, HFILL
}},
6944 { &hf_dcerpc_cn_flags_reserved
,
6945 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFC_RESERVED_1
, NULL
, HFILL
}},
6946 { &hf_dcerpc_cn_flags_mpx
,
6947 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFC_CONC_MPX
, NULL
, HFILL
}},
6948 { &hf_dcerpc_cn_flags_dne
,
6949 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFC_DID_NOT_EXECUTE
, NULL
, HFILL
}},
6950 { &hf_dcerpc_cn_flags_maybe
,
6951 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFC_MAYBE
, NULL
, HFILL
}},
6952 { &hf_dcerpc_cn_flags_object
,
6953 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFC_OBJECT_UUID
, NULL
, HFILL
}},
6955 { "Data Representation", "dcerpc.drep", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
6956 { &hf_dcerpc_drep_byteorder
,
6957 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8
, BASE_DEC
, VALS(drep_byteorder_vals
), 0x0, NULL
, HFILL
}},
6958 { &hf_dcerpc_ndr_padding
,
6959 { "NDR-Padding", "dcerpc.ndr_padding", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
6960 { &hf_dcerpc_drep_character
,
6961 { "Character", "dcerpc.drep.character", FT_UINT8
, BASE_DEC
, VALS(drep_character_vals
), 0x0, NULL
, HFILL
}},
6962 { &hf_dcerpc_drep_fp
,
6963 { "Floating-point", "dcerpc.drep.fp", FT_UINT8
, BASE_DEC
, VALS(drep_fp_vals
), 0x0, NULL
, HFILL
}},
6964 { &hf_dcerpc_cn_frag_len
,
6965 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
6966 { &hf_dcerpc_cn_auth_len
,
6967 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
6968 { &hf_dcerpc_cn_call_id
,
6969 { "Call ID", "dcerpc.cn_call_id", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
6970 { &hf_dcerpc_cn_max_xmit
,
6971 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
6972 { &hf_dcerpc_cn_max_recv
,
6973 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
6974 { &hf_dcerpc_cn_assoc_group
,
6975 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
6976 { &hf_dcerpc_cn_num_ctx_items
,
6977 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
6978 { &hf_dcerpc_cn_ctx_item
,
6979 { "Ctx Item", "dcerpc.cn_ctx_item", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
6980 { &hf_dcerpc_cn_ctx_id
,
6981 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
6982 { &hf_dcerpc_cn_num_trans_items
,
6983 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
6984 { &hf_dcerpc_cn_bind_abstract_syntax
,
6985 { "Abstract Syntax", "dcerpc.cn_bind_abstract_syntax", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
6986 { &hf_dcerpc_cn_bind_if_id
,
6987 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_GUID
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
6988 { &hf_dcerpc_cn_bind_if_ver
,
6989 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
6990 { &hf_dcerpc_cn_bind_if_ver_minor
,
6991 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
6992 { &hf_dcerpc_cn_bind_trans_syntax
,
6993 { "Transfer Syntax", "dcerpc.cn_bind_trans", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
6994 { &hf_dcerpc_cn_bind_trans_id
,
6995 { "ID", "dcerpc.cn_bind_trans_id", FT_GUID
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
6996 { &hf_dcerpc_cn_bind_trans_ver
,
6997 { "ver", "dcerpc.cn_bind_trans_ver", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
6998 { &hf_dcerpc_cn_bind_trans_btfn
, /* [MS-RPCE] 2.2.2.14 */
6999 {"Bind Time Features", "dcerpc.cn_bind_trans_btfn", FT_UINT16
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}},
7000 { &hf_dcerpc_cn_bind_trans_btfn_01
,
7001 { "Security Context Multiplexing Supported", "dcerpc.cn_bind_trans_btfn.01", FT_BOOLEAN
, 16, NULL
, 0x0001, NULL
, HFILL
}},
7002 { &hf_dcerpc_cn_bind_trans_btfn_02
,
7003 { "Keep Connection On Orphan Supported", "dcerpc.cn_bind_trans_btfn.02", FT_BOOLEAN
, 16, NULL
, 0x0002, NULL
, HFILL
}},
7004 { &hf_dcerpc_cn_bind_trans_btfn_04
,
7005 { "Support SHA512 PREAUTH Verification", "dcerpc.cn_bind_trans_btfn.04", FT_BOOLEAN
, 16, NULL
, 0x0004, NULL
, HFILL
}},
7006 { &hf_dcerpc_cn_bind_trans_btfn_08
,
7007 { "Support protection of all PDUs", "dcerpc.cn_bind_trans_btfn.08", FT_BOOLEAN
, 16, NULL
, 0x0008, NULL
, HFILL
}},
7008 { &hf_dcerpc_cn_alloc_hint
,
7009 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7010 { &hf_dcerpc_cn_sec_addr_len
,
7011 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7012 { &hf_dcerpc_cn_sec_addr
,
7013 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7014 { &hf_dcerpc_cn_num_results
,
7015 { "Num results", "dcerpc.cn_num_results", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7016 { &hf_dcerpc_cn_ack_result
,
7017 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16
, BASE_DEC
, VALS(p_cont_result_vals
), 0x0, NULL
, HFILL
}},
7018 { &hf_dcerpc_cn_ack_reason
,
7019 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16
, BASE_DEC
, VALS(p_provider_reason_vals
), 0x0, NULL
, HFILL
}},
7020 { &hf_dcerpc_cn_ack_trans_id
,
7021 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_GUID
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7022 { &hf_dcerpc_cn_ack_trans_ver
,
7023 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7024 { &hf_dcerpc_cn_reject_reason
,
7025 { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16
, BASE_DEC
, VALS(reject_reason_vals
), 0x0, NULL
, HFILL
}},
7026 { &hf_dcerpc_cn_num_protocols
,
7027 { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7028 { &hf_dcerpc_cn_protocol_ver_major
,
7029 { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7030 { &hf_dcerpc_cn_protocol_ver_minor
,
7031 { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7032 { &hf_dcerpc_cn_cancel_count
,
7033 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7034 { &hf_dcerpc_cn_fault_flags
,
7035 { "Fault flags", "dcerpc.cn_fault_flags", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7036 { &hf_dcerpc_cn_fault_flags_extended_error_info
,
7037 { "Extended error information present", "dcerpc.cn_fault_flags.extended_error", FT_BOOLEAN
, 8, NULL
, 0x1, NULL
, HFILL
}},
7038 { &hf_dcerpc_cn_status
,
7039 { "Status", "dcerpc.cn_status", FT_UINT32
, BASE_HEX
, VALS(reject_status_vals
), 0x0, NULL
, HFILL
}},
7040 { &hf_dcerpc_cn_deseg_req
,
7041 { "Desegmentation Required", "dcerpc.cn_deseg_req", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7042 { &hf_dcerpc_auth_type
,
7043 { "Auth type", "dcerpc.auth_type", FT_UINT8
, BASE_DEC
, VALS(authn_protocol_vals
), 0x0, NULL
, HFILL
}},
7044 { &hf_dcerpc_auth_level
,
7045 { "Auth level", "dcerpc.auth_level", FT_UINT8
, BASE_DEC
, VALS(authn_level_vals
), 0x0, NULL
, HFILL
}},
7046 { &hf_dcerpc_auth_pad_len
,
7047 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7048 { &hf_dcerpc_auth_rsrvd
,
7049 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7050 { &hf_dcerpc_auth_ctx_id
,
7051 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7052 { &hf_dcerpc_dg_flags1
,
7053 { "Flags1", "dcerpc.dg_flags1", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7054 { &hf_dcerpc_dg_flags1_rsrvd_01
,
7055 { "Reserved for implementation", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL1_RESERVED_01
, NULL
, HFILL
}},
7056 { &hf_dcerpc_dg_flags1_last_frag
,
7057 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL1_LASTFRAG
, NULL
, HFILL
}},
7058 { &hf_dcerpc_dg_flags1_frag
,
7059 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL1_FRAG
, NULL
, HFILL
}},
7060 { &hf_dcerpc_dg_flags1_nofack
,
7061 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL1_NOFACK
, NULL
, HFILL
}},
7062 { &hf_dcerpc_dg_flags1_maybe
,
7063 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL1_MAYBE
, NULL
, HFILL
}},
7064 { &hf_dcerpc_dg_flags1_idempotent
,
7065 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL1_IDEMPOTENT
, NULL
, HFILL
}},
7066 { &hf_dcerpc_dg_flags1_broadcast
,
7067 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL1_BROADCAST
, NULL
, HFILL
}},
7068 { &hf_dcerpc_dg_flags1_rsrvd_80
,
7069 { "Reserved for implementation", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL1_RESERVED_80
, NULL
, HFILL
}},
7070 { &hf_dcerpc_dg_flags2
,
7071 { "Flags2", "dcerpc.dg_flags2", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7072 { &hf_dcerpc_dg_flags2_rsrvd_01
,
7073 { "Reserved for implementation", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL2_RESERVED_01
, NULL
, HFILL
}},
7074 { &hf_dcerpc_dg_flags2_cancel_pending
,
7075 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL2_CANCEL_PENDING
, NULL
, HFILL
}},
7076 { &hf_dcerpc_dg_flags2_rsrvd_04
,
7077 { "Reserved for future use (MBZ)", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL2_RESERVED_04
, NULL
, HFILL
}},
7078 { &hf_dcerpc_dg_flags2_rsrvd_08
,
7079 { "Reserved for future use (MBZ)", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL2_RESERVED_08
, NULL
, HFILL
}},
7080 { &hf_dcerpc_dg_flags2_rsrvd_10
,
7081 { "Reserved for future use (MBZ)", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL2_RESERVED_10
, NULL
, HFILL
}},
7082 { &hf_dcerpc_dg_flags2_rsrvd_20
,
7083 { "Reserved for future use (MBZ)", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL2_RESERVED_20
, NULL
, HFILL
}},
7084 { &hf_dcerpc_dg_flags2_rsrvd_40
,
7085 { "Reserved for future use (MBZ)", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL2_RESERVED_40
, NULL
, HFILL
}},
7086 { &hf_dcerpc_dg_flags2_rsrvd_80
,
7087 { "Reserved for future use (MBZ)", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL2_RESERVED_80
, NULL
, HFILL
}},
7088 { &hf_dcerpc_dg_serial_lo
,
7089 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7090 { &hf_dcerpc_dg_serial_hi
,
7091 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7092 { &hf_dcerpc_dg_ahint
,
7093 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7094 { &hf_dcerpc_dg_ihint
,
7095 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7096 { &hf_dcerpc_dg_frag_len
,
7097 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7098 { &hf_dcerpc_dg_frag_num
,
7099 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7100 { &hf_dcerpc_dg_auth_proto
,
7101 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8
, BASE_DEC
, VALS(authn_protocol_vals
), 0x0, NULL
, HFILL
}},
7102 { &hf_dcerpc_dg_seqnum
,
7103 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7104 { &hf_dcerpc_dg_server_boot
,
7105 { "Server boot time", "dcerpc.dg_server_boot", FT_ABSOLUTE_TIME
, ABSOLUTE_TIME_LOCAL
, NULL
, 0x0, NULL
, HFILL
}},
7106 { &hf_dcerpc_dg_if_ver
,
7107 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7108 { &hf_dcerpc_krb5_av_prot_level
,
7109 { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8
, BASE_DEC
, VALS(authn_level_vals
), 0x0, NULL
, HFILL
}},
7110 { &hf_dcerpc_krb5_av_key_vers_num
,
7111 { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7112 { &hf_dcerpc_krb5_av_key_auth_verifier
,
7113 { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7114 { &hf_dcerpc_obj_id
,
7115 { "Object", "dcerpc.obj_id", FT_GUID
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7116 { &hf_dcerpc_dg_if_id
,
7117 { "Interface", "dcerpc.dg_if_id", FT_GUID
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7118 { &hf_dcerpc_dg_act_id
,
7119 { "Activity", "dcerpc.dg_act_id", FT_GUID
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7121 { "Opnum", "dcerpc.opnum", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7123 { &hf_dcerpc_dg_cancel_vers
,
7124 { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7126 { &hf_dcerpc_dg_cancel_id
,
7127 { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7129 { &hf_dcerpc_dg_server_accepting_cancels
,
7130 { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7132 { &hf_dcerpc_dg_fack_vers
,
7133 { "FACK Version", "dcerpc.fack_vers", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7135 { &hf_dcerpc_dg_fack_window_size
,
7136 { "Window Size", "dcerpc.fack_window_size", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7138 { &hf_dcerpc_dg_fack_max_tsdu
,
7139 { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7141 { &hf_dcerpc_dg_fack_max_frag_size
,
7142 { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7144 { &hf_dcerpc_dg_fack_serial_num
,
7145 { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7147 { &hf_dcerpc_dg_fack_selack_len
,
7148 { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7150 { &hf_dcerpc_dg_fack_selack
,
7151 { "Selective ACK", "dcerpc.fack_selack", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7153 { &hf_dcerpc_dg_status
,
7154 { "Status", "dcerpc.dg_status", FT_UINT32
, BASE_HEX
, VALS(reject_status_vals
), 0x0, NULL
, HFILL
}},
7156 { &hf_dcerpc_array_max_count
,
7157 { "Max Count", "dcerpc.array.max_count", FT_UINT32
, BASE_DEC
, NULL
, 0x0, "Maximum Count: Number of elements in the array", HFILL
}},
7159 { &hf_dcerpc_array_offset
,
7160 { "Offset", "dcerpc.array.offset", FT_UINT32
, BASE_DEC
, NULL
, 0x0, "Offset for first element in array", HFILL
}},
7162 { &hf_dcerpc_array_actual_count
,
7163 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32
, BASE_DEC
, NULL
, 0x0, "Actual Count: Actual number of elements in the array", HFILL
}},
7166 { "Operation", "dcerpc.op", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7168 { &hf_dcerpc_null_pointer
,
7169 { "NULL Pointer", "dcerpc.null_pointer", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7171 { &hf_dcerpc_fragments
,
7172 { "Reassembled DCE/RPC Fragments", "dcerpc.fragments", FT_NONE
, BASE_NONE
,
7173 NULL
, 0x0, NULL
, HFILL
}},
7175 { &hf_dcerpc_fragment
,
7176 { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM
, BASE_NONE
,
7177 NULL
, 0x0, NULL
, HFILL
}},
7179 { &hf_dcerpc_fragment_overlap
,
7180 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN
, BASE_NONE
,
7181 NULL
, 0x0, "Fragment overlaps with other fragments", HFILL
}},
7183 { &hf_dcerpc_fragment_overlap_conflict
,
7184 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN
, BASE_NONE
,
7185 NULL
, 0x0, "Overlapping fragments contained conflicting data", HFILL
}},
7187 { &hf_dcerpc_fragment_multiple_tails
,
7188 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN
, BASE_NONE
,
7189 NULL
, 0x0, "Several tails were found when defragmenting the packet", HFILL
}},
7191 { &hf_dcerpc_fragment_too_long_fragment
,
7192 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN
, BASE_NONE
,
7193 NULL
, 0x0, "Fragment contained data past end of packet", HFILL
}},
7195 { &hf_dcerpc_fragment_error
,
7196 { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM
, BASE_NONE
,
7197 NULL
, 0x0, "Defragmentation error due to illegal fragments", HFILL
}},
7199 { &hf_dcerpc_fragment_count
,
7200 { "Fragment count", "dcerpc.fragment.count", FT_UINT32
, BASE_DEC
,
7201 NULL
, 0x0, NULL
, HFILL
}},
7204 { "Time from request", "dcerpc.time", FT_RELATIVE_TIME
, BASE_NONE
,
7205 NULL
, 0, "Time between Request and Response for DCE-RPC calls", HFILL
}},
7207 { &hf_dcerpc_reassembled_in
,
7208 { "Reassembled PDU in frame", "dcerpc.reassembled_in", FT_FRAMENUM
, BASE_NONE
,
7209 NULL
, 0x0, "The DCE/RPC PDU is completely reassembled in the packet with this number", HFILL
}},
7211 { &hf_dcerpc_reassembled_length
,
7212 { "Reassembled DCE/RPC length", "dcerpc.reassembled.length", FT_UINT32
, BASE_DEC
,
7213 NULL
, 0x0, "The total length of the reassembled payload", HFILL
}},
7215 { &hf_dcerpc_unknown_if_id
,
7216 { "Unknown DCERPC interface id", "dcerpc.unknown_if_id", FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7218 { &hf_dcerpc_cn_rts_flags
,
7219 { "RTS Flags", "dcerpc.cn_rts_flags", FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7220 { &hf_dcerpc_cn_rts_flags_ping
,
7221 { "Ping", "dcerpc.cn_rts.flags.ping", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), RTS_FLAG_PING
, NULL
, HFILL
}},
7222 { &hf_dcerpc_cn_rts_flags_other_cmd
,
7223 { "Other Cmd", "dcerpc.cn_rts_flags.other_cmd", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), RTS_FLAG_OTHER_CMD
, NULL
, HFILL
}},
7224 { &hf_dcerpc_cn_rts_flags_recycle_channel
,
7225 { "Recycle Channel", "dcerpc.cn_rts_flags.recycle_channel", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), RTS_FLAG_RECYCLE_CHANNEL
, NULL
, HFILL
}},
7226 { &hf_dcerpc_cn_rts_flags_in_channel
,
7227 { "In Channel", "dcerpc.cn_rts_flags.in_channel", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), RTS_FLAG_IN_CHANNEL
, NULL
, HFILL
}},
7228 { &hf_dcerpc_cn_rts_flags_out_channel
,
7229 { "Out Channel", "dcerpc.cn_rts_flags.out_channel", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), RTS_FLAG_OUT_CHANNEL
, NULL
, HFILL
}},
7230 { &hf_dcerpc_cn_rts_flags_eof
,
7231 { "EOF", "dcerpc.cn_rts_flags.eof", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), RTS_FLAG_EOF
, NULL
, HFILL
}},
7232 { &hf_dcerpc_cn_rts_commands_nb
,
7233 { "RTS Number of Commands", "dcerpc.cn_rts_commands_nb", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7234 { &hf_dcerpc_cn_rts_command
,
7235 { "RTS Command", "dcerpc.cn_rts_command", FT_UINT32
, BASE_HEX
, VALS(rts_command_vals
), 0x0, NULL
, HFILL
}},
7236 { &hf_dcerpc_cn_rts_command_receivewindowsize
,
7237 {"Receive Window Size", "dcerpc.cn_rts_command.receivewindowsize", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7238 { &hf_dcerpc_cn_rts_command_fack_bytesreceived
,
7239 {"Bytes Received", "dcerpc.cn_rts_command.fack.bytesreceived", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7240 { &hf_dcerpc_cn_rts_command_fack_availablewindow
,
7241 {"Available Window", "dcerpc.cn_rts_command.fack.availablewindow", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7242 { &hf_dcerpc_cn_rts_command_fack_channelcookie
,
7243 {"Channel Cookie", "dcerpc.cn_rts_command.fack.channelcookie", FT_GUID
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7244 { &hf_dcerpc_cn_rts_command_connectiontimeout
,
7245 {"Connection Timeout", "dcerpc.cn_rts_command.connectiontimeout", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7246 { &hf_dcerpc_cn_rts_command_cookie
,
7247 {"Cookie", "dcerpc.cn_rts_command.cookie", FT_GUID
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7248 { &hf_dcerpc_cn_rts_command_channellifetime
,
7249 {"Channel Lifetime", "dcerpc.cn_rts_command.channellifetime", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
7250 { &hf_dcerpc_cn_rts_command_clientkeepalive
,
7251 {"Client Keepalive", "dcerpc.cn_rts_command.clientkeepalive", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7252 { &hf_dcerpc_cn_rts_command_version
,
7253 {"Version", "dcerpc.cn_rts_command.version", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7254 { &hf_dcerpc_cn_rts_command_conformancecount
,
7255 {"Conformance Count", "dcerpc.cn_rts_command.padding.conformancecount", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7256 { &hf_dcerpc_cn_rts_command_padding
,
7257 { "Padding", "dcerpc.cn_rts_command.padding.padding", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7258 { &hf_dcerpc_cn_rts_command_addrtype
,
7259 { "Address Type", "dcerpc.cn_rts_command.addrtype", FT_UINT32
, BASE_DEC
, VALS(rts_addresstype_vals
), 0x0, NULL
, HFILL
}},
7260 { &hf_dcerpc_cn_rts_command_associationgroupid
,
7261 {"Association Group ID", "dcerpc.cn_rts_command.associationgroupid", FT_GUID
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7262 { &hf_dcerpc_cn_rts_command_forwarddestination
,
7263 {"Forward Destination", "dcerpc.cn_rts_command.forwarddestination", FT_UINT32
, BASE_DEC
, VALS(rts_forward_destination_vals
), 0x0, NULL
, HFILL
}},
7264 { &hf_dcerpc_cn_rts_command_pingtrafficsentnotify
,
7265 {"Ping Traffic Sent Notify", "dcerpc.cn_rts_command.pingtrafficsentnotify", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
7266 { &hf_dcerpc_sec_vt_signature
,
7267 {"SEC_VT_SIGNATURE", "dcerpc.rpc_sec_vt.signature", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7268 { &hf_dcerpc_sec_vt_command_end
,
7269 {"SEC_VT_COMMAND_END", "dcerpc.rpc_sec_vt.command.end", FT_BOOLEAN
, 16, NULL
, 0x4000, NULL
, HFILL
}},
7270 { &hf_dcerpc_sec_vt_command_must
,
7271 {"SEC_VT_MUST_PROCESS_COMMAND", "dcerpc.rpc_sec_vt.command.must_process", FT_BOOLEAN
, 16, NULL
, 0x8000, NULL
, HFILL
}},
7272 { &hf_dcerpc_sec_vt_command_cmd
,
7273 {"Cmd", "dcerpc.rpc_sec_vt.command.cmd", FT_UINT16
, BASE_HEX
, VALS(sec_vt_command_cmd_vals
), 0x3fff, NULL
, HFILL
}},
7274 { &hf_dcerpc_sec_vt_command
,
7275 {"Command", "dcerpc.rpc_sec_vt.command", FT_UINT16
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}},
7276 { &hf_dcerpc_sec_vt_command_length
,
7277 {"Length", "dcerpc.rpc_sec_vt.command.length", FT_UINT16
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}},
7278 { &hf_dcerpc_sec_vt_bitmask
,
7279 {"rpc_sec_vt_bitmask", "dcerpc.rpc_sec_vt.bitmask", FT_UINT32
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}},
7280 { &hf_dcerpc_sec_vt_bitmask_sign
,
7281 {"CLIENT_SUPPORT_HEADER_SIGNING", "dcerpc.rpc_sec_vt.bitmask.sign", FT_BOOLEAN
, 32, NULL
, 0x1, NULL
, HFILL
}},
7282 { &hf_dcerpc_sec_vt_pcontext_uuid
,
7283 {"UUID", "dcerpc.rpc_sec_vt.pcontext.interface.uuid", FT_GUID
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}},
7284 { &hf_dcerpc_sec_vt_pcontext_ver
,
7285 {"Version", "dcerpc.rpc_sec_vt.pcontext.interface.ver", FT_UINT32
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}},
7286 { &hf_dcerpc_sec_vt_preauth_salt
,
7287 {"Salt", "dcerpc.rpc_sec_vt.preauth.salt", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7288 { &hf_dcerpc_sec_vt_preauth_sha512
,
7289 {"SHA512 Hash", "dcerpc.rpc_sec_vt.preauth.sha512", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7290 { &hf_dcerpc_reserved
,
7291 {"Reserved", "dcerpc.reserved", FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}},
7292 { &hf_dcerpc_unknown
,
7293 {"Unknown", "dcerpc.unknown", FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}},
7294 { &hf_dcerpc_missalign
,
7295 {"missalign", "dcerpc.missalign", FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}},
7296 /* Generated from convert_proto_tree_add_text.pl */
7297 { &hf_dcerpc_duplicate_ptr
, { "duplicate PTR", "dcerpc.duplicate_ptr", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7298 { &hf_dcerpc_encrypted_stub_data
, { "Encrypted stub data", "dcerpc.encrypted_stub_data", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7299 { &hf_dcerpc_decrypted_stub_data
, { "Decrypted stub data", "dcerpc.decrypted_stub_data", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7300 { &hf_dcerpc_payload_stub_data
, { "Payload stub data", "dcerpc.payload_stub_data", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7301 { &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
}},
7302 { &hf_dcerpc_stub_data
, { "Stub data", "dcerpc.stub_data", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7303 { &hf_dcerpc_auth_padding
, { "Auth Padding", "dcerpc.auth_padding", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7304 { &hf_dcerpc_auth_info
, { "Auth Info", "dcerpc.auth_info", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7305 { &hf_dcerpc_auth_credentials
, { "Auth Credentials", "dcerpc.auth_credentials", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7306 { &hf_dcerpc_fault_stub_data
, { "Fault stub data", "dcerpc.fault_stub_data", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7307 { &hf_dcerpc_fragment_data
, { "Fragment data", "dcerpc.fragment_data", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7308 { &hf_dcerpc_cmd_client_ipv4
, { "RTS Client address", "dcerpc.cmd_client_ipv4", FT_IPv4
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7309 { &hf_dcerpc_cmd_client_ipv6
, { "RTS Client address", "dcerpc.cmd_client_ipv6", FT_IPv6
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7310 { &hf_dcerpc_authentication_verifier
, { "Authentication verifier", "dcerpc.authentication_verifier", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
7312 static int *ett
[] = {
7314 &ett_dcerpc_cn_flags
,
7316 &ett_dcerpc_cn_iface
,
7317 &ett_dcerpc_cn_trans_syntax
,
7318 &ett_dcerpc_cn_trans_btfn
,
7319 &ett_dcerpc_cn_bind_trans_btfn
,
7320 &ett_dcerpc_cn_rts_flags
,
7321 &ett_dcerpc_cn_rts_command
,
7322 &ett_dcerpc_cn_rts_pdu
,
7324 &ett_dcerpc_dg_flags1
,
7325 &ett_dcerpc_dg_flags2
,
7326 &ett_dcerpc_pointer_data
,
7328 &ett_dcerpc_fragments
,
7329 &ett_dcerpc_fragment
,
7330 &ett_dcerpc_krb5_auth_verf
,
7331 &ett_dcerpc_auth_info
,
7332 &ett_dcerpc_verification_trailer
,
7333 &ett_dcerpc_sec_vt_command
,
7334 &ett_dcerpc_sec_vt_bitmask
,
7335 &ett_dcerpc_sec_vt_pcontext
,
7336 &ett_dcerpc_sec_vt_header
,
7337 &ett_dcerpc_sec_vt_preauth
,
7338 &ett_dcerpc_complete_stub_data
,
7339 &ett_dcerpc_fault_flags
,
7340 &ett_dcerpc_fault_stub_data
,
7343 static ei_register_info ei
[] = {
7344 { &ei_dcerpc_fragment
, { "dcerpc.fragment.reassemble", PI_REASSEMBLE
, PI_CHAT
, "Fragment", EXPFILL
}},
7345 { &ei_dcerpc_fragment_reassembled
, { "dcerpc.fragment_reassembled", PI_REASSEMBLE
, PI_CHAT
, "Fragment, reassembled", EXPFILL
}},
7346 { &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
}},
7347 { &ei_dcerpc_no_request_found
, { "dcerpc.no_request_found", PI_SEQUENCE
, PI_NOTE
, "No request to this DCE/RPC call found", EXPFILL
}},
7348 { &ei_dcerpc_cn_status
, { "dcerpc.cn_status.expert", PI_RESPONSE_CODE
, PI_NOTE
, "Fault", EXPFILL
}},
7349 { &ei_dcerpc_fragment_multiple
, { "dcerpc.fragment_multiple", PI_SEQUENCE
, PI_CHAT
, "Multiple DCE/RPC fragments/PDU's in one packet", EXPFILL
}},
7350 #if 0 /* XXX - too much "output noise", removed for now */
7351 { &ei_dcerpc_context_change
, { "dcerpc.context_change", PI_SEQUENCE
, PI_CHAT
, "Context change", EXPFILL
}},
7353 { &ei_dcerpc_bind_not_acknowledged
, { "dcerpc.bind_not_acknowledged", PI_SEQUENCE
, PI_WARN
, "Bind not acknowledged", EXPFILL
}},
7354 { &ei_dcerpc_verifier_unavailable
, { "dcerpc.verifier_unavailable", PI_UNDECODED
, PI_WARN
, "Verifier unavailable", EXPFILL
}},
7355 { &ei_dcerpc_invalid_pdu_authentication_attempt
, { "dcerpc.invalid_pdu_authentication_attempt", PI_UNDECODED
, PI_WARN
, "Invalid authentication attempt", EXPFILL
}},
7356 /* Generated from convert_proto_tree_add_text.pl */
7357 { &ei_dcerpc_long_frame
, { "dcerpc.long_frame", PI_PROTOCOL
, PI_WARN
, "Long frame", EXPFILL
}},
7358 { &ei_dcerpc_cn_rts_command
, { "dcerpc.cn_rts_command.unknown", PI_PROTOCOL
, PI_WARN
, "unknown RTS command number", EXPFILL
}},
7359 { &ei_dcerpc_not_implemented
, { "dcerpc.not_implemented", PI_UNDECODED
, PI_WARN
, "dissection not implemented", EXPFILL
}},
7362 /* Decode As handling */
7363 static build_valid_func dcerpc_da_build_value
[1] = {dcerpc_value
};
7364 static decode_as_value_t dcerpc_da_values
= {dcerpc_prompt
, 1, dcerpc_da_build_value
};
7365 static decode_as_t dcerpc_da
= {"dcerpc", "dcerpc.uuid",
7366 1, 0, &dcerpc_da_values
, NULL
, NULL
,
7367 dcerpc_populate_list
, decode_dcerpc_binding_reset
, dcerpc_decode_as_change
, dcerpc_decode_as_free
};
7369 module_t
*dcerpc_module
;
7370 expert_module_t
* expert_dcerpc
;
7372 proto_dcerpc
= proto_register_protocol("Distributed Computing Environment / Remote Procedure Call (DCE/RPC)", "DCERPC", "dcerpc");
7373 proto_register_field_array(proto_dcerpc
, hf
, array_length(hf
));
7374 proto_register_subtree_array(ett
, array_length(ett
));
7375 expert_dcerpc
= expert_register_protocol(proto_dcerpc
);
7376 expert_register_field_array(expert_dcerpc
, ei
, array_length(ei
));
7378 uuid_dissector_table
= register_dissector_table(DCERPC_TABLE_NAME
, "DCE/RPC UUIDs", proto_dcerpc
, FT_GUID
, BASE_HEX
);
7381 * structures and data for
7383 * - per presentation context (bind)
7384 * - per authentication context
7386 dcerpc_connections
= wmem_map_new_autoreset(wmem_epan_scope(),
7388 dcerpc_connection_hash
,
7389 dcerpc_connection_equal
);
7391 dcerpc_binds
= wmem_map_new_autoreset(wmem_epan_scope(),
7396 dcerpc_auths
= wmem_map_new_autoreset(wmem_epan_scope(),
7398 dcerpc_auth_context_hash
,
7399 dcerpc_auth_context_equal
);
7401 /* structures and data for CALL */
7402 dcerpc_cn_calls
= wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), dcerpc_cn_call_hash
, dcerpc_cn_call_equal
);
7403 dcerpc_dg_calls
= wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), dcerpc_dg_call_hash
, dcerpc_dg_call_equal
);
7405 /* structure and data for MATCHED */
7406 dcerpc_matched
= wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), dcerpc_matched_hash
, dcerpc_matched_equal
);
7408 register_init_routine(decode_dcerpc_inject_bindings
);
7410 dcerpc_module
= prefs_register_protocol(proto_dcerpc
, NULL
);
7411 prefs_register_bool_preference(dcerpc_module
,
7413 "Reassemble DCE/RPC messages spanning multiple TCP segments",
7414 "Whether the DCE/RPC dissector should reassemble messages"
7415 " spanning multiple TCP segments."
7416 " To use this option, you must also enable"
7417 " \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
7418 &dcerpc_cn_desegment
);
7419 prefs_register_bool_preference(dcerpc_module
,
7420 "reassemble_dcerpc",
7421 "Reassemble DCE/RPC fragments",
7422 "Whether the DCE/RPC dissector should reassemble fragmented DCE/RPC PDUs",
7423 &dcerpc_reassemble
);
7426 * XXX - addresses_ports_reassembly_table_functions?
7427 * Or can a single connection-oriented DCE RPC session persist
7428 * over multiple transport layer connections?
7430 reassembly_table_register(&dcerpc_co_reassembly_table
,
7431 &addresses_reassembly_table_functions
);
7432 reassembly_table_register(&dcerpc_cl_reassembly_table
,
7433 &dcerpc_cl_reassembly_table_functions
);
7435 dcerpc_uuids
= g_hash_table_new_full(dcerpc_uuid_hash
, dcerpc_uuid_equal
, g_free
, g_free
);
7436 dcerpc_tap
= register_tap("dcerpc");
7438 register_decode_as(&dcerpc_da
);
7440 register_srt_table(proto_dcerpc
, NULL
, 1, dcerpcstat_packet
, dcerpcstat_init
, dcerpcstat_param
);
7442 tvb_trailer_signature
= tvb_new_real_data(TRAILER_SIGNATURE
,
7443 sizeof(TRAILER_SIGNATURE
),
7444 sizeof(TRAILER_SIGNATURE
));
7446 dcerpc_tcp_handle
= register_dissector("dcerpc.tcp", dissect_dcerpc_tcp
, proto_dcerpc
);
7448 register_shutdown_routine(dcerpc_shutdown
);
7452 proto_reg_handoff_dcerpc(void)
7454 heur_dissector_add("tcp", dissect_dcerpc_tcp_heur
, "DCE/RPC over TCP", "dcerpc_tcp", proto_dcerpc
, HEURISTIC_ENABLE
);
7455 heur_dissector_add("netbios", dissect_dcerpc_cn_pk
, "DCE/RPC over NetBios", "dcerpc_netbios", proto_dcerpc
, HEURISTIC_ENABLE
);
7456 heur_dissector_add("udp", dissect_dcerpc_dg
, "DCE/RPC over UDP", "dcerpc_udp", proto_dcerpc
, HEURISTIC_ENABLE
);
7457 heur_dissector_add("smb_transact", dissect_dcerpc_cn_smbpipe
, "DCE/RPC over SMB", "dcerpc_smb_transact", proto_dcerpc
, HEURISTIC_ENABLE
);
7458 heur_dissector_add("smb2_pipe_subdissectors", dissect_dcerpc_cn_smb2
, "DCE/RPC over SMB2", "dcerpc_smb2", proto_dcerpc
, HEURISTIC_ENABLE
);
7459 heur_dissector_add("http", dissect_dcerpc_cn_bs
, "DCE/RPC over HTTP", "dcerpc_http", proto_dcerpc
, HEURISTIC_ENABLE
);
7460 dcerpc_smb_init(proto_dcerpc
);
7462 dissector_add_for_decode_as("tcp.port", dcerpc_tcp_handle
);
7464 guids_add_uuid(&uuid_data_repr_proto
, "32bit NDR");
7465 guids_add_uuid(&uuid_ndr64
, "64bit NDR");
7466 guids_add_uuid(&uuid_asyncemsmdb
, "async MAPI");
7470 * Editor modelines - https://www.wireshark.org/tools/modelines.html
7475 * indent-tabs-mode: nil
7478 * vi: set shiftwidth=4 tabstop=8 expandtab:
7479 * :indentSize=4:tabSize=8:noTabs=true: