Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-dcerpc.c
blob3dcb8976a7e91a2992b6ae2066c8fa49f094dcf9
1 /* packet-dcerpc.c
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
27 #include "config.h"
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>
35 #include <epan/tap.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>
42 #include <epan/tfs.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"},
70 { PDU_PING, "Ping"},
71 { PDU_RESP, "Response"},
72 { PDU_FAULT, "Fault"},
73 { PDU_WORKING, "Working"},
74 { PDU_NOCALL, "Nocall"},
75 { PDU_REJECT, "Reject"},
76 { PDU_ACK, "Ack"},
77 { PDU_CL_CANCEL, "Cl_cancel"},
78 { PDU_FACK, "Fack"},
79 { PDU_CANCEL_ACK, "Cancel_ack"},
80 { PDU_BIND, "Bind"},
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"},
90 { 0, NULL }
93 static const value_string drep_byteorder_vals[] = {
94 { 0, "Big-endian" },
95 { 1, "Little-endian" },
96 { 0, NULL }
99 static const value_string drep_character_vals[] = {
100 { 0, "ASCII" },
101 { 1, "EBCDIC" },
102 { 0, NULL }
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" },
115 { 0, NULL }
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"},
134 { 0, NULL }
138 * Protection levels.
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" },
147 { 0, NULL }
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
156 * transmission */
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'
163 * request */
164 #define PFCL1_IDEMPOTENT 0x20 /* If set, the PDU is for an idempotent
165 * request */
166 #define PFCL1_BROADCAST 0x40 /* If set, the PDU is for a broadcast
167 * request */
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
194 * execute. */
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
200 * is omitted. */
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[] = {
214 { 0, "Acceptance" },
215 { 1, "User rejection" },
216 { 2, "Provider rejection" },
217 { 3, "Negotiate ACK" }, /* [MS-RPCE] 2.2.2.4 */
218 { 0, NULL }
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" },
229 { 0, NULL }
233 * Reject reasons.
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" },
257 { 0, NULL }
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" },
346 { 0, NULL }
351 * RTS Flags
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
363 * RTS Commands
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" },
398 { 0x0, NULL }
402 * RTS client address type
404 #define RTS_IPV4 0
405 #define RTS_IPV6 1
407 static const value_string rts_addresstype_vals[] = {
408 { RTS_IPV4, "IPV4" },
409 { RTS_IPV6, "IPV6" },
410 { 0x0, NULL }
414 * RTS Forward destination
417 static const value_string rts_forward_destination_vals[] = {
418 { 0x0, "FDClient" },
419 { 0x1, "FDInProxy" },
420 { 0x2, "FDServer" },
421 { 0x3, "FDOutProxy" },
422 { 0x0, NULL }
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;
435 /* field defines */
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,
605 NULL
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,
632 NULL
635 static int * const sec_vt_bitmask_fields[] = {
636 &hf_dcerpc_sec_vt_bitmask_sign,
637 NULL
640 static int * const dcerpc_cn_fault_flags_fields[] = {
641 &hf_dcerpc_cn_fault_flags_extended_error_info,
642 NULL
645 static const value_string sec_vt_command_cmd_vals[] = {
646 {1, "BITMASK_1"},
647 {2, "PCONTEXT"},
648 {3, "HEADER2"},
649 {4, "PREAUTH"},
650 {0, NULL}
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;
709 } dcerpc_connection;
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
716 * value is 0.
718 static wmem_map_t *dcerpc_binds;
720 typedef struct _dcerpc_bind_key {
721 conversation_t *conv;
722 uint16_t ctx_id;
723 uint64_t transport_salt;
724 } dcerpc_bind_key;
726 typedef struct _dcerpc_bind_value {
727 e_guid_t uuid;
728 uint16_t ver;
729 e_guid_t transport;
730 } 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;
737 uint8_t auth_type;
738 uint8_t auth_level;
739 uint32_t auth_context_id;
740 uint32_t first_frame;
741 bool hdr_signing;
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);
757 if (data == NULL)
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);
764 return data;
768 * Registers a conversation/UUID binding association, so that
769 * we can invoke the proper sub-dissector for a given DCERPC
770 * conversation.
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(
785 &binding->addr_a,
786 &binding->addr_b,
787 conversation_pt_to_conversation_type(binding->ptype),
788 binding->port_a,
789 binding->port_b,
792 if (!conv) {
793 conv = conversation_new(
795 &binding->addr_a,
796 &binding->addr_b,
797 conversation_pt_to_conversation_type(binding->ptype),
798 binding->port_a,
799 binding->port_b,
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);
813 key->conv = conv;
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);
820 return bind_value;
824 /* inject one of our bindings into the dcerpc binding table */
825 static void
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 */
832 static void
833 decode_dcerpc_inject_bindings(void) {
834 g_slist_foreach(decode_dcerpc_bindings, decode_dcerpc_inject_binding, NULL /* user_data */);
837 /* free a binding */
838 static void
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);
845 if (binding->ifname)
846 g_string_free(binding->ifname, true);
847 g_free(binding);
850 static void
851 dcerpc_decode_as_free(void *value)
853 decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t *)value;
854 if (binding != NULL)
855 decode_dcerpc_binding_free(binding);
858 /* removes all bindings */
859 void
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);
875 void
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);
881 static void
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) {
889 case(PT_TCP):
890 g_string_append(address_str, "Address: ToBeDone TCP port");
891 break;
892 case(PT_UDP):
893 g_string_append(address_str, "Address: ToBeDone UDP port");
894 break;
895 default:
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);
912 static void *
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);
918 /* clone binding */
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;*/
929 binding->ver = 0;
931 return binding;
934 struct dcerpc_decode_as_populate
936 decode_as_add_to_list_func add_to_list;
937 void *ui_element;
940 static void
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);
952 static void
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) */
964 static int
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! */
972 if (
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)
981 /* equal */
982 return 0;
985 /* unequal */
986 return 1;
989 /* remove a binding (looking the same way as the given one) */
990 static bool
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;
994 GSList *le;
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,
999 binding,
1000 decode_dcerpc_binding_cmp);
1001 if (le == NULL)
1002 return false;
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);
1012 return false;
1015 static bool
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
1027 * to the list.
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);
1039 return false;
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,
1054 NULL,
1055 &hf_dcerpc_reassembled_length,
1056 /* Reassembled data field */
1057 NULL,
1058 "fragments"
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:
1068 too bad
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 {
1078 address src;
1079 address dst;
1080 uint32_t id;
1081 e_guid_t act_id;
1082 } dcerpc_fragment_key;
1084 static unsigned
1085 dcerpc_fragment_hash(const void *k)
1087 const dcerpc_fragment_key* key = (const dcerpc_fragment_key*) k;
1088 unsigned hash_val;
1090 hash_val = 0;
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;
1097 return hash_val;
1100 static int
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))
1114 ? true : false);
1117 /* allocate a persistent dcerpc fragment key to insert in the hash */
1118 static void *
1119 dcerpc_fragment_temporary_key(const packet_info *pinfo, const uint32_t id,
1120 const void *data)
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);
1127 key->id = id;
1128 key->act_id = hdr->act_id;
1130 return key;
1133 /* allocate a persistent dcerpc fragment key to insert in the hash */
1134 static void *
1135 dcerpc_fragment_persistent_key(const packet_info *pinfo, const uint32_t id,
1136 const void *data)
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);
1143 key->id = id;
1144 key->act_id = hdr->act_id;
1146 return key;
1149 static void
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);
1157 static void
1158 dcerpc_fragment_free_persistent_key(void *ptr)
1160 dcerpc_fragment_key *key = (dcerpc_fragment_key *)ptr;
1162 if (key) {
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 {
1188 uint8_t auth_level;
1189 uint8_t auth_type;
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)
1198 void *data;
1199 int i;
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;
1209 return NULL;
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))
1218 return;
1220 d = g_new(dcerpc_auth_subdissector, 1);
1222 d->auth_level = auth_level;
1223 d->auth_type = auth_type;
1224 d->auth_fns = *fns;
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) {
1243 return;
1246 if (auth_info->auth_fns == NULL) {
1247 return;
1249 di.ptype = hdr->ptype;
1250 di.auth_info = auth_info;
1252 switch (hdr->ptype) {
1253 case PDU_BIND:
1254 case PDU_ALTER:
1255 fn = auth_info->auth_fns->bind_fn;
1256 break;
1257 case PDU_BIND_ACK:
1258 case PDU_ALTER_ACK:
1259 fn = auth_info->auth_fns->bind_ack_fn;
1260 break;
1261 case PDU_AUTH3:
1262 fn = auth_info->auth_fns->auth3_fn;
1263 break;
1264 case PDU_REQ:
1265 case PDU_CO_CANCEL:
1266 case PDU_ORPHANED:
1267 fn = auth_info->auth_fns->req_verf_fn;
1268 break;
1269 case PDU_RESP:
1270 case PDU_FAULT:
1271 fn = auth_info->auth_fns->resp_verf_fn;
1272 break;
1274 default:
1275 /* Don't know how to handle authentication data in this
1276 pdu type. */
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)"));
1282 return;
1285 if (fn)
1286 fn(auth_info->auth_tvb, 0, pinfo, auth_info->auth_tree, &di, hdr->drep);
1287 else
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,
1294 "Unknown (%u)"));
1297 static proto_item*
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)"));
1314 return ti;
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,
1322 packet_info *pinfo,
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)
1329 return NULL;
1331 if (auth_info->auth_fns == NULL)
1332 return NULL;
1334 switch (hdr->ptype) {
1335 case PDU_REQ:
1336 fn = auth_info->auth_fns->req_data_fn;
1337 break;
1338 case PDU_RESP:
1339 case PDU_FAULT:
1340 fn = auth_info->auth_fns->resp_data_fn;
1341 break;
1344 if (fn)
1345 return fn(header_tvb, payload_tvb, trailer_tvb, auth_info->auth_tvb, pinfo, auth_info);
1347 return NULL;
1350 typedef struct _dcerpc_dissector_data
1352 dcerpc_uuid_value *sub_proto;
1353 dcerpc_info *info;
1354 bool decrypted;
1355 dcerpc_auth_info *auth_info;
1356 uint8_t *drep;
1357 proto_tree *dcerpc_tree;
1358 } dcerpc_dissector_data_t;
1361 * Subdissectors
1364 static dissector_table_t uuid_dissector_table;
1366 /* the registered subdissectors */
1367 GHashTable *dcerpc_uuids;
1369 static int
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));
1378 static unsigned
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
1383 unique. */
1384 return key->guid.data1;
1388 static int
1389 dissect_verification_trailer(packet_info *pinfo, tvbuff_t *tvb, int stub_offset,
1390 proto_tree *parent_tree, int *signature_offset);
1392 static void
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;
1413 auth_pad_len = 0;
1415 auth_pad_offset = offset + plain_length;
1417 if ((auth_info != NULL) &&
1418 (auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)) {
1419 if (is_encrypted) {
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 */
1422 auth_pad_len = 0;
1423 } else {
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);
1427 } else {
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);
1438 static int
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) {
1458 name = proc->name;
1459 break;
1463 col_set_str(pinfo->cinfo, COL_PROTOCOL, dissector_data->sub_proto->name);
1465 if (!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");
1469 else
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,
1478 0, -1, ENC_NA);
1479 sub_tree = proto_item_add_subtree(sub_item, dissector_data->sub_proto->ett);
1480 if (!name)
1481 proto_item_append_text(sub_item, ", unknown operation %u",
1482 dissector_data->info->call_data->opnum);
1483 else
1484 proto_item_append_text(sub_item, ", %s", name);
1486 if (tree) {
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);
1497 else
1498 proto_tree_add_uint_format_value(sub_tree, hf_dcerpc_op, tvb,
1499 0, 0, dissector_data->info->call_data->opnum,
1500 "%s (%u)",
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);
1514 } /* tree */
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;
1558 } else {
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.
1565 stub_tvb = NULL;
1566 auth_pad_len = reported_length;
1567 auth_pad_offset = 0;
1568 length = 0;
1570 } else {
1572 * No authentication padding.
1574 stub_tvb = tvb;
1575 auth_pad_len = 0;
1576 auth_pad_offset = 0;
1579 if (sub_item) {
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
1587 * padding, if any.
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.
1593 TRY {
1594 proto_tree *stub_tree = NULL;
1595 int remaining;
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,
1605 stub_tvb, 0,
1606 stub_tree,
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;
1614 if (sub_item) {
1615 proto_item_set_len(sub_item, length);
1617 } else {
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)]",
1642 remaining,
1643 plurality(remaining, "", "s"));
1644 remaining = 0;
1645 } else {
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)]",
1654 remaining,
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
1663 * or info columns.
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);
1669 } ENDTRY;
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);
1684 static void
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");
1706 void
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;
1715 key->guid = *uuid;
1716 key->ver = ver;
1718 value->proto = find_protocol_by_id(proto);
1719 value->proto_id = proto;
1720 value->ett = ett;
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);
1734 void
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));
1741 key->guid = *uuid;
1742 key->ver = ver;
1744 value->proto = find_protocol_by_id(proto);
1745 value->proto_id = proto;
1746 value->ett = -1;
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.
1761 const char *
1762 dcerpc_get_proto_name(e_guid_t *uuid, uint16_t ver)
1764 dissector_handle_t handle;
1765 guid_key key;
1767 key.guid = *uuid;
1768 key.ver = ver;
1770 handle = dissector_get_guid_handle(uuid_dissector_table, &key);
1771 if (handle == NULL) {
1772 return 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)
1784 guid_key key;
1785 dcerpc_uuid_value *sub_proto;
1787 key.guid = *uuid;
1788 key.ver = ver;
1789 if (!(sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key))) {
1790 return -1;
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;
1801 int i;
1802 int num_sd = 0;
1804 again:
1805 for (i = 0; sd[i].name; i++) {
1806 if (vs) {
1807 vs[i].value = sd[i].num;
1808 vs[i].strptr = sd[i].name;
1809 } else
1810 num_sd++;
1813 if (!vs) {
1814 vs = (value_string *)wmem_alloc(wmem_epan_scope(), (num_sd + 1) * sizeof(value_string));
1815 goto again;
1818 vs[num_sd].value = 0;
1819 vs[num_sd].strptr = NULL;
1821 return vs;
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)
1830 guid_key key;
1831 dcerpc_uuid_value *sub_proto;
1833 key.guid = *uuid;
1834 key.ver = ver;
1835 if (!(sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key))) {
1836 return NULL;
1838 return sub_proto->procs;
1842 static int
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));
1851 static unsigned
1852 dcerpc_connection_hash(const void *k)
1854 const dcerpc_connection *key = (const dcerpc_connection *)k;
1855 unsigned hash;
1857 hash = GPOINTER_TO_UINT(key->conv);
1858 hash += g_int64_hash(&key->transport_salt);
1860 return hash;
1864 static int
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));
1874 static unsigned
1875 dcerpc_bind_hash(const void *k)
1877 const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
1878 unsigned hash;
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));
1886 return hash;
1889 static int
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));
1899 static unsigned
1900 dcerpc_auth_context_hash(const void *k)
1902 const dcerpc_auth_context *key = (const dcerpc_auth_context *)k;
1903 unsigned hash;
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));
1911 return hash;
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;
1923 uint32_t call_id;
1924 uint64_t transport_salt;
1925 } dcerpc_cn_call_key;
1927 typedef struct _dcerpc_dg_call_key {
1928 conversation_t *conv;
1929 uint32_t seqnum;
1930 e_guid_t act_id ;
1931 } dcerpc_dg_call_key;
1934 static int
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));
1944 static int
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)));
1954 static unsigned
1955 dcerpc_cn_call_hash(const void *k)
1957 const dcerpc_cn_call_key *key = (const dcerpc_cn_call_key *)k;
1958 unsigned hash;
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));
1966 return hash;
1969 static 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 {
1991 uint32_t frame;
1992 uint32_t call_id;
1993 } dcerpc_matched_key;
1995 static int
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));
2004 static unsigned
2005 dcerpc_matched_hash(const void *k)
2007 const dcerpc_matched_key *key = (const dcerpc_matched_key *)k;
2008 return key->frame;
2011 static bool
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]) ){
2025 return false;
2027 return true;
2030 static void
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;
2035 int i, hf_opnum;
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);
2043 if(hf_opnum != -1){
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);
2045 } else {
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++){
2050 int j;
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_)
2069 unsigned i = 0;
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;
2078 if(!ri->call_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;
2106 static unsigned
2107 dcerpcstat_param(register_srt_t* srt, const char* opt_arg, char** err)
2109 int pos = 0;
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;
2113 int major, minor;
2114 uint16_t ver;
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);
2122 return pos;
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);
2126 return pos;
2128 ver = major;
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);
2159 else
2161 *err = ws_strdup_printf("<uuid>,<major version>.<minor version>[,<filter>]");
2164 return pos;
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)
2177 uint8_t data;
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));
2186 if (pdata)
2187 *pdata = data;
2188 tvb_ensure_bytes_exist(tvb, offset, 1);
2189 return 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)
2197 uint8_t data;
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));
2203 if (pdata)
2204 *pdata = data;
2205 tvb_ensure_bytes_exist(tvb, offset, 1);
2206 return 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)
2214 uint16_t data;
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));
2223 if (pdata)
2224 *pdata = data;
2225 tvb_ensure_bytes_exist(tvb, offset, 2);
2226 return 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)
2234 uint32_t data;
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));
2243 if (pdata)
2244 *pdata = data;
2245 tvb_ensure_bytes_exist(tvb, offset, 4);
2246 return 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)
2255 uint32_t data;
2256 nstime_t tv;
2258 data = ((drep[0] & DREP_LITTLE_ENDIAN)
2259 ? tvb_get_letohl(tvb, offset)
2260 : tvb_get_ntohl(tvb, offset));
2262 tv.secs = data;
2263 tv.nsecs = 0;
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");
2268 } else {
2269 proto_tree_add_time(tree, hfindex, tvb, offset, 4, &tv);
2272 if (pdata)
2273 *pdata = data;
2275 tvb_ensure_bytes_exist(tvb, offset, 4);
2276 return 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)
2284 uint64_t data;
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
2295 helper here
2297 hfinfo = proto_registrar_get_nth(hfindex);
2299 switch (hfinfo->type) {
2300 case FT_UINT64:
2301 proto_tree_add_uint64(tree, hfindex, tvb, offset, 8, data);
2302 break;
2303 case FT_INT64:
2304 proto_tree_add_int64(tree, hfindex, tvb, offset, 8, data);
2305 break;
2306 default:
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);
2313 if (pdata)
2314 *pdata = data;
2315 tvb_ensure_bytes_exist(tvb, offset, 8);
2316 return 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)
2325 float data;
2328 switch (drep[1]) {
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);
2336 break;
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) */
2340 default:
2341 /* ToBeDone: non IEEE floating formats */
2342 /* Set data to a negative infinity value */
2343 data = -FLT_MAX;
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)!",
2346 drep[1]);
2348 if (pdata)
2349 *pdata = data;
2350 tvb_ensure_bytes_exist(tvb, offset, 4);
2351 return 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)
2360 double data;
2363 switch (drep[1]) {
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);
2371 break;
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) */
2375 default:
2376 /* ToBeDone: non IEEE double formats */
2377 /* Set data to a negative infinity value */
2378 data = -DBL_MAX;
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)!",
2381 drep[1]);
2383 if (pdata)
2384 *pdata = data;
2385 tvb_ensure_bytes_exist(tvb, offset, 8);
2386 return 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)
2395 e_guid_t uuid;
2398 if (drep[0] & DREP_LITTLE_ENDIAN) {
2399 tvb_get_letohguid(tvb, offset, (e_guid_t *) &uuid);
2400 } else {
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);
2406 if (pdata) {
2407 *pdata = uuid;
2409 return offset + 16;
2414 * a couple simpler things
2416 uint16_t
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);
2421 } else {
2422 return tvb_get_ntohs(tvb, offset);
2426 uint32_t
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);
2431 } else {
2432 return tvb_get_ntohl(tvb, offset);
2436 void
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);
2441 } else {
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;
2452 uint64_t val;
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,
2462 -1, &val);
2463 DISSECTOR_ASSERT(val <= UINT32_MAX);
2464 nga->max_count = (uint32_t)val;
2465 nga->max_count_offset = offset-conformance_size;
2467 nga->offset = 0;
2468 nga->actual_count = nga->max_count;
2470 nga->is_conformant = true;
2472 return offset;
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;
2481 uint64_t val;
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,
2491 -1, &val);
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,
2496 -1, &val);
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;
2503 return offset;
2506 static int
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,
2528 conformance_size,
2529 nga->max_count);
2531 if (nga->is_varying) {
2532 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb,
2533 nga->offset_offset,
2534 conformance_size,
2535 nga->offset);
2536 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb,
2537 nga->actual_count_offset,
2538 conformance_size,
2539 nga->actual_count);
2542 /* real run, dissect the elements */
2543 if (fnct_block) {
2544 offset = (*fnct_block)(tvb, offset, nga->actual_count,
2545 pinfo, tree, di, drep);
2546 } else {
2547 uint32_t i;
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)
2553 break;
2557 return 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,
2568 fnct_bytes,
2569 NULL);
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,
2580 NULL,
2581 fnct_block);
2584 /* NDR arrays */
2585 /* function to dissect a unidimensional conformant array */
2586 static int
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));
2599 if (is_conformant)
2600 offset = dissect_ndr_conformant_array_hdr(tvb, offset, pinfo, tree, di, drep, &nga);
2601 if (is_varying)
2602 offset = dissect_ndr_varying_array_hdr(tvb, offset, pinfo, tree, di, drep, &nga);
2603 if (fnct_block) {
2604 offset = dissect_ndr_generic_array_block(tvb, offset, pinfo,
2605 tree, di, drep, &nga,
2606 fnct_block);
2607 } else if (fnct_bytes) {
2608 offset = dissect_ndr_generic_array_bytes(tvb, offset, pinfo,
2609 tree, di, drep, &nga,
2610 fnct_bytes);
2613 return offset;
2616 /* NDR arrays */
2617 /* function to dissect a unidimensional conformant array */
2618 static int
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,
2625 tree, di, drep,
2626 true, /* is_conformant */
2627 false, /* is_varying */
2628 fnct_bytes,
2629 fnct_block);
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
2652 static int
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,
2659 tree, di, drep,
2660 true, /* is_conformant */
2661 true, /* is_varying */
2662 fnct_bytes,
2663 fnct_block);
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 */
2682 static int
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,
2689 tree, di, drep,
2690 false, /* is_conformant */
2691 true, /* is_varying */
2692 fnct_bytes,
2693 fnct_block);
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
2713 released that IDL.)
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)
2723 uint64_t len;
2725 if (di->conformant_run) {
2726 /* just a run to handle conformant arrays, no scalars to dissect */
2727 return offset;
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);
2742 if (len) {
2743 proto_tree_add_item(tree, di->hf_index, tvb, offset, (uint32_t)len,
2744 ENC_NA);
2747 offset += (uint32_t)len;
2749 return offset;
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 {
2756 int size_is;
2757 int hfindex;
2758 bool add_subtree;
2759 char **data;
2762 static int
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;
2777 char *s;
2779 if (add_subtree) {
2780 string_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_dcerpc_string, &string_item,
2781 proto_registrar_get_name(hfindex));
2782 } else {
2783 string_item = NULL;
2784 string_tree = tree;
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;
2791 /* Adjust offset */
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));
2809 } else {
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,
2818 buffer_len, s);
2820 if (string_item != NULL)
2821 proto_item_append_text(string_item, ": %s", s);
2823 if (data)
2824 *data = s;
2826 offset += buffer_len;
2828 proto_item_set_end(string_item, tvb, offset);
2830 return 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,
2838 char **data)
2840 struct dcerpc_ndr_string_uarray_blk_state state = {
2841 .size_is = size_is,
2842 .hfindex = hfindex,
2843 .add_subtree = add_subtree,
2844 .data = data,
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);
2854 old_di = *di;
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);
2859 *di = old_di;
2861 return offset;
2864 static int
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,
2869 char **data)
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);
2879 if (is_conformant)
2880 offset = dissect_ndr_conformant_array_hdr(tvb, offset, pinfo, tree, di, drep, &nga);
2881 if (is_varying)
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);
2885 return offset;
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,
2895 tree, di, drep,
2896 size_is, hfindex, add_subtree,
2897 true, /* is_conformant */
2898 true, /* is_varying */
2899 data);
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,
2909 tree, di, drep,
2910 size_is, hfindex, add_subtree,
2911 true, /* is_conformant */
2912 false, /* is_varying */
2913 data);
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,
2931 false, NULL);
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,
2949 false, NULL);
2952 /* This function is aimed for PIDL usage and dissects a UNIQUE pointer to
2953 * unicode string.
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)
2958 char *s = NULL;
2959 int levels = CB_STR_ITEM_LEVELS(param);
2961 offset = dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep,
2962 chsize, hfindex,
2963 false, &s);
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;
2980 levels--;
2981 if (levels > 0) {
2982 proto_item_append_text(tree, ": %s", s);
2983 tree = tree->parent;
2984 levels--;
2985 while (levels > 0) {
2986 proto_item_append_text(tree, " %s", s);
2987 tree = tree->parent;
2988 levels--;
2995 return offset;
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,
3008 tree, di, drep,
3009 size_is, hfindex, add_subtree,
3010 false, /* is_conformant */
3011 true, /* is_varying */
3012 data);
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,
3030 false, NULL);
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,
3048 false, NULL);
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 {
3054 uint32_t id;
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*/
3058 int hf_index;
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;
3065 void
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));
3080 void
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;
3096 int old_offset;
3097 int next_pointer;
3098 unsigned original_depth;
3099 int len;
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) {
3107 return offset;
3110 /* Probably not necessary, it is supposed to prevent more pointers from
3111 * being added to the list. */
3112 di->pointers.list = NULL;
3114 next_pointer = 0;
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);
3121 do {
3122 int i;
3124 found_new_pointer = 0;
3125 process_list:
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);
3129 if (tnpd->fnct) {
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;
3136 next_pointer = i+1;
3137 found_new_pointer = 1;
3138 fnct = tnpd->fnct;
3139 tnpd->fnct = NULL;
3140 di->ptr_stack = tnpd->ptr_stack;
3141 di->hf_index = tnpd->hf_index;
3142 /* first a run to handle any conformant
3143 array headers */
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
3158 * in the array.
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
3173 * dissected.
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) {
3189 * return offset;
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);
3201 if (tnpd->callback)
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. */
3208 next_pointer = 0;
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 */
3213 } else {
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)) {
3229 GSList *list;
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 !
3239 next_pointer = 0;
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;
3253 return offset;
3256 static int
3257 find_pointer_index(dcerpc_info *di, uint32_t id)
3259 unsigned *p = (unsigned*) g_hash_table_lookup(di->pointers.hash, &id);
3261 return (p != NULL);
3264 static void
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;
3270 unsigned *p_id;
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;
3284 } else {
3285 /* if we haven't seen the request bail out since we can't
3286 know whether this is the first non-NULL instance
3287 or not */
3288 if (value->req_frame == 0) {
3289 /* XXX THROW EXCEPTION */
3292 /* We saw this one in the request frame, nothing to
3293 dissect later */
3294 if (id <= value->max_ptr) {
3295 return;
3300 npd = g_new(ndr_pointer_data_t, 1);
3301 npd->id = id;
3302 npd->tree = tree;
3303 npd->item = item;
3304 npd->fnct = fnct;
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);
3311 *p_id = id;
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,
3318 di->pointers.list);
3319 } else {
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
3331 * the bytestream.
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.
3361 return offset;
3363 if (di->call_data->flags & DCERPC_IS_NDR64) {
3364 pointer_size = 8;
3368 /*TOP LEVEL REFERENCE POINTER*/
3369 if (di->pointers.are_top_level
3370 && (type == NDR_POINTER_REF) ) {
3371 proto_item *item;
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);
3379 goto after_ref_id;
3382 /*TOP LEVEL FULL POINTER*/
3383 if (di->pointers.are_top_level
3384 && (type == NDR_POINTER_PTR) ) {
3385 int found;
3386 uint64_t id;
3387 proto_item *item;
3389 /* get the referent id */
3390 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
3392 /* we got a NULL pointer */
3393 if (id == 0) {
3394 proto_tree_add_bytes_format_value(tree, hf_dcerpc_null_pointer, tvb, offset-pointer_size,
3395 pointer_size, NULL, "%s", text);
3396 goto after_ref_id;
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 */
3405 if (found) {
3406 proto_tree_add_string(tree, hf_dcerpc_duplicate_ptr, tvb, offset-pointer_size, pointer_size, text);
3407 goto after_ref_id;
3410 /* new pointer */
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);
3416 } else {
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);
3422 goto after_ref_id;
3424 /*TOP LEVEL UNIQUE POINTER*/
3425 if (di->pointers.are_top_level
3426 && (type == NDR_POINTER_UNIQUE) ) {
3427 uint64_t id;
3428 proto_item *item;
3430 /* get the referent id */
3431 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
3433 /* we got a NULL pointer */
3434 if (id == 0) {
3435 proto_tree_add_bytes_format_value(tree, hf_dcerpc_null_pointer, tvb, offset-pointer_size,
3436 pointer_size, NULL, "%s",text);
3437 goto after_ref_id;
3440 /* new pointer */
3441 tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
3442 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);
3447 } else {
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);
3453 goto after_ref_id;
3456 /*EMBEDDED REFERENCE POINTER*/
3457 if ((!di->pointers.are_top_level)
3458 && (type == NDR_POINTER_REF) ) {
3459 uint64_t id;
3460 proto_item *item;
3462 /* get the referent id */
3463 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
3465 /* new pointer */
3466 tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
3467 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);
3472 } else {
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);
3478 goto after_ref_id;
3481 /*EMBEDDED UNIQUE POINTER*/
3482 if ((!di->pointers.are_top_level)
3483 && (type == NDR_POINTER_UNIQUE) ) {
3484 uint64_t id;
3485 proto_item *item;
3487 /* get the referent id */
3488 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
3490 /* we got a NULL pointer */
3491 if (id == 0) {
3492 proto_tree_add_bytes_format_value(tree, hf_dcerpc_null_pointer, tvb, offset-pointer_size,
3493 pointer_size, NULL, "%s",text);
3494 goto after_ref_id;
3497 /* new pointer */
3498 tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
3499 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);
3504 } else {
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);
3510 goto after_ref_id;
3513 /*EMBEDDED FULL POINTER*/
3514 if ((!di->pointers.are_top_level)
3515 && (type == NDR_POINTER_PTR) ) {
3516 int found;
3517 uint64_t id;
3518 proto_item *item;
3520 /* get the referent id */
3521 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
3523 /* we got a NULL pointer */
3524 if (id == 0) {
3525 proto_tree_add_bytes_format_value(tree, hf_dcerpc_null_pointer, tvb, offset-pointer_size,
3526 pointer_size, NULL, "%s",text);
3527 goto after_ref_id;
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 */
3536 if (found) {
3537 proto_tree_add_string(tree, hf_dcerpc_duplicate_ptr, tvb, offset-pointer_size, pointer_size, text);
3538 goto after_ref_id;
3541 /* new pointer */
3542 tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
3543 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);
3548 } else {
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);
3554 goto after_ref_id;
3558 after_ref_id:
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
3561 argument */
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 */
3569 if (tr) {
3570 proto_item_set_len(tr, offset-start_offset);
3572 return 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,
3582 NULL, NULL);
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)
3589 int ret;
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,
3594 NULL, NULL);
3595 return ret;
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)
3602 int ret;
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,
3607 NULL, NULL);
3608 return ret;
3611 static void
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,
3618 ENC_LITTLE_ENDIAN);
3621 static void
3622 dissect_sec_vt_pcontext(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb)
3624 int offset = 0;
3625 proto_item *ti = NULL;
3626 proto_tree *tr = proto_tree_add_subtree(tree, tvb, offset, -1,
3627 ett_dcerpc_sec_vt_pcontext,
3628 &ti, "pcontext");
3629 e_guid_t uuid;
3630 const char *uuid_name;
3632 tvb_get_letohguid(tvb, offset, &uuid);
3633 uuid_name = guids_get_uuid_name(&uuid, pinfo->pool);
3634 if (!uuid_name) {
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);
3640 offset += 16;
3642 proto_tree_add_item(tr, hf_dcerpc_sec_vt_pcontext_ver,
3643 tvb, offset, 4, ENC_LITTLE_ENDIAN);
3644 offset += 4;
3646 tvb_get_letohguid(tvb, offset, &uuid);
3647 uuid_name = guids_get_uuid_name(&uuid, pinfo->pool);
3648 if (!uuid_name) {
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);
3654 offset += 16;
3656 proto_tree_add_item(tr, hf_dcerpc_sec_vt_pcontext_ver,
3657 tvb, offset, 4, ENC_LITTLE_ENDIAN);
3658 offset += 4;
3660 proto_item_set_len(ti, offset);
3663 static void
3664 dissect_sec_vt_header(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb)
3666 int offset = 0;
3667 proto_item *ti = NULL;
3668 proto_tree *tr = proto_tree_add_subtree(tree, tvb, offset, -1,
3669 ett_dcerpc_sec_vt_header,
3670 &ti, "header2");
3671 uint8_t drep[4];
3672 uint8_t ptype = tvb_get_uint8(tvb, offset);
3674 proto_tree_add_uint(tr, hf_dcerpc_packet_type, tvb, offset, 1, ptype);
3675 offset += 1;
3677 proto_tree_add_item(tr, hf_dcerpc_reserved, tvb, offset, 1, ENC_NA);
3678 offset += 1;
3680 proto_tree_add_item(tr, hf_dcerpc_reserved, tvb, offset, 2, ENC_NA);
3681 offset += 2;
3683 tvb_memcpy(tvb, drep, offset, 4);
3684 proto_tree_add_dcerpc_drep(tr, tvb, offset, drep, 4);
3685 offset += 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);
3699 static void
3700 dissect_sec_vt_preauth(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb)
3702 int offset = 0;
3703 uint8_t salt[16];
3704 uint8_t sha512[64];
3705 proto_item *ti = NULL;
3706 proto_tree *tr = proto_tree_add_subtree(tree, tvb, offset, -1,
3707 ett_dcerpc_sec_vt_preauth,
3708 &ti, "preauth");
3710 tvb_memcpy(tvb, salt, offset, 16);
3711 proto_tree_add_bytes(tr, hf_dcerpc_sec_vt_preauth_salt, tvb, offset, 16, salt);
3712 offset += 16;
3714 tvb_memcpy(tvb, sha512, offset, 64);
3715 proto_tree_add_bytes(tr, hf_dcerpc_sec_vt_preauth_sha512, tvb, offset, 64, sha512);
3716 offset += 64;
3718 proto_item_set_len(ti, offset);
3721 static int
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);
3726 int offset;
3727 int signature_start;
3728 int payload_length;
3729 typedef enum {
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,
3737 } sec_vt_command;
3738 proto_item *payload_item;
3739 proto_item *item;
3740 proto_tree *tree;
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)) {
3748 return -1;
3751 /* We only scan the last 512 bytes for a possible trailer */
3752 if (remaining > 512) {
3753 offset = remaining - 512;
3754 remaining = 512;
3755 } else {
3756 offset = 0;
3758 offset += stub_offset;
3760 signature_start = tvb_find_tvb(tvb, tvb_trailer_signature, offset);
3761 if (signature_start == -1) {
3762 return -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) {
3787 sec_vt_command cmd;
3788 uint16_t len, len_missalign;
3789 bool cmd_end, cmd_must;
3790 proto_item *ti;
3791 proto_tree *tr;
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,
3802 &ti, "Command: %s",
3803 val_to_str(cmd, sec_vt_command_cmd_vals,
3804 "Unknown (0x%04x)"));
3806 if (cmd_must) {
3807 proto_item_append_text(ti, "!!!");
3809 if (cmd_end) {
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,
3817 ENC_LITTLE_ENDIAN);
3818 offset += 2;
3820 proto_tree_add_item(tr, hf_dcerpc_sec_vt_command_length, tvb,
3821 offset, 2, ENC_LITTLE_ENDIAN);
3822 offset += 2;
3824 cmd_tvb = tvb_new_subset_length(tvb, offset, len);
3825 switch (cmd) {
3826 case SEC_VT_COMMAND_BITMASK_1:
3827 dissect_sec_vt_bitmask(tr, cmd_tvb);
3828 break;
3829 case SEC_VT_COMMAND_PCONTEXT:
3830 dissect_sec_vt_pcontext(pinfo, tr, cmd_tvb);
3831 break;
3832 case SEC_VT_COMMAND_HEADER2:
3833 dissect_sec_vt_header(pinfo, tr, cmd_tvb);
3834 break;
3835 case SEC_VT_COMMAND_PREAUTH:
3836 dissect_sec_vt_preauth(pinfo, tr, cmd_tvb);
3837 break;
3838 default:
3839 proto_tree_add_item(tr, hf_dcerpc_unknown, cmd_tvb, 0, len, ENC_NA);
3840 break;
3843 offset += len;
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);
3851 offset += l;
3852 remaining -= l;
3855 if (cmd_end) {
3856 break;
3860 proto_item_set_end(item, tvb, offset);
3861 return offset;
3864 static int
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;
3869 TRY {
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 {
3879 } ENDTRY;
3880 return ret;
3883 static int
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;
3891 guid_key key;
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);
3922 return -1;
3925 tap_queue_packet(dcerpc_tap, pinfo, info);
3926 return 0;
3929 static void
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) {
3953 goto return_value;
3956 connection = wmem_new(wmem_file_scope(), dcerpc_connection);
3957 if (connection == NULL) {
3958 return NULL;
3961 *connection = connection_key;
3962 wmem_map_insert(dcerpc_connections, connection, connection);
3964 return_value:
3965 if (pinfo->fd->num < connection->first_frame) {
3966 connection->first_frame = pinfo->fd->num;
3968 return connection;
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) {
3986 goto return_value;
3989 auth_value = wmem_new(wmem_file_scope(), dcerpc_auth_context);
3990 if (auth_value == NULL) {
3991 return NULL;
3994 *auth_value = auth_key;
3995 wmem_map_insert(dcerpc_auths, auth_value, auth_value);
3997 return_value:
3998 if (pinfo->fd->num < auth_value->first_frame) {
3999 auth_value->first_frame = pinfo->fd->num;
4001 return auth_value;
4004 static void
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
4031 * come before it.
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
4037 * stub data?)
4040 if (hdr->auth_len
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.
4075 TRY {
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,
4096 "AuthType(%u)"),
4097 val_to_str(auth_info->auth_level,
4098 authn_level_vals,
4099 "AuthLevel(%u)"),
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)),
4108 hdr->auth_len);
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);
4132 else
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);
4140 } ENDTRY;
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
4148 * socket.
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.
4155 uint64_t
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... */
4167 return 0;
4170 void
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
4182 static void
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;
4188 unsigned i;
4189 uint16_t ctx_id;
4190 uint8_t num_trans_items;
4191 unsigned j;
4192 e_guid_t if_id;
4193 e_guid_t trans_id;
4194 uint32_t trans_ver;
4195 uint16_t if_ver, if_ver_minor;
4196 dcerpc_auth_info auth_info;
4197 char *uuid_str;
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);
4214 /* padding */
4215 offset += 3;
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;
4232 if (dcerpc_tree) {
4233 ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_item,
4234 tvb, offset, 0,
4235 ENC_NA);
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);
4244 if (dcerpc_tree) {
4245 proto_item_append_text(ctx_item, "[%u]: Context ID:%u", i+1, ctx_id);
4248 /* padding */
4249 offset += 1;
4251 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &if_id);
4252 if (ctx_tree) {
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);
4259 if (uuid_name) {
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);
4264 } else {
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);
4271 offset += 16;
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);
4278 } else {
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);
4285 if (ctx_tree) {
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);
4296 if (ctx_tree) {
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",
4309 uuid_str);
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,
4314 ENC_LITTLE_ENDIAN);
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);
4323 } else {
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);
4332 offset += 16;
4334 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, trans_tree, hdr->drep,
4335 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
4336 if (ctx_tree) {
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);
4352 key->conv = conv;
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);
4365 if (i > 0) {
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));
4372 if (ctx_tree) {
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);
4385 static void
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;
4392 unsigned i;
4393 uint16_t result = 0;
4394 uint16_t reason = 0;
4395 e_guid_t trans_id;
4396 uint32_t trans_ver;
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;
4418 if (offset % 4) {
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);
4425 /* padding */
4426 offset += 3;
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;
4435 if (dcerpc_tree) {
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,
4441 &result);
4443 /* [MS-RPCE] 3.3.1.5.3 check if this Ctx Item is the response to a Bind Time Feature Negotiation request */
4444 if (result == 3) {
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,
4449 ENC_LITTLE_ENDIAN);
4450 offset += 2;
4451 } else if (result != 0) {
4452 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree,
4453 hdr->drep, hf_dcerpc_cn_ack_reason,
4454 &reason);
4455 } else {
4457 * The reason for rejection isn't meaningful, and often isn't
4458 * set, when the syntax was accepted.
4460 offset += 2;
4463 result_str = val_to_str(result, p_cont_result_vals, "Unknown result (%u)");
4465 if (ctx_tree) {
4466 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &trans_id);
4467 uuid_name = guids_get_uuid_name(&trans_id, pinfo->pool);
4468 if (! uuid_name) {
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",
4473 uuid_name);
4474 proto_item_append_text(ctx_item, " %s, %s", result_str, uuid_name);
4476 offset += 16;
4478 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, ctx_tree, hdr->drep,
4479 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
4481 if (i > 0) {
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);
4494 static void
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)
4498 uint16_t reason;
4499 uint8_t num_protocols;
4500 unsigned i;
4502 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
4503 hdr->drep, hf_dcerpc_cn_reject_reason,
4504 &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,
4512 &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,
4517 NULL);
4518 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
4519 hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
4520 NULL);
4525 /* Return a string describing a DCE/RPC fragment as first, middle, or end
4526 fragment. */
4528 #define PFC_FRAG_MASK 0x03
4530 static const char *
4531 fragment_type(uint8_t flags)
4533 static const char* t[4] = {
4534 "Mid",
4535 "1st",
4536 "Last",
4537 "Single"
4539 return t[flags & PFC_FRAG_MASK];
4542 /* Dissect stub data (payload) of a DCERPC packet. */
4544 static void
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_,
4549 uint32_t frame)
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;
4557 proto_item *pi;
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
4568 stuff. */
4569 return;
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) {
4586 tvbuff_t *result;
4588 result = decode_encrypted_data(header_tvb, payload_tvb, trailer_tvb,
4589 pinfo, hdr, auth_info);
4590 if (result) {
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");
4597 /* We succeeded. */
4598 decrypted_tvb = result;
4601 } else
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;
4614 return;
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
4628 encrypted stub?
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;
4640 return;
4643 /* if we have already seen this packet, see if it was reassembled
4644 and if so dissect the full pdu.
4645 then exit
4647 if (pinfo->fd->visited) {
4648 fd_head = fragment_get_reassembled_id(&dcerpc_co_reassembly_table, pinfo, frame);
4649 goto end_cn_stub;
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)) )
4657 goto end_cn_stub;
4659 /* if we didn't get 'frame' we don't know where the PDU started and thus
4660 it is pointless to continue
4662 if (!frame)
4663 goto end_cn_stub;
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. */
4676 goto end_cn_stub;
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 */);
4690 end_cn_stub:
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) ) {
4699 tvbuff_t *next_tvb;
4700 proto_item *frag_tree_item;
4702 next_tvb = tvb_new_chain((decrypted_tvb)?decrypted_tvb:payload_tvb,
4703 fd_head->tvb_data);
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);
4721 } else {
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);
4725 } else {
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);
4738 } else {
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);
4745 } else {
4746 show_stub_data(pinfo, payload_tvb, 0, tree, auth_info, true);
4750 pinfo->fragmented = save_fragmented;
4753 static void
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;
4759 uint16_t ctx_id;
4760 uint16_t opnum;
4761 e_guid_t obj_id = DCERPC_UUID_NULL;
4762 dcerpc_auth_info auth_info;
4763 uint32_t alloc_hint;
4764 proto_item *pi;
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",
4785 opnum, ctx_id);
4787 if (hdr->flags & PFC_OBJECT_UUID) {
4788 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &obj_id);
4789 if (dcerpc_tree) {
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));
4794 offset += 16;
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);
4804 if (!conv)
4805 show_stub_data(pinfo, tvb, offset, dcerpc_tree, &auth_info, true);
4806 else {
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);
4818 if (!value) {
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);
4838 value = call_value;
4840 } else {
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
4847 matched table
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);
4882 value = call_value;
4887 if (value) {
4888 dcerpc_info *di;
4890 di = wmem_new0(pinfo->pool, dcerpc_info);
4891 /* handoff this call */
4892 di->dcerpc_procedure_name = "";
4893 di->conv = conv;
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;
4898 di->hf_index = -1;
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,
4911 value->req_frame);
4912 } else {
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);
4926 static void
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;
4933 uint16_t ctx_id;
4934 dcerpc_auth_info auth_info;
4935 uint32_t alloc_hint;
4936 proto_item *pi;
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);
4958 /* padding */
4959 offset++;
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);
4969 if (!conv) {
4970 /* no point in creating one here, really */
4971 show_stub_data(pinfo, tvb, offset, dcerpc_tree, &auth_info, true);
4972 } else {
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);
4983 if (!value) {
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);
4998 value = call_value;
4999 if (call_value->rep_frame == 0) {
5000 call_value->rep_frame = pinfo->num;
5006 if (value) {
5007 dcerpc_info *di;
5009 di = wmem_new0(pinfo->pool, dcerpc_info);
5010 /* handoff this call */
5011 di->dcerpc_procedure_name = "";
5012 di->conv = conv;
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);
5029 /* request in */
5030 if (value->req_frame != 0) {
5031 nstime_t delta_ts;
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);
5041 } else {
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,
5047 value->rep_frame);
5048 } else {
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);
5062 static void
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;
5068 uint16_t ctx_id;
5069 uint32_t status;
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));
5090 offset += 1;
5092 #if 0
5093 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
5094 hf_dcerpc_cn_status, &status);
5095 #endif
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));
5101 offset+=4;
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)"));
5113 /* padding */
5114 proto_tree_add_item(dcerpc_tree, hf_dcerpc_reserved, tvb, offset, 4, ENC_NA);
5115 offset += 4;
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
5128 stuff. */
5129 return;
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);
5137 if (!conv) {
5138 /* no point in creating one here, really */
5139 } else {
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);
5150 if (!value) {
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);
5163 value = call_value;
5164 if (call_value->rep_frame == 0) {
5165 call_value->rep_frame = pinfo->num;
5171 if (value) {
5172 proto_tree *stub_tree = NULL;
5173 int stub_length;
5174 dcerpc_info *di;
5175 proto_item *parent_pi;
5177 di = wmem_new0(pinfo->pool, dcerpc_info);
5178 /* handoff this call */
5179 di->dcerpc_procedure_name = "";
5180 di->conv = conv;
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) {
5189 nstime_t delta_ts;
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);
5200 } else {
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);
5240 } else {
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);
5246 } else {
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. */
5251 if (dcerpc_tree) {
5252 if (length > 0) {
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,
5259 stub_tvb, 0,
5260 pinfo, value->rep_frame, NULL,
5261 stub_length,
5262 true);
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,
5269 stub_tvb, 0,
5270 pinfo, value->rep_frame, NULL,
5271 stub_length,
5272 true);
5274 if (fd_head) {
5275 /* We completed reassembly */
5276 tvbuff_t *next_tvb;
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.
5294 if (dcerpc_tree) {
5295 if (length > 0) {
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,
5304 stub_tvb, 0,
5305 pinfo, value->rep_frame, NULL,
5306 stub_length,
5307 true);
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);
5321 static void
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;
5328 uint16_t rts_flags;
5329 uint16_t commands_nb = 0;
5330 uint32_t *cmd;
5331 uint32_t i;
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,
5340 NULL
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);
5347 offset += 2;
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);
5361 cmd[i] = command;
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);
5364 offset += 4;
5365 switch (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);
5368 break;
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);
5373 break;
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);
5376 break;
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);
5379 break;
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);
5382 break;
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);
5385 break;
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);
5388 break;
5389 case RTS_CMD_EMPTY:
5390 break;
5391 case RTS_CMD_PADDING: {
5392 uint8_t *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);
5395 offset += 4;
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;
5399 } break;
5400 case RTS_CMD_NEGATIVEANCE:
5401 break;
5402 case RTS_CMD_ANCE:
5403 break;
5404 case RTS_CMD_CLIENTADDRESS: {
5405 uint8_t *padding;
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);
5408 offset += 4;
5409 switch (addrtype) {
5410 case RTS_IPV4: {
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));
5413 offset += 4;
5414 } break;
5415 case RTS_IPV6: {
5416 ws_in6_addr addr6;
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));
5419 offset += 16;
5420 } break;
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);
5424 offset += 12;
5425 } break;
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);
5428 break;
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);
5431 break;
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);
5434 break;
5435 default:
5436 expert_add_info(pinfo, tf, &ei_dcerpc_cn_rts_command);
5437 break;
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) {
5447 case RTS_FLAG_NONE:
5448 switch (commands_nb) {
5449 case 1:
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";
5463 break;
5464 case 2:
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";
5470 break;
5471 case 3:
5472 if ((cmd[0] == 0x6) && (cmd[1] == 0x0) && (cmd[2] == 0x2)) {
5473 info_str = "CONN/C1,CONN/C2";
5475 break;
5476 case 4:
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";
5482 break;
5483 case 6:
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";
5487 break;
5488 default:
5489 break;
5491 break;
5492 case RTS_FLAG_PING:
5493 switch (commands_nb) {
5494 case 0:
5495 info_str = "Ping";
5496 break;
5497 case 1:
5498 if ((cmd[0] == 0x7) || (cmd[0] == 0x8)) {
5499 info_str = "OUT_R2/C1";
5501 break;
5502 default:
5503 break;
5505 break;
5506 case RTS_FLAG_OTHER_CMD:
5507 switch (commands_nb) {
5508 case 1:
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";
5516 break;
5517 case 2:
5518 if ((cmd[0] == 0xD) && (cmd[1] == 0x1)) {
5519 info_str = "FlowControlAckWithDestination";
5521 break;
5522 default:
5523 break;
5525 break;
5526 case RTS_FLAG_RECYCLE_CHANNEL:
5527 switch (commands_nb) {
5528 case 1:
5529 if (cmd[0] == 0xD) {
5530 info_str = "OUT_R1/A1,OUT_R1/A2,OUT_R2/A1,OUT_R2/A2";
5532 break;
5533 case 4:
5534 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3)) {
5535 info_str = "IN_R1/A1,IN_R2/A1";
5537 break;
5538 case 5:
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";
5542 break;
5543 default:
5544 break;
5546 break;
5547 case RTS_FLAG_IN_CHANNEL|RTS_FLAG_RECYCLE_CHANNEL:
5548 switch (commands_nb) {
5549 case 6:
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";
5553 break;
5554 default:
5555 break;
5557 break;
5558 case RTS_FLAG_IN_CHANNEL:
5559 switch (commands_nb) {
5560 case 7:
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";
5564 break;
5565 default:
5566 break;
5568 break;
5569 case RTS_FLAG_OUT_CHANNEL|RTS_FLAG_RECYCLE_CHANNEL:
5570 switch (commands_nb) {
5571 case 7:
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";
5575 break;
5576 default:
5577 break;
5579 break;
5580 case RTS_FLAG_OUT_CHANNEL:
5581 switch (commands_nb) {
5582 case 2:
5583 if ((cmd[0] == 0xD) && (cmd[1] == 0x3)) {
5584 info_str = "OUT_R1/A7,OUT_R1/A8,OUT_R2/A8";
5586 break;
5587 case 3:
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";
5593 break;
5594 case 5:
5595 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x4) && (cmd[4] == 0x0)) {
5596 info_str = "CONN/A2";
5598 break;
5599 default:
5600 break;
5602 break;
5603 case RTS_FLAG_EOF:
5604 switch (commands_nb) {
5605 case 1:
5606 if (cmd[0] == 0xA) {
5607 info_str = "OUT_R2/B3";
5609 break;
5610 default:
5611 break;
5613 break;
5614 case RTS_FLAG_ECHO:
5615 switch (commands_nb) {
5616 case 0:
5617 info_str = "Echo";
5618 break;
5619 default:
5620 break;
5622 break;
5623 default:
5624 break;
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 */
5637 static bool
5638 is_dcerpc(tvbuff_t *tvb, int offset, packet_info *pinfo _U_)
5640 uint8_t rpc_ver;
5641 uint8_t rpc_ver_minor;
5642 uint8_t ptype;
5643 uint8_t drep[4];
5644 uint16_t frag_len;
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++);
5650 if (rpc_ver != 5)
5651 return false;
5652 rpc_ver_minor = tvb_get_uint8(tvb, offset++);
5653 if ((rpc_ver_minor != 0) && (rpc_ver_minor != 1))
5654 return false;
5655 ptype = tvb_get_uint8(tvb, offset++);
5656 if (ptype > PDU_RTS)
5657 return false;
5658 /* Skip flags, nothing good to check */
5659 offset++;
5661 tvb_memcpy(tvb, (uint8_t *)drep, offset, sizeof (drep));
5662 if (drep[0]&0xee)
5663 return false;
5664 if (drep[1] > DCE_RPC_DREP_FP_IBM)
5665 return false;
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)) {
5669 return false;
5672 return true;
5676 * DCERPC dissector for connection oriented calls.
5678 static bool
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 };
5683 int start_offset;
5684 int padding = 0;
5685 int subtvb_len = 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,
5702 NULL
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) {
5717 * Skip the padding.
5719 offset += 4;
5720 padding += 4;
5723 * Check if this looks like a C/O DCERPC call
5725 if (!is_dcerpc(tvb, offset, pinfo))
5726 return false;
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);
5738 offset += 2;
5739 hdr.auth_len = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5740 offset += 2;
5741 hdr.call_id = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
5742 /*offset += 4;*/
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 */
5749 return true;
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);
5770 if (tree) {
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);
5776 offset++;
5778 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset, 1, hdr.rpc_ver_minor);
5779 offset++;
5781 tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
5782 offset++;
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)"));
5788 #endif
5789 if (hdr.ptype == PDU_BIND_NAK)
5790 expert_add_info(pinfo, tf, &ei_dcerpc_bind_not_acknowledged);
5792 if (tree) {
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);
5800 offset++;
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);
5808 offset += 2;
5810 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
5811 offset += 2;
5813 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
5814 offset += 4;
5816 if (ti) {
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
5842 * offset otherwise.
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) {
5853 case PDU_BIND:
5854 case PDU_ALTER:
5855 dissect_dcerpc_cn_bind(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
5856 break;
5858 case PDU_BIND_ACK:
5859 case PDU_ALTER_ACK:
5860 dissect_dcerpc_cn_bind_ack(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
5861 break;
5863 case PDU_AUTH3:
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,
5868 &auth_info);
5869 break;
5871 case PDU_REQ:
5872 dissect_dcerpc_cn_rqst(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, tree, &hdr);
5873 break;
5875 case PDU_RESP:
5876 dissect_dcerpc_cn_resp(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, tree, &hdr);
5877 break;
5879 case PDU_FAULT:
5880 dissect_dcerpc_cn_fault(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
5881 break;
5883 case PDU_BIND_NAK:
5884 dissect_dcerpc_cn_bind_nak(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
5885 break;
5887 case PDU_CO_CANCEL:
5888 case PDU_ORPHANED:
5890 * Nothing after the common header other than an authentication
5891 * verifier.
5893 dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr,
5894 &auth_info);
5895 break;
5897 case PDU_SHUTDOWN:
5899 * Nothing after the common header, not even an authentication
5900 * verifier.
5902 break;
5903 case PDU_RTS:
5904 dissect_dcerpc_cn_rts(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
5905 break;
5907 default:
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,
5910 &auth_info);
5911 break;
5913 return true;
5917 * DCERPC dissector for connection oriented calls over packet-oriented
5918 * transports
5920 static bool
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
5927 * packet per PDU.
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.
5934 return false;
5935 } else {
5937 * It was.
5939 return true;
5944 * DCERPC dissector for connection oriented calls over byte-stream
5945 * transports.
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.
5949 static bool
5950 dissect_dcerpc_cn_bs_body(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
5952 volatile int offset = 0;
5953 int pdu_len = 0;
5954 volatile int dcerpc_pdus = 0;
5955 volatile bool ret = false;
5958 * There may be multiple PDUs per transport packet; keep
5959 * processing them.
5961 while (tvb_reported_length_remaining(tvb, offset) != 0) {
5962 TRY {
5963 pdu_len = 0;
5964 if (dissect_dcerpc_cn(tvb, offset, pinfo, tree,
5965 dcerpc_cn_desegment, &pdu_len)) {
5966 dcerpc_pdus++;
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
5974 * or info columns.
5976 * Just show the exception and then continue dissecting
5977 * PDUs.
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.
5984 dcerpc_pdus++;
5985 } ENDTRY;
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;
5997 break;
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
6007 * data. */
6008 pinfo->desegment_offset = offset;
6009 pinfo->desegment_len = (uint32_t)(sizeof(e_dce_cn_common_hdr_t) - tvb_reported_length_remaining(tvb, offset));
6010 } else {
6011 /* Really not DCE-RPC */
6012 break;
6017 * Well, we've seen at least one DCERPC PDU.
6019 ret = true;
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);
6026 if (pdu_len == 0) {
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"));
6036 break;
6040 * Step to the next PDU.
6042 offset += pdu_len;
6044 return ret;
6047 static bool
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);
6056 static unsigned
6057 get_dcerpc_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb,
6058 int offset, void *data _U_)
6060 uint8_t drep[4];
6061 uint16_t frag_len;
6063 tvb_memcpy(tvb, (uint8_t *)drep, offset+4, sizeof(drep));
6064 frag_len = dcerpc_tvb_get_ntohs(tvb, offset+8, drep);
6066 if (!frag_len) {
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.
6074 frag_len = 1;
6076 return frag_len;
6079 static int
6080 dissect_dcerpc_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
6082 int pdu_len = 0;
6083 dissect_dcerpc_cn(tvb, 0, pinfo, tree,
6084 /* Desegment is already handled by TCP, don't confuse it */
6085 false,
6086 &pdu_len);
6087 return pdu_len;
6090 static bool
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))
6096 return false;
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);
6102 return true;
6105 static int
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);
6117 static bool
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);
6126 static bool
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);
6137 static void
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)
6149 *auth_level_p = -1;
6152 * The authentication information is at the *end* of the PDU; in
6153 * request and response PDUs, the request and response stub data
6154 * come before it.
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);
6169 offset++;
6170 proto_tree_add_item(auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, ENC_BIG_ENDIAN);
6171 offset++;
6172 if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
6173 offset += 6; /* 6 bytes of padding */
6174 else
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);
6177 /*offset += 16;*/
6178 break;
6180 default:
6181 proto_tree_add_item(dcerpc_tree, hf_dcerpc_authentication_verifier, tvb, offset, -1, ENC_NA);
6182 break;
6187 static void
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)
6192 uint32_t version;
6194 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
6195 hdr->drep, hf_dcerpc_dg_cancel_vers,
6196 &version);
6198 switch (version) {
6200 case 0:
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,
6204 NULL);
6205 /*offset = */dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
6206 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
6207 NULL);
6208 break;
6212 static void
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)
6217 uint32_t version;
6219 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
6220 hdr->drep, hf_dcerpc_dg_cancel_vers,
6221 &version);
6223 switch (version) {
6225 case 0:
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,
6229 NULL);
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,
6236 NULL);*/
6237 break;
6241 static void
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)
6246 uint8_t version;
6247 uint16_t serial_num;
6248 uint16_t selack_len;
6249 unsigned i;
6251 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
6252 hdr->drep, hf_dcerpc_dg_fack_vers,
6253 &version);
6254 /* padding */
6255 offset++;
6257 switch (version) {
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,
6263 NULL);
6264 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
6265 hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
6266 NULL);
6267 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
6268 hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
6269 NULL);
6270 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
6271 hdr->drep, hf_dcerpc_dg_fack_serial_num,
6272 &serial_num);
6273 col_append_fstr(pinfo->cinfo, COL_INFO, " serial: %u",
6274 serial_num);
6275 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
6276 hdr->drep, hf_dcerpc_dg_fack_selack_len,
6277 &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,
6281 NULL);
6284 break;
6288 static void
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)
6293 uint32_t status;
6295 /*offset = */dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
6296 hdr->drep, hf_dcerpc_dg_status,
6297 &status);
6299 col_append_fstr (pinfo->cinfo, COL_INFO,
6300 ": status: %s",
6301 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
6304 static void
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;
6312 tvbuff_t *next_tvb;
6313 proto_item *pi;
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,
6346 reported_length);
6347 dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb, true, hdr->drep, di, NULL);
6348 } else {
6349 /* PDU is fragmented and this isn't the first fragment */
6350 if (length > 0) {
6351 proto_tree_add_item(dcerpc_tree, hf_dcerpc_fragment_data, tvb, offset, stub_length, ENC_NA);
6354 } else {
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. */
6359 if (length > 0) {
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,
6364 tvb, offset,
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);
6382 } else {
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;
6399 static void
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)
6404 dcerpc_info *di;
6405 dcerpc_call_value *value;
6406 dcerpc_matched_key matched_key, *new_matched_key;
6407 proto_item *pi;
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);
6445 if (!value) {
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;
6453 value->max_ptr = 0;
6454 value->se_data = NULL;
6455 value->private_data = NULL;
6458 di = wmem_new0(pinfo->pool, dcerpc_info);
6459 di->dcerpc_procedure_name = "";
6460 di->conv = conv;
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);
6478 static void
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)
6483 dcerpc_info *di;
6484 dcerpc_call_value *value;
6485 dcerpc_matched_key matched_key, *new_matched_key;
6486 proto_item *pi;
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);
6511 if (!value) {
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 = "";
6522 di->conv = conv;
6523 di->transport_salt = -1;
6524 di->ptype = PDU_RESP;
6525 di->call_data = value;
6527 if (value->req_frame != 0) {
6528 nstime_t delta_ts;
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);
6539 } else {
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);
6545 static void
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))) {
6560 proto_item *pi;
6561 nstime_t delta_ts;
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);
6576 /* }*/
6581 * DCERPC dissector for connectionless calls
6583 static bool
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;
6589 int offset = 0;
6590 conversation_t *conv;
6591 int auth_level;
6592 char *uuid_str;
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,
6603 NULL
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,
6615 NULL
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)) {
6624 return false;
6627 /* Version must be 4 */
6628 hdr.rpc_ver = tvb_get_uint8(tvb, offset++);
6629 if (hdr.rpc_ver != 4)
6630 return false;
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)
6635 return false;
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)
6649 return false;
6651 tvb_memcpy(tvb, (uint8_t *)hdr.drep, offset, sizeof (hdr.drep));
6652 offset += (int)sizeof (hdr.drep);
6653 if (hdr.drep[0]&0xee)
6654 return false;
6655 if (hdr.drep[1] > DCE_RPC_DREP_FP_IBM)
6656 return false;
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);
6663 offset += 16;
6664 dcerpc_tvb_get_uuid(tvb, offset, hdr.drep, &hdr.if_id);
6665 offset += 16;
6666 dcerpc_tvb_get_uuid(tvb, offset, hdr.drep, &hdr.act_id);
6667 offset += 16;
6668 hdr.server_boot = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
6669 offset += 4;
6670 hdr.if_ver = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
6671 offset += 4;
6672 hdr.seqnum = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
6673 offset += 4;
6674 hdr.opnum = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
6675 offset += 2;
6676 hdr.ihint = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
6677 offset += 2;
6678 hdr.ahint = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
6679 offset += 2;
6680 hdr.frag_len = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
6681 offset += 2;
6682 hdr.frag_num = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
6683 offset += 2;
6684 hdr.auth_proto = tvb_get_uint8(tvb, offset++);
6685 hdr.serial_lo = tvb_get_uint8(tvb, offset++);
6687 if (tree) {
6688 ti = proto_tree_add_item(tree, proto_dcerpc, tvb, 0, -1, ENC_NA);
6689 if (ti) {
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);
6697 offset = 0;
6699 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
6700 offset++;
6702 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
6703 offset++;
6705 proto_tree_add_bitmask_value(dcerpc_tree, tvb, offset, hf_dcerpc_dg_flags1,
6706 ett_dcerpc_dg_flags1, hdr_flags1, hdr.flags1);
6707 offset++;
6709 proto_tree_add_bitmask_value(dcerpc_tree, tvb, offset, hf_dcerpc_dg_flags2,
6710 ett_dcerpc_dg_flags2, hdr_flags2, hdr.flags2);
6711 offset++;
6713 if (tree) {
6714 proto_tree_add_dcerpc_drep(dcerpc_tree, tvb, offset, hdr.drep, (int)sizeof (hdr.drep));
6716 offset += (int)sizeof (hdr.drep);
6718 if (tree)
6719 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
6720 offset++;
6722 if (tree) {
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));
6727 offset += 16;
6729 if (tree) {
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);
6732 if (uuid_name) {
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);
6735 } else {
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);
6740 offset += 16;
6742 if (tree) {
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));
6747 offset += 16;
6749 if (tree) {
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,
6758 "Unknown (0)");
6759 else
6760 proto_tree_add_time(dcerpc_tree, hf_dcerpc_dg_server_boot,
6761 tvb, offset, 4, &server_boot);
6763 offset += 4;
6765 if (tree)
6766 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
6767 offset += 4;
6769 if (tree)
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);
6772 offset += 4;
6774 if (tree)
6775 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
6776 offset += 2;
6778 if (tree)
6779 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
6780 offset += 2;
6782 if (tree)
6783 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
6784 offset += 2;
6786 if (tree)
6787 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
6788 offset += 2;
6790 if (tree)
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",
6795 hdr.frag_num);
6797 offset += 2;
6799 if (tree)
6800 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
6801 offset++;
6803 if (tree)
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);
6810 offset++;
6812 if (tree) {
6814 * XXX - for Kerberos, we get a protection level; if it's
6815 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
6816 * stub data.
6818 dissect_dcerpc_dg_auth(tvb, offset, dcerpc_tree, &hdr,
6819 &auth_level);
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);
6846 break;
6848 case PDU_CL_CANCEL:
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
6852 * body.
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);
6857 break;
6859 case PDU_NOCALL:
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);
6864 break;
6866 case PDU_FACK:
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);
6871 break;
6873 case PDU_REJECT:
6874 case PDU_FAULT:
6875 dissect_dcerpc_dg_reject_fault(tvb, offset, pinfo, dcerpc_tree, &hdr);
6876 break;
6878 case PDU_REQ:
6879 dissect_dcerpc_dg_rqst(tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
6880 break;
6882 case PDU_RESP:
6883 dissect_dcerpc_dg_resp(tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
6884 break;
6886 /* these requests have no body */
6887 case PDU_ACK:
6888 case PDU_PING:
6889 dissect_dcerpc_dg_ping_ack(tvb, offset, pinfo, dcerpc_tree, &hdr, conv);
6890 break;
6891 case PDU_WORKING:
6892 default:
6893 break;
6896 return true;
6899 static void
6900 dcerpc_auth_subdissector_list_free(void *p, void *user_data _U_)
6902 g_free(p);
6905 static void
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);
6914 void
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 }},
6930 { &hf_dcerpc_ver,
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 }},
6954 { &hf_dcerpc_drep,
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 }},
7120 { &hf_dcerpc_opnum,
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 }},
7165 { &hf_dcerpc_op,
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 }},
7203 { &hf_dcerpc_time,
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[] = {
7313 &ett_dcerpc,
7314 &ett_dcerpc_cn_flags,
7315 &ett_dcerpc_cn_ctx,
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,
7323 &ett_dcerpc_drep,
7324 &ett_dcerpc_dg_flags1,
7325 &ett_dcerpc_dg_flags2,
7326 &ett_dcerpc_pointer_data,
7327 &ett_dcerpc_string,
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 }},
7352 #endif
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
7382 * - per connection,
7383 * - per presentation context (bind)
7384 * - per authentication context
7386 dcerpc_connections = wmem_map_new_autoreset(wmem_epan_scope(),
7387 wmem_file_scope(),
7388 dcerpc_connection_hash,
7389 dcerpc_connection_equal);
7391 dcerpc_binds = wmem_map_new_autoreset(wmem_epan_scope(),
7392 wmem_file_scope(),
7393 dcerpc_bind_hash,
7394 dcerpc_bind_equal);
7396 dcerpc_auths = wmem_map_new_autoreset(wmem_epan_scope(),
7397 wmem_file_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,
7412 "desegment_dcerpc",
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);
7451 void
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
7472 * Local variables:
7473 * c-basic-offset: 4
7474 * tab-width: 8
7475 * indent-tabs-mode: nil
7476 * End:
7478 * vi: set shiftwidth=4 tabstop=8 expandtab:
7479 * :indentSize=4:tabSize=8:noTabs=true: