epan/dissectors/pidl/samr/samr.cnf cnf_dissect_lsa_BinaryString => lsarpc_dissect_str...
[wireshark-sm.git] / epan / dissectors / packet-dcerpc.c
blobba6240444fae1e80958389aaec7b1297e7261cf1
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_new(uuid_dissector_table, &key, tvb, pinfo, tree, false, &dissector_data))) {
3911 * We don't have a dissector for this UUID, or the protocol
3912 * for that UUID is disabled.
3915 hidden_item = proto_tree_add_boolean(dcerpc_tree, hf_dcerpc_unknown_if_id,
3916 tvb, offset, 0, true);
3917 proto_item_set_hidden(hidden_item);
3918 col_append_fstr(pinfo->cinfo, COL_INFO, " %s V%u",
3919 guids_resolve_guid_to_str(&info->call_data->uuid, pinfo->pool), info->call_data->ver);
3921 show_stub_data(pinfo, tvb, 0, dcerpc_tree, auth_info, !decrypted);
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;
4028 * The authentication information is at the *end* of the PDU; in
4029 * request and response PDUs, the request and response stub data
4030 * come before it.
4032 * Is there any authentication data (i.e., is the authentication length
4033 * non-zero), and is the authentication length valid (i.e., is it, plus
4034 * 8 bytes for the type/level/pad length/reserved/context id, less than
4035 * or equal to the fragment length minus the starting offset of the
4036 * stub data?)
4039 if (hdr->auth_len
4040 && ((hdr->auth_len + 8) <= (hdr->frag_len - stub_offset))) {
4043 * Yes, there is authentication data, and the length is valid.
4044 * Do we have all the bytes of stub data?
4045 * (If not, we'd throw an exception dissecting *that*, so don't
4046 * bother trying to dissect the authentication information and
4047 * throwing another exception there.)
4049 offset = hdr->frag_len - (hdr->auth_len + 8);
4050 if (offset == 0 || tvb_offset_exists(tvb, offset - 1)) {
4051 dcerpc_connection *connection = NULL;
4052 dcerpc_auth_context *auth_context = NULL;
4053 int auth_offset = offset;
4055 /* Compute the size of the auth block. Note that this should not
4056 include auth padding, since when NTLMSSP encryption is used, the
4057 padding is actually inside the encrypted stub */
4058 auth_info->auth_size = hdr->auth_len + 8;
4060 auth_info->auth_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_auth_info,
4061 tvb, offset, auth_info->auth_size, ENC_NA);
4062 auth_info->auth_tree = proto_item_add_subtree(auth_info->auth_item, ett_dcerpc_auth_info);
4065 * Either there's no stub data, or the last byte of the stub
4066 * data is present in the captured data, so we shouldn't
4067 * get a BoundsError dissecting the stub data.
4069 * Try dissecting the authentication data.
4070 * Catch all exceptions, so that even if the auth info is bad
4071 * or we don't have all of it, we still show the stuff we
4072 * dissect after this, such as stub data.
4074 TRY {
4075 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, auth_info->auth_tree, hdr->drep,
4076 hf_dcerpc_auth_type,
4077 &auth_info->auth_type);
4078 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, auth_info->auth_tree, hdr->drep,
4079 hf_dcerpc_auth_level,
4080 &auth_info->auth_level);
4082 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, auth_info->auth_tree, hdr->drep,
4083 hf_dcerpc_auth_pad_len,
4084 &auth_info->auth_pad_len);
4085 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, auth_info->auth_tree, hdr->drep,
4086 hf_dcerpc_auth_rsrvd, NULL);
4087 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, auth_info->auth_tree, hdr->drep,
4088 hf_dcerpc_auth_ctx_id,
4089 &auth_info->auth_context_id);
4091 proto_item_append_text(auth_info->auth_item,
4092 ": %s, %s, AuthContextId(%d)",
4093 val_to_str(auth_info->auth_type,
4094 authn_protocol_vals,
4095 "AuthType(%u)"),
4096 val_to_str(auth_info->auth_level,
4097 authn_level_vals,
4098 "AuthLevel(%u)"),
4099 auth_info->auth_context_id);
4102 * Dissect the authentication data.
4104 auth_info->auth_hdr_tvb = tvb_new_subset_length_caplen(tvb, auth_offset, 8, 8);
4105 auth_info->auth_tvb = tvb_new_subset_length_caplen(tvb, offset,
4106 MIN(hdr->auth_len,tvb_reported_length_remaining(tvb, offset)),
4107 hdr->auth_len);
4109 connection = find_or_create_dcerpc_connection(pinfo);
4110 auth_context = find_or_create_dcerpc_auth_context(pinfo, auth_info);
4111 if (auth_context != NULL) {
4112 if (hdr->ptype == PDU_BIND || hdr->ptype == PDU_ALTER) {
4113 if (auth_context->first_frame == pinfo->fd->num) {
4114 auth_context->hdr_signing = (hdr->flags & PFC_HDR_SIGNING);
4115 if (auth_context->hdr_signing && connection != NULL) {
4116 connection->hdr_signing_negotiated = true;
4120 if (connection != NULL && connection->hdr_signing_negotiated) {
4121 auth_context->hdr_signing = true;
4124 auth_info->hdr_signing = auth_context->hdr_signing;
4127 auth_info->auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
4128 auth_info->auth_type);
4129 if (auth_info->auth_fns != NULL)
4130 dissect_auth_verf(pinfo, hdr, auth_info);
4131 else
4132 proto_tree_add_item(auth_info->auth_tree,
4133 hf_dcerpc_auth_credentials,
4134 auth_info->auth_tvb, 0,
4135 hdr->auth_len, ENC_NA);
4137 } CATCH_BOUNDS_ERRORS {
4138 show_exception(tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
4139 } ENDTRY;
4145 /* We need to hash in the SMB fid number to generate a unique hash table
4146 * key as DCERPC over SMB allows several pipes over the same TCP/IP
4147 * socket.
4148 * We pass this function the transport type here to make sure we only look
4149 * at this function if it came across an SMB pipe.
4150 * Other transports might need to mix in their own extra multiplexing data
4151 * as well in the future.
4154 uint64_t
4155 dcerpc_get_transport_salt(packet_info *pinfo)
4157 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
4159 switch (decode_data->dcetransporttype) {
4160 case DCE_CN_TRANSPORT_SMBPIPE:
4161 /* DCERPC over smb */
4162 return decode_data->dcetransportsalt;
4165 /* Some other transport... */
4166 return 0;
4169 void
4170 dcerpc_set_transport_salt(uint64_t dcetransportsalt, packet_info *pinfo)
4172 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
4174 decode_data->dcetransportsalt = dcetransportsalt;
4178 * Connection oriented packet types
4181 static void
4182 dissect_dcerpc_cn_bind(tvbuff_t *tvb, int offset, packet_info *pinfo,
4183 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
4185 conversation_t *conv = find_or_create_conversation(pinfo);
4186 uint8_t num_ctx_items = 0;
4187 unsigned i;
4188 uint16_t ctx_id;
4189 uint8_t num_trans_items;
4190 unsigned j;
4191 e_guid_t if_id;
4192 e_guid_t trans_id;
4193 uint32_t trans_ver;
4194 uint16_t if_ver, if_ver_minor;
4195 dcerpc_auth_info auth_info;
4196 char *uuid_str;
4197 const char *uuid_name = NULL;
4198 proto_item *iface_item = NULL;
4199 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
4201 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4202 hf_dcerpc_cn_max_xmit, NULL);
4204 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4205 hf_dcerpc_cn_max_recv, NULL);
4207 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4208 hf_dcerpc_cn_assoc_group, NULL);
4210 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4211 hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
4213 /* padding */
4214 offset += 3;
4216 col_append_fstr(pinfo->cinfo, COL_INFO, ", %u context items:", num_ctx_items);
4218 for (i = 0; i < num_ctx_items; i++) {
4219 proto_item *ctx_item = NULL;
4220 proto_tree *ctx_tree = NULL, *iface_tree = NULL;
4221 int ctx_offset = offset;
4223 dissect_dcerpc_uint16(tvb, offset, pinfo, NULL, hdr->drep,
4224 hf_dcerpc_cn_ctx_id, &ctx_id);
4226 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
4227 /* (if we have multiple contexts, this might cause "decode as"
4228 * to behave unpredictably) */
4229 decode_data->dcectxid = ctx_id;
4231 if (dcerpc_tree) {
4232 ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_item,
4233 tvb, offset, 0,
4234 ENC_NA);
4235 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
4238 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree, hdr->drep,
4239 hf_dcerpc_cn_ctx_id, &ctx_id);
4240 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, ctx_tree, hdr->drep,
4241 hf_dcerpc_cn_num_trans_items, &num_trans_items);
4243 if (dcerpc_tree) {
4244 proto_item_append_text(ctx_item, "[%u]: Context ID:%u", i+1, ctx_id);
4247 /* padding */
4248 offset += 1;
4250 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &if_id);
4251 if (ctx_tree) {
4253 iface_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_abstract_syntax, tvb, offset, 0, ENC_NA);
4254 iface_tree = proto_item_add_subtree(iface_item, ett_dcerpc_cn_iface);
4256 uuid_str = guid_to_str(pinfo->pool, (e_guid_t*)&if_id);
4257 uuid_name = guids_get_uuid_name(&if_id, pinfo->pool);
4258 if (uuid_name) {
4259 proto_tree_add_guid_format(iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
4260 offset, 16, (e_guid_t *) &if_id, "Interface: %s UUID: %s", uuid_name, uuid_str);
4261 proto_item_append_text(iface_item, ": %s", uuid_name);
4262 proto_item_append_text(ctx_item, ", %s", uuid_name);
4263 } else {
4264 proto_tree_add_guid_format(iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
4265 offset, 16, (e_guid_t *) &if_id, "Interface UUID: %s", uuid_str);
4266 proto_item_append_text(iface_item, ": %s", uuid_str);
4267 proto_item_append_text(ctx_item, ", %s", uuid_str);
4270 offset += 16;
4272 if (hdr->drep[0] & DREP_LITTLE_ENDIAN) {
4273 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
4274 hf_dcerpc_cn_bind_if_ver, &if_ver);
4275 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
4276 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
4277 } else {
4278 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
4279 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
4280 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
4281 hf_dcerpc_cn_bind_if_ver, &if_ver);
4284 if (ctx_tree) {
4285 proto_item_append_text(iface_item, " V%u.%u", if_ver, if_ver_minor);
4286 proto_item_set_len(iface_item, 20);
4289 memset(&trans_id, 0, sizeof(trans_id));
4290 for (j = 0; j < num_trans_items; j++) {
4291 proto_tree *trans_tree = NULL;
4292 proto_item *trans_item = NULL;
4294 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &trans_id);
4295 if (ctx_tree) {
4297 trans_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_trans_syntax, tvb, offset, 0, ENC_NA);
4298 trans_tree = proto_item_add_subtree(trans_item, ett_dcerpc_cn_trans_syntax);
4300 uuid_str = guid_to_str(pinfo->pool, (e_guid_t *) &trans_id);
4301 uuid_name = guids_get_uuid_name(&trans_id, pinfo->pool);
4303 /* check for [MS-RPCE] 3.3.1.5.3 Bind Time Feature Negotiation */
4304 if (trans_id.data1 == 0x6cb71c2c && trans_id.data2 == 0x9812 && trans_id.data3 == 0x4540) {
4305 proto_tree_add_guid_format(trans_tree, hf_dcerpc_cn_bind_trans_id,
4306 tvb, offset, 16, (e_guid_t *) &trans_id,
4307 "Transfer Syntax: Bind Time Feature Negotiation UUID:%s",
4308 uuid_str);
4309 proto_tree_add_bitmask(trans_tree, tvb, offset + 8,
4310 hf_dcerpc_cn_bind_trans_btfn,
4311 ett_dcerpc_cn_bind_trans_btfn,
4312 dcerpc_cn_bind_trans_btfn_fields,
4313 ENC_LITTLE_ENDIAN);
4314 proto_item_append_text(trans_item, "[%u]: Bind Time Feature Negotiation", j+1);
4315 proto_item_append_text(ctx_item, ", Bind Time Feature Negotiation");
4316 } else if (uuid_name) {
4317 proto_tree_add_guid_format(trans_tree, hf_dcerpc_cn_bind_trans_id,
4318 tvb, offset, 16, (e_guid_t *) &trans_id,
4319 "Transfer Syntax: %s UUID:%s", uuid_name, uuid_str);
4320 proto_item_append_text(trans_item, "[%u]: %s", j+1, uuid_name);
4321 proto_item_append_text(ctx_item, ", %s", uuid_name);
4322 } else {
4323 proto_tree_add_guid_format(trans_tree, hf_dcerpc_cn_bind_trans_id,
4324 tvb, offset, 16, (e_guid_t *) &trans_id,
4325 "Transfer Syntax: %s", uuid_str);
4326 proto_item_append_text(trans_item, "[%u]: %s", j+1, uuid_str);
4327 proto_item_append_text(ctx_item, ", %s", uuid_str);
4331 offset += 16;
4333 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, trans_tree, hdr->drep,
4334 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
4335 if (ctx_tree) {
4336 proto_item_set_len(trans_item, 20);
4337 proto_item_append_text(trans_item, " V%u", trans_ver);
4341 /* if this is the first time we've seen this packet, we need to
4342 update the dcerpc_binds table so that any later calls can
4343 match to the interface.
4344 XXX We assume that BINDs will NEVER be fragmented.
4346 if (!(pinfo->fd->visited)) {
4347 dcerpc_bind_key *key;
4348 dcerpc_bind_value *value;
4350 key = wmem_new(wmem_file_scope(), dcerpc_bind_key);
4351 key->conv = conv;
4352 key->ctx_id = ctx_id;
4353 key->transport_salt = dcerpc_get_transport_salt(pinfo);
4355 value = wmem_new(wmem_file_scope(), dcerpc_bind_value);
4356 value->uuid = if_id;
4357 value->ver = if_ver;
4358 value->transport = trans_id;
4360 /* add this entry to the bind table */
4361 wmem_map_insert(dcerpc_binds, key, value);
4364 if (i > 0) {
4365 col_append_str(pinfo->cinfo, COL_INFO, ",");
4367 col_append_fstr(pinfo->cinfo, COL_INFO, " %s V%u.%u (%s)",
4368 guids_resolve_guid_to_str(&if_id, pinfo->pool), if_ver, if_ver_minor,
4369 guids_resolve_guid_to_str(&trans_id, pinfo->pool));
4371 if (ctx_tree) {
4372 proto_item_set_len(ctx_item, offset - ctx_offset);
4377 * XXX - we should save the authentication type *if* we have
4378 * an authentication header, and associate it with an authentication
4379 * context, so subsequent PDUs can use that context.
4381 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, &auth_info);
4384 static void
4385 dissect_dcerpc_cn_bind_ack(tvbuff_t *tvb, int offset, packet_info *pinfo,
4386 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
4388 uint16_t max_xmit, max_recv;
4389 uint16_t sec_addr_len;
4390 uint8_t num_results;
4391 unsigned i;
4392 uint16_t result = 0;
4393 uint16_t reason = 0;
4394 e_guid_t trans_id;
4395 uint32_t trans_ver;
4396 dcerpc_auth_info auth_info;
4397 const char *uuid_name = NULL;
4398 const char *result_str = NULL;
4400 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4401 hf_dcerpc_cn_max_xmit, &max_xmit);
4403 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4404 hf_dcerpc_cn_max_recv, &max_recv);
4406 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4407 hf_dcerpc_cn_assoc_group, NULL);
4409 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4410 hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
4411 if (sec_addr_len != 0) {
4412 proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
4413 sec_addr_len, ENC_ASCII);
4414 offset += sec_addr_len;
4417 if (offset % 4) {
4418 offset += 4 - offset % 4;
4421 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4422 hf_dcerpc_cn_num_results, &num_results);
4424 /* padding */
4425 offset += 3;
4427 col_append_fstr(pinfo->cinfo, COL_INFO, ", max_xmit: %u max_recv: %u, %u results:",
4428 max_xmit, max_recv, num_results);
4430 for (i = 0; i < num_results; i++) {
4431 proto_tree *ctx_tree = NULL;
4432 proto_item *ctx_item = NULL;
4434 if (dcerpc_tree) {
4435 ctx_tree = proto_tree_add_subtree_format(dcerpc_tree, tvb, offset, 24, ett_dcerpc_cn_ctx, &ctx_item, "Ctx Item[%u]:", i+1);
4438 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree,
4439 hdr->drep, hf_dcerpc_cn_ack_result,
4440 &result);
4442 /* [MS-RPCE] 3.3.1.5.3 check if this Ctx Item is the response to a Bind Time Feature Negotiation request */
4443 if (result == 3) {
4444 proto_tree_add_bitmask(ctx_tree, tvb, offset,
4445 hf_dcerpc_cn_bind_trans_btfn,
4446 ett_dcerpc_cn_bind_trans_btfn,
4447 dcerpc_cn_bind_trans_btfn_fields,
4448 ENC_LITTLE_ENDIAN);
4449 offset += 2;
4450 } else if (result != 0) {
4451 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree,
4452 hdr->drep, hf_dcerpc_cn_ack_reason,
4453 &reason);
4454 } else {
4456 * The reason for rejection isn't meaningful, and often isn't
4457 * set, when the syntax was accepted.
4459 offset += 2;
4462 result_str = val_to_str(result, p_cont_result_vals, "Unknown result (%u)");
4464 if (ctx_tree) {
4465 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &trans_id);
4466 uuid_name = guids_get_uuid_name(&trans_id, pinfo->pool);
4467 if (! uuid_name) {
4468 uuid_name = guid_to_str(pinfo->pool, (e_guid_t *) &trans_id);
4470 proto_tree_add_guid_format(ctx_tree, hf_dcerpc_cn_ack_trans_id, tvb,
4471 offset, 16, (e_guid_t *) &trans_id, "Transfer Syntax: %s",
4472 uuid_name);
4473 proto_item_append_text(ctx_item, " %s, %s", result_str, uuid_name);
4475 offset += 16;
4477 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, ctx_tree, hdr->drep,
4478 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
4480 if (i > 0) {
4481 col_append_str(pinfo->cinfo, COL_INFO, ",");
4483 col_append_fstr(pinfo->cinfo, COL_INFO, " %s", result_str);
4487 * XXX - do we need to do anything with the authentication level
4488 * we get back from this?
4490 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, &auth_info);
4493 static void
4494 dissect_dcerpc_cn_bind_nak(tvbuff_t *tvb, int offset, packet_info *pinfo,
4495 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
4497 uint16_t reason;
4498 uint8_t num_protocols;
4499 unsigned i;
4501 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
4502 hdr->drep, hf_dcerpc_cn_reject_reason,
4503 &reason);
4505 col_append_fstr(pinfo->cinfo, COL_INFO, " reason: %s",
4506 val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
4508 if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
4509 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4510 hf_dcerpc_cn_num_protocols,
4511 &num_protocols);
4513 for (i = 0; i < num_protocols; i++) {
4514 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
4515 hdr->drep, hf_dcerpc_cn_protocol_ver_major,
4516 NULL);
4517 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
4518 hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
4519 NULL);
4524 /* Return a string describing a DCE/RPC fragment as first, middle, or end
4525 fragment. */
4527 #define PFC_FRAG_MASK 0x03
4529 static const char *
4530 fragment_type(uint8_t flags)
4532 static const char* t[4] = {
4533 "Mid",
4534 "1st",
4535 "Last",
4536 "Single"
4538 return t[flags & PFC_FRAG_MASK];
4541 /* Dissect stub data (payload) of a DCERPC packet. */
4543 static void
4544 dissect_dcerpc_cn_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
4545 proto_tree *dcerpc_tree, proto_tree *tree,
4546 e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
4547 dcerpc_auth_info *auth_info, uint32_t alloc_hint _U_,
4548 uint32_t frame)
4550 int length, reported_length;
4551 bool save_fragmented;
4552 fragment_head *fd_head = NULL;
4554 tvbuff_t *header_tvb = NULL, *trailer_tvb = NULL;
4555 tvbuff_t *payload_tvb, *decrypted_tvb = NULL;
4556 proto_item *pi;
4557 proto_item *parent_pi;
4558 proto_item *dcerpc_tree_item;
4560 save_fragmented = pinfo->fragmented;
4562 length = tvb_reported_length_remaining(tvb, offset);
4563 reported_length = tvb_reported_length_remaining(tvb, offset);
4564 if (reported_length < 0 ||
4565 (uint32_t)reported_length < auth_info->auth_size) {
4566 /* We don't even have enough bytes for the authentication
4567 stuff. */
4568 return;
4570 reported_length -= auth_info->auth_size;
4571 if (length > reported_length)
4572 length = reported_length;
4573 header_tvb = tvb_new_subset_length_caplen(tvb, 0, offset, offset);
4574 payload_tvb = tvb_new_subset_length_caplen(tvb, offset, length, reported_length);
4575 trailer_tvb = auth_info->auth_hdr_tvb;
4577 /* Decrypt the PDU if it is encrypted */
4579 if (auth_info->auth_type &&
4580 (auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)) {
4582 /* Start out assuming we won't succeed in decrypting. */
4584 if (auth_info->auth_fns != NULL) {
4585 tvbuff_t *result;
4587 result = decode_encrypted_data(header_tvb, payload_tvb, trailer_tvb,
4588 pinfo, hdr, auth_info);
4589 if (result) {
4590 proto_tree_add_item(dcerpc_tree, hf_dcerpc_encrypted_stub_data, payload_tvb, 0, -1, ENC_NA);
4592 add_new_data_source(
4593 pinfo, result, "Decrypted stub data");
4595 /* We succeeded. */
4596 decrypted_tvb = result;
4599 } else
4600 decrypted_tvb = payload_tvb;
4602 /* if this packet is not fragmented, just dissect it and exit */
4603 if (PFC_NOT_FRAGMENTED(hdr)) {
4604 pinfo->fragmented = false;
4606 dcerpc_try_handoff(pinfo, tree, dcerpc_tree,
4607 ((decrypted_tvb != NULL) ? decrypted_tvb : payload_tvb),
4608 ((decrypted_tvb != NULL) ? true : false),
4609 hdr->drep, di, auth_info);
4611 pinfo->fragmented = save_fragmented;
4612 return;
4615 /* The packet is fragmented. */
4616 pinfo->fragmented = true;
4618 /* debug output of essential fragment data. */
4619 /* leave it here for future debugging sessions */
4620 /*printf("DCE num:%u offset:%u frag_len:%u tvb_len:%u\n",
4621 pinfo->num, offset, hdr->frag_len, tvb_reported_length(decrypted_tvb));*/
4623 /* if we are not doing reassembly and this is the first fragment
4624 then just dissect it and exit
4625 XXX - if we're not doing reassembly, can we decrypt an
4626 encrypted stub?
4628 if ( (!dcerpc_reassemble) && (hdr->flags & PFC_FIRST_FRAG) ) {
4630 dcerpc_try_handoff(pinfo, tree, dcerpc_tree,
4631 ((decrypted_tvb != NULL) ? decrypted_tvb : payload_tvb),
4632 ((decrypted_tvb != NULL) ? true : false),
4633 hdr->drep, di, auth_info);
4635 expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment, "%s fragment", fragment_type(hdr->flags));
4637 pinfo->fragmented = save_fragmented;
4638 return;
4641 /* if we have already seen this packet, see if it was reassembled
4642 and if so dissect the full pdu.
4643 then exit
4645 if (pinfo->fd->visited) {
4646 fd_head = fragment_get_reassembled_id(&dcerpc_co_reassembly_table, pinfo, frame);
4647 goto end_cn_stub;
4650 /* if we are not doing reassembly and it was neither a complete PDU
4651 nor the first fragment then there is nothing more we can do
4652 so we just have to exit
4654 if ( !dcerpc_reassemble || (tvb_captured_length(tvb) != tvb_reported_length(tvb)) )
4655 goto end_cn_stub;
4657 /* if we didn't get 'frame' we don't know where the PDU started and thus
4658 it is pointless to continue
4660 if (!frame)
4661 goto end_cn_stub;
4663 /* from now on we must attempt to reassemble the PDU
4666 /* if we get here we know it is the first time we see the packet
4667 and we also know it is only a fragment and not a full PDU,
4668 thus we must reassemble it.
4671 /* Do we have any non-encrypted data to reassemble? */
4672 if (decrypted_tvb == NULL) {
4673 /* No. We can't even try to reassemble. */
4674 goto end_cn_stub;
4677 /* defragmentation is a bit tricky, as there's no offset of the fragment
4678 * in the protocol data.
4680 * just use fragment_add_seq_next() and hope that TCP/SMB segments coming
4681 * in with the correct sequence.
4683 fd_head = fragment_add_seq_next(&dcerpc_co_reassembly_table,
4684 decrypted_tvb, 0, pinfo, frame, NULL,
4685 tvb_reported_length(decrypted_tvb),
4686 !(hdr->flags & PFC_LAST_FRAG) /* more_frags */);
4688 end_cn_stub:
4690 /* if reassembly is complete and this is the last fragment
4691 * (multiple fragments in one PDU are possible!)
4692 * dissect the full PDU
4694 if (fd_head && (fd_head->flags & FD_DEFRAGMENTED) ) {
4696 if ((pinfo->num == fd_head->reassembled_in) && (hdr->flags & PFC_LAST_FRAG) ) {
4697 tvbuff_t *next_tvb;
4698 proto_item *frag_tree_item;
4700 next_tvb = tvb_new_chain((decrypted_tvb)?decrypted_tvb:payload_tvb,
4701 fd_head->tvb_data);
4703 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
4704 show_fragment_tree(fd_head, &dcerpc_frag_items,
4705 tree, pinfo, next_tvb, &frag_tree_item);
4706 /* the toplevel fragment subtree is now behind all desegmented data,
4707 * move it right behind the DCE/RPC tree */
4708 dcerpc_tree_item = proto_tree_get_parent(dcerpc_tree);
4709 if (frag_tree_item && dcerpc_tree_item) {
4710 proto_tree_move_item(tree, dcerpc_tree_item, frag_tree_item);
4713 pinfo->fragmented = false;
4715 expert_add_info_format(pinfo, frag_tree_item, &ei_dcerpc_fragment_reassembled, "%s fragment, reassembled", fragment_type(hdr->flags));
4717 dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb, true, hdr->drep, di, auth_info);
4719 } else {
4720 if (decrypted_tvb) {
4721 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
4722 decrypted_tvb, 0, 0, fd_head->reassembled_in);
4723 } else {
4724 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
4725 payload_tvb, 0, 0, fd_head->reassembled_in);
4727 proto_item_set_generated(pi);
4728 parent_pi = proto_tree_get_parent(dcerpc_tree);
4729 if (parent_pi != NULL) {
4730 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
4732 col_append_fstr(pinfo->cinfo, COL_INFO,
4733 " [DCE/RPC %s fragment, reas: #%u]", fragment_type(hdr->flags), fd_head->reassembled_in);
4734 expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment_reassembled, "%s fragment, reassembled in #%u", fragment_type(hdr->flags), fd_head->reassembled_in);
4736 } else {
4737 /* Reassembly not complete - some fragments
4738 are missing. Just show the stub data. */
4739 expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment, "%s fragment", fragment_type(hdr->flags));
4741 if (decrypted_tvb) {
4742 show_stub_data(pinfo, decrypted_tvb, 0, tree, auth_info, false);
4743 } else {
4744 show_stub_data(pinfo, payload_tvb, 0, tree, auth_info, true);
4748 pinfo->fragmented = save_fragmented;
4751 static void
4752 dissect_dcerpc_cn_rqst(tvbuff_t *tvb, int offset, packet_info *pinfo,
4753 proto_tree *dcerpc_tree, proto_tree *tree,
4754 e_dce_cn_common_hdr_t *hdr)
4756 conversation_t *conv;
4757 uint16_t ctx_id;
4758 uint16_t opnum;
4759 e_guid_t obj_id = DCERPC_UUID_NULL;
4760 dcerpc_auth_info auth_info;
4761 uint32_t alloc_hint;
4762 proto_item *pi;
4763 proto_item *parent_pi;
4764 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
4766 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4767 hf_dcerpc_cn_alloc_hint, &alloc_hint);
4769 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4770 hf_dcerpc_cn_ctx_id, &ctx_id);
4771 parent_pi = proto_tree_get_parent(dcerpc_tree);
4772 if (parent_pi != NULL) {
4773 proto_item_append_text(parent_pi, ", Ctx: %u", ctx_id);
4776 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4777 hf_dcerpc_opnum, &opnum);
4779 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
4780 decode_data->dcectxid = ctx_id;
4782 col_append_fstr(pinfo->cinfo, COL_INFO, ", opnum: %u, Ctx: %u",
4783 opnum, ctx_id);
4785 if (hdr->flags & PFC_OBJECT_UUID) {
4786 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &obj_id);
4787 if (dcerpc_tree) {
4788 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
4789 offset, 16, (e_guid_t *) &obj_id, "Object UUID: %s",
4790 guid_to_str(pinfo->pool, (e_guid_t *) &obj_id));
4792 offset += 16;
4796 * XXX - what if this was set when the connection was set up,
4797 * and we just have a security context?
4799 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, &auth_info);
4801 conv = find_conversation_pinfo(pinfo, 0);
4802 if (!conv)
4803 show_stub_data(pinfo, tvb, offset, dcerpc_tree, &auth_info, true);
4804 else {
4805 dcerpc_matched_key matched_key, *new_matched_key;
4806 dcerpc_call_value *value;
4808 /* !!! we can NOT check visited here since this will interact
4809 badly with when SMB handles (i.e. calls the subdissector)
4810 and desegmented pdu's .
4811 Instead we check if this pdu is already in the matched table or not
4813 matched_key.frame = pinfo->num;
4814 matched_key.call_id = hdr->call_id;
4815 value = (dcerpc_call_value *)wmem_map_lookup(dcerpc_matched, &matched_key);
4816 if (!value) {
4817 dcerpc_bind_key bind_key;
4818 dcerpc_bind_value *bind_value;
4820 bind_key.conv = conv;
4821 bind_key.ctx_id = ctx_id;
4822 bind_key.transport_salt = dcerpc_get_transport_salt(pinfo);
4824 if ((bind_value = (dcerpc_bind_value *)wmem_map_lookup(dcerpc_binds, &bind_key)) ) {
4825 if (!(hdr->flags&PFC_FIRST_FRAG)) {
4826 dcerpc_cn_call_key call_key;
4827 dcerpc_call_value *call_value;
4829 call_key.conv = conv;
4830 call_key.call_id = hdr->call_id;
4831 call_key.transport_salt = dcerpc_get_transport_salt(pinfo);
4832 if ((call_value = (dcerpc_call_value *)wmem_map_lookup(dcerpc_cn_calls, &call_key))) {
4833 new_matched_key = wmem_new(wmem_file_scope(), dcerpc_matched_key);
4834 *new_matched_key = matched_key;
4835 wmem_map_insert(dcerpc_matched, new_matched_key, call_value);
4836 value = call_value;
4838 } else {
4839 dcerpc_cn_call_key *call_key;
4840 dcerpc_call_value *call_value;
4842 /* We found the binding and it is the first fragment
4843 (or a complete PDU) of a dcerpc pdu so just add
4844 the call to both the call table and the
4845 matched table
4847 call_key = wmem_new(wmem_file_scope(), dcerpc_cn_call_key);
4848 call_key->conv = conv;
4849 call_key->call_id = hdr->call_id;
4850 call_key->transport_salt = dcerpc_get_transport_salt(pinfo);
4852 /* if there is already a matching call in the table
4853 remove it so it is replaced with the new one */
4854 if (wmem_map_lookup(dcerpc_cn_calls, call_key)) {
4855 wmem_map_remove(dcerpc_cn_calls, call_key);
4858 call_value = wmem_new(wmem_file_scope(), dcerpc_call_value);
4859 call_value->uuid = bind_value->uuid;
4860 call_value->ver = bind_value->ver;
4861 call_value->object_uuid = obj_id;
4862 call_value->opnum = opnum;
4863 call_value->req_frame = pinfo->num;
4864 call_value->req_time = pinfo->abs_ts;
4865 call_value->rep_frame = 0;
4866 call_value->max_ptr = 0;
4867 call_value->se_data = NULL;
4868 call_value->private_data = NULL;
4869 call_value->pol = NULL;
4870 call_value->flags = 0;
4871 if (!memcmp(&bind_value->transport, &uuid_ndr64, sizeof(uuid_ndr64))) {
4872 call_value->flags |= DCERPC_IS_NDR64;
4875 wmem_map_insert(dcerpc_cn_calls, call_key, call_value);
4877 new_matched_key = wmem_new(wmem_file_scope(), dcerpc_matched_key);
4878 *new_matched_key = matched_key;
4879 wmem_map_insert(dcerpc_matched, new_matched_key, call_value);
4880 value = call_value;
4885 if (value) {
4886 dcerpc_info *di;
4888 di = wmem_new0(pinfo->pool, dcerpc_info);
4889 /* handoff this call */
4890 di->dcerpc_procedure_name = "";
4891 di->conv = conv;
4892 di->call_id = hdr->call_id;
4893 di->transport_salt = dcerpc_get_transport_salt(pinfo);
4894 di->ptype = PDU_REQ;
4895 di->call_data = value;
4896 di->hf_index = -1;
4898 if (value->rep_frame != 0) {
4899 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
4900 tvb, 0, 0, value->rep_frame);
4901 proto_item_set_generated(pi);
4902 if (parent_pi != NULL) {
4903 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
4907 dissect_dcerpc_cn_stub(tvb, offset, pinfo, dcerpc_tree, tree,
4908 hdr, di, &auth_info, alloc_hint,
4909 value->req_frame);
4910 } else {
4911 /* no bind information, simply show stub data */
4912 proto_tree_add_expert_format(dcerpc_tree, pinfo, &ei_dcerpc_cn_ctx_id_no_bind, tvb, offset, 0, "No bind info for interface Context ID %u - capture start too late?", ctx_id);
4913 show_stub_data(pinfo, tvb, offset, dcerpc_tree, &auth_info, true);
4918 * Move the auth_info subtree to the end,
4919 * as it's also at the end of the pdu on the wire.
4921 dissect_dcerpc_cn_auth_move(&auth_info, dcerpc_tree);
4924 static void
4925 dissect_dcerpc_cn_resp(tvbuff_t *tvb, int offset, packet_info *pinfo,
4926 proto_tree *dcerpc_tree, proto_tree *tree,
4927 e_dce_cn_common_hdr_t *hdr)
4929 dcerpc_call_value *value = NULL;
4930 conversation_t *conv;
4931 uint16_t ctx_id;
4932 dcerpc_auth_info auth_info;
4933 uint32_t alloc_hint;
4934 proto_item *pi;
4935 proto_item *parent_pi;
4936 e_guid_t obj_id_null = DCERPC_UUID_NULL;
4937 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
4939 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4940 hf_dcerpc_cn_alloc_hint, &alloc_hint);
4942 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4943 hf_dcerpc_cn_ctx_id, &ctx_id);
4944 parent_pi = proto_tree_get_parent(dcerpc_tree);
4945 if (parent_pi != NULL) {
4946 proto_item_append_text(parent_pi, ", Ctx: %u", ctx_id);
4949 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
4950 decode_data->dcectxid = ctx_id;
4952 col_append_fstr(pinfo->cinfo, COL_INFO, ", Ctx: %u", ctx_id);
4954 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4955 hf_dcerpc_cn_cancel_count, NULL);
4956 /* padding */
4957 offset++;
4960 * XXX - what if this was set when the connection was set up,
4961 * and we just have a security context?
4963 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, &auth_info);
4965 conv = find_conversation_pinfo(pinfo, 0);
4967 if (!conv) {
4968 /* no point in creating one here, really */
4969 show_stub_data(pinfo, tvb, offset, dcerpc_tree, &auth_info, true);
4970 } else {
4971 dcerpc_matched_key matched_key, *new_matched_key;
4973 /* !!! we can NOT check visited here since this will interact
4974 badly with when SMB handles (i.e. calls the subdissector)
4975 and desegmented pdu's .
4976 Instead we check if this pdu is already in the matched table or not
4978 matched_key.frame = pinfo->num;
4979 matched_key.call_id = hdr->call_id;
4980 value = (dcerpc_call_value *)wmem_map_lookup(dcerpc_matched, &matched_key);
4981 if (!value) {
4982 dcerpc_cn_call_key call_key;
4983 dcerpc_call_value *call_value;
4985 call_key.conv = conv;
4986 call_key.call_id = hdr->call_id;
4987 call_key.transport_salt = dcerpc_get_transport_salt(pinfo);
4989 if ((call_value = (dcerpc_call_value *)wmem_map_lookup(dcerpc_cn_calls, &call_key))) {
4990 /* extra sanity check, only match them if the reply
4991 came after the request */
4992 if (call_value->req_frame<pinfo->num) {
4993 new_matched_key = wmem_new(wmem_file_scope(), dcerpc_matched_key);
4994 *new_matched_key = matched_key;
4995 wmem_map_insert(dcerpc_matched, new_matched_key, call_value);
4996 value = call_value;
4997 if (call_value->rep_frame == 0) {
4998 call_value->rep_frame = pinfo->num;
5004 if (value) {
5005 dcerpc_info *di;
5007 di = wmem_new0(pinfo->pool, dcerpc_info);
5008 /* handoff this call */
5009 di->dcerpc_procedure_name = "";
5010 di->conv = conv;
5011 di->call_id = hdr->call_id;
5012 di->transport_salt = dcerpc_get_transport_salt(pinfo);
5013 di->ptype = PDU_RESP;
5014 di->call_data = value;
5016 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
5017 proto_item_set_generated(pi);
5019 /* (optional) "Object UUID" from request */
5020 if (dcerpc_tree && (memcmp(&value->object_uuid, &obj_id_null, sizeof(obj_id_null)) != 0)) {
5021 pi = proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
5022 offset, 0, (e_guid_t *) &value->object_uuid, "Object UUID: %s",
5023 guid_to_str(pinfo->pool, (e_guid_t *) &value->object_uuid));
5024 proto_item_set_generated(pi);
5027 /* request in */
5028 if (value->req_frame != 0) {
5029 nstime_t delta_ts;
5030 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
5031 tvb, 0, 0, value->req_frame);
5032 proto_item_set_generated(pi);
5033 if (parent_pi != NULL) {
5034 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
5036 nstime_delta(&delta_ts, &pinfo->abs_ts, &value->req_time);
5037 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
5038 proto_item_set_generated(pi);
5039 } else {
5040 proto_tree_add_expert(dcerpc_tree, pinfo, &ei_dcerpc_no_request_found, tvb, 0, 0);
5043 dissect_dcerpc_cn_stub(tvb, offset, pinfo, dcerpc_tree, tree,
5044 hdr, di, &auth_info, alloc_hint,
5045 value->rep_frame);
5046 } else {
5047 /* no bind information, simply show stub data */
5048 proto_tree_add_expert_format(dcerpc_tree, pinfo, &ei_dcerpc_cn_ctx_id_no_bind, tvb, offset, 0, "No bind info for interface Context ID %u - capture start too late?", ctx_id);
5049 show_stub_data(pinfo, tvb, offset, dcerpc_tree, &auth_info, true);
5054 * Move the auth_info subtree to the end,
5055 * as it's also at the end of the pdu on the wire.
5057 dissect_dcerpc_cn_auth_move(&auth_info, dcerpc_tree);
5060 static void
5061 dissect_dcerpc_cn_fault(tvbuff_t *tvb, int offset, packet_info *pinfo,
5062 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
5064 dcerpc_call_value *value = NULL;
5065 conversation_t *conv;
5066 uint16_t ctx_id;
5067 uint32_t status;
5068 uint32_t alloc_hint;
5069 dcerpc_auth_info auth_info;
5070 int length, reported_length;
5071 tvbuff_t *stub_tvb = NULL;
5072 proto_item *pi = NULL;
5073 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
5075 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
5076 hf_dcerpc_cn_alloc_hint, &alloc_hint);
5078 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
5079 hf_dcerpc_cn_ctx_id, &ctx_id);
5081 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
5082 hf_dcerpc_cn_cancel_count, NULL);
5083 proto_tree_add_bitmask(dcerpc_tree, tvb, offset,
5084 hf_dcerpc_cn_fault_flags,
5085 ett_dcerpc_fault_flags,
5086 dcerpc_cn_fault_flags_fields,
5087 DREP_ENC_INTEGER(hdr->drep));
5088 offset += 1;
5090 #if 0
5091 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
5092 hf_dcerpc_cn_status, &status);
5093 #endif
5094 status = ((hdr->drep[0] & DREP_LITTLE_ENDIAN)
5095 ? tvb_get_letohl(tvb, offset)
5096 : tvb_get_ntohl(tvb, offset));
5098 pi = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_status, tvb, offset, 4, DREP_ENC_INTEGER(hdr->drep));
5099 offset+=4;
5101 expert_add_info_format(pinfo, pi, &ei_dcerpc_cn_status, "Fault: %s", val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
5103 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
5104 decode_data->dcectxid = ctx_id;
5106 col_append_fstr(pinfo->cinfo, COL_INFO,
5107 ", Ctx: %u, status: %s", ctx_id,
5108 val_to_str(status, reject_status_vals,
5109 "Unknown (0x%08x)"));
5111 /* padding */
5112 proto_tree_add_item(dcerpc_tree, hf_dcerpc_reserved, tvb, offset, 4, ENC_NA);
5113 offset += 4;
5116 * XXX - what if this was set when the connection was set up,
5117 * and we just have a security context?
5119 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, &auth_info);
5121 length = tvb_captured_length_remaining(tvb, offset);
5122 reported_length = tvb_reported_length_remaining(tvb, offset);
5123 if (reported_length < 0 ||
5124 (uint32_t)reported_length < auth_info.auth_size) {
5125 /* We don't even have enough bytes for the authentication
5126 stuff. */
5127 return;
5129 reported_length -= auth_info.auth_size;
5130 if (length > reported_length)
5131 length = reported_length;
5132 stub_tvb = tvb_new_subset_length_caplen(tvb, offset, length, reported_length);
5134 conv = find_conversation_pinfo(pinfo, 0);
5135 if (!conv) {
5136 /* no point in creating one here, really */
5137 } else {
5138 dcerpc_matched_key matched_key, *new_matched_key;
5140 /* !!! we can NOT check visited here since this will interact
5141 badly with when SMB handles (i.e. calls the subdissector)
5142 and desegmented pdu's .
5143 Instead we check if this pdu is already in the matched table or not
5145 matched_key.frame = pinfo->num;
5146 matched_key.call_id = hdr->call_id;
5147 value = (dcerpc_call_value *)wmem_map_lookup(dcerpc_matched, &matched_key);
5148 if (!value) {
5149 dcerpc_cn_call_key call_key;
5150 dcerpc_call_value *call_value;
5152 call_key.conv = conv;
5153 call_key.call_id = hdr->call_id;
5154 call_key.transport_salt = dcerpc_get_transport_salt(pinfo);
5156 if ((call_value = (dcerpc_call_value *)wmem_map_lookup(dcerpc_cn_calls, &call_key))) {
5157 new_matched_key = wmem_new(wmem_file_scope(), dcerpc_matched_key);
5158 *new_matched_key = matched_key;
5159 wmem_map_insert(dcerpc_matched, new_matched_key, call_value);
5161 value = call_value;
5162 if (call_value->rep_frame == 0) {
5163 call_value->rep_frame = pinfo->num;
5169 if (value) {
5170 proto_tree *stub_tree = NULL;
5171 int stub_length;
5172 dcerpc_info *di;
5173 proto_item *parent_pi;
5175 di = wmem_new0(pinfo->pool, dcerpc_info);
5176 /* handoff this call */
5177 di->dcerpc_procedure_name = "";
5178 di->conv = conv;
5179 di->call_id = hdr->call_id;
5180 di->transport_salt = dcerpc_get_transport_salt(pinfo);
5181 di->ptype = PDU_FAULT;
5182 di->call_data = value;
5184 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
5185 proto_item_set_generated(pi);
5186 if (value->req_frame != 0) {
5187 nstime_t delta_ts;
5188 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
5189 tvb, 0, 0, value->req_frame);
5190 proto_item_set_generated(pi);
5191 parent_pi = proto_tree_get_parent(dcerpc_tree);
5192 if (parent_pi != NULL) {
5193 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
5195 nstime_delta(&delta_ts, &pinfo->abs_ts, &value->req_time);
5196 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
5197 proto_item_set_generated(pi);
5198 } else {
5199 proto_tree_add_expert(dcerpc_tree, pinfo, &ei_dcerpc_no_request_found, tvb, 0, 0);
5202 length = tvb_reported_length_remaining(stub_tvb, 0);
5203 /* as we now create a tvb in dissect_dcerpc_cn() containing only the
5204 * stub_data, the following calculation is no longer valid:
5205 * stub_length = hdr->frag_len - offset - auth_info.auth_size;
5206 * simply use the remaining length of the tvb instead.
5207 * XXX - or better use the reported_length?!?
5209 stub_length = length;
5211 stub_tree = proto_tree_add_subtree_format(dcerpc_tree,
5212 stub_tvb, 0, stub_length,
5213 ett_dcerpc_fault_stub_data, NULL,
5214 "Fault stub data (%d byte%s)", stub_length,
5215 plurality(stub_length, "", "s"));
5217 /* If we don't have reassembly enabled, or this packet contains
5218 the entire PDU, or if we don't have all the data in this
5219 fragment, just call the handoff directly if this is the
5220 first fragment or the PDU isn't fragmented. */
5221 if ( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
5222 !tvb_bytes_exist(stub_tvb, 0, stub_length) ) {
5223 if (hdr->flags&PFC_FIRST_FRAG) {
5224 /* First fragment, possibly the only fragment */
5226 * XXX - should there be a third routine for each
5227 * function in an RPC subdissector, to handle
5228 * fault responses? The DCE RPC 1.1 spec says
5229 * three's "stub data" here, which I infer means
5230 * that it's protocol-specific and call-specific.
5232 * It should probably get passed the status code
5233 * as well, as that might be protocol-specific.
5235 if (stub_length > 0) {
5236 proto_tree_add_item(stub_tree, hf_dcerpc_fault_stub_data, stub_tvb, 0, stub_length, ENC_NA);
5238 } else {
5239 /* PDU is fragmented and this isn't the first fragment */
5240 if (stub_length > 0) {
5241 proto_tree_add_item(stub_tree, hf_dcerpc_fragment_data, stub_tvb, 0, stub_length, ENC_NA);
5244 } else {
5245 /* Reassembly is enabled, the PDU is fragmented, and
5246 we have all the data in the fragment; the first two
5247 of those mean we should attempt reassembly, and the
5248 third means we can attempt reassembly. */
5249 if (dcerpc_tree) {
5250 if (length > 0) {
5251 proto_tree_add_item(stub_tree, hf_dcerpc_fragment_data, stub_tvb, 0, stub_length, ENC_NA);
5254 if (hdr->flags&PFC_FIRST_FRAG) { /* FIRST fragment */
5255 if ( (!pinfo->fd->visited) && value->rep_frame ) {
5256 fragment_add_seq_next(&dcerpc_co_reassembly_table,
5257 stub_tvb, 0,
5258 pinfo, value->rep_frame, NULL,
5259 stub_length,
5260 true);
5262 } else if (hdr->flags&PFC_LAST_FRAG) { /* LAST fragment */
5263 if ( value->rep_frame ) {
5264 fragment_head *fd_head;
5266 fd_head = fragment_add_seq_next(&dcerpc_co_reassembly_table,
5267 stub_tvb, 0,
5268 pinfo, value->rep_frame, NULL,
5269 stub_length,
5270 true);
5272 if (fd_head) {
5273 /* We completed reassembly */
5274 tvbuff_t *next_tvb;
5275 proto_item *frag_tree_item;
5277 next_tvb = tvb_new_chain(stub_tvb, fd_head->tvb_data);
5278 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
5279 show_fragment_tree(fd_head, &dcerpc_frag_items,
5280 dcerpc_tree, pinfo, next_tvb, &frag_tree_item);
5283 * XXX - should there be a third routine for each
5284 * function in an RPC subdissector, to handle
5285 * fault responses? The DCE RPC 1.1 spec says
5286 * three's "stub data" here, which I infer means
5287 * that it's protocol-specific and call-specific.
5289 * It should probably get passed the status code
5290 * as well, as that might be protocol-specific.
5292 if (dcerpc_tree) {
5293 if (length > 0) {
5294 proto_tree_add_item(dcerpc_tree, hf_dcerpc_stub_data, stub_tvb, 0, stub_length, ENC_NA);
5299 } else { /* MIDDLE fragment(s) */
5300 if ( (!pinfo->fd->visited) && value->rep_frame ) {
5301 fragment_add_seq_next(&dcerpc_co_reassembly_table,
5302 stub_tvb, 0,
5303 pinfo, value->rep_frame, NULL,
5304 stub_length,
5305 true);
5313 * Move the auth_info subtree to the end,
5314 * as it's also at the end of the pdu on the wire.
5316 dissect_dcerpc_cn_auth_move(&auth_info, dcerpc_tree);
5319 static void
5320 dissect_dcerpc_cn_rts(tvbuff_t *tvb, int offset, packet_info *pinfo,
5321 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
5323 proto_item *tf = NULL;
5324 proto_item *parent_pi = NULL;
5325 proto_tree *cn_rts_pdu_tree = NULL;
5326 uint16_t rts_flags;
5327 uint16_t commands_nb = 0;
5328 uint32_t *cmd;
5329 uint32_t i;
5330 const char *info_str = NULL;
5331 static int * const flags[] = {
5332 &hf_dcerpc_cn_rts_flags_ping,
5333 &hf_dcerpc_cn_rts_flags_other_cmd,
5334 &hf_dcerpc_cn_rts_flags_recycle_channel,
5335 &hf_dcerpc_cn_rts_flags_in_channel,
5336 &hf_dcerpc_cn_rts_flags_out_channel,
5337 &hf_dcerpc_cn_rts_flags_eof,
5338 NULL
5341 /* Dissect specific RTS header */
5342 rts_flags = dcerpc_tvb_get_ntohs(tvb, offset, hdr->drep);
5343 proto_tree_add_bitmask_value_with_flags(dcerpc_tree, tvb, offset, hf_dcerpc_cn_rts_flags,
5344 ett_dcerpc_cn_rts_flags, flags, rts_flags, BMT_NO_APPEND);
5345 offset += 2;
5347 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
5348 hf_dcerpc_cn_rts_commands_nb, &commands_nb);
5350 /* Create the RTS PDU tree - we do not yet know its name */
5351 cn_rts_pdu_tree = proto_tree_add_subtree_format(dcerpc_tree, tvb, offset, -1, ett_dcerpc_cn_rts_pdu, &tf, "RTS PDU: %u commands", commands_nb);
5353 cmd = (uint32_t *)wmem_alloc(pinfo->pool, sizeof (uint32_t) * (commands_nb + 1));
5355 /* Dissect commands */
5356 for (i = 0; i < commands_nb; ++i) {
5357 proto_tree *cn_rts_command_tree = NULL;
5358 const uint32_t command = dcerpc_tvb_get_ntohl(tvb, offset, hdr->drep);
5359 cmd[i] = command;
5360 tf = proto_tree_add_uint(cn_rts_pdu_tree, hf_dcerpc_cn_rts_command, tvb, offset, 4, command);
5361 cn_rts_command_tree = proto_item_add_subtree(tf, ett_dcerpc_cn_rts_command);
5362 offset += 4;
5363 switch (command) {
5364 case RTS_CMD_RECEIVEWINDOWSIZE:
5365 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_receivewindowsize, NULL);
5366 break;
5367 case RTS_CMD_FLOWCONTROLACK:
5368 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_fack_bytesreceived, NULL);
5369 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_fack_availablewindow, NULL);
5370 offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_fack_channelcookie, NULL);
5371 break;
5372 case RTS_CMD_CONNECTIONTIMEOUT:
5373 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_connectiontimeout, NULL);
5374 break;
5375 case RTS_CMD_COOKIE:
5376 offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_cookie, NULL);
5377 break;
5378 case RTS_CMD_CHANNELLIFETIME:
5379 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_channellifetime, NULL);
5380 break;
5381 case RTS_CMD_CLIENTKEEPALIVE:
5382 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_clientkeepalive, NULL);
5383 break;
5384 case RTS_CMD_VERSION:
5385 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_version, NULL);
5386 break;
5387 case RTS_CMD_EMPTY:
5388 break;
5389 case RTS_CMD_PADDING: {
5390 uint8_t *padding;
5391 const uint32_t conformance_count = dcerpc_tvb_get_ntohl(tvb, offset, hdr->drep);
5392 proto_tree_add_uint(cn_rts_command_tree, hf_dcerpc_cn_rts_command_conformancecount, tvb, offset, 4, conformance_count);
5393 offset += 4;
5394 padding = (uint8_t *)tvb_memdup(pinfo->pool, tvb, offset, conformance_count);
5395 proto_tree_add_bytes(cn_rts_command_tree, hf_dcerpc_cn_rts_command_padding, tvb, offset, conformance_count, padding);
5396 offset += conformance_count;
5397 } break;
5398 case RTS_CMD_NEGATIVEANCE:
5399 break;
5400 case RTS_CMD_ANCE:
5401 break;
5402 case RTS_CMD_CLIENTADDRESS: {
5403 uint8_t *padding;
5404 const uint32_t addrtype = dcerpc_tvb_get_ntohl(tvb, offset, hdr->drep);
5405 proto_tree_add_uint(cn_rts_command_tree, hf_dcerpc_cn_rts_command_addrtype, tvb, offset, 4, addrtype);
5406 offset += 4;
5407 switch (addrtype) {
5408 case RTS_IPV4: {
5409 const uint32_t addr4 = tvb_get_ipv4(tvb, offset);
5410 proto_tree_add_ipv4_format_value(cn_rts_command_tree, hf_dcerpc_cmd_client_ipv4, tvb, offset, 4, addr4, "%s", get_hostname(addr4));
5411 offset += 4;
5412 } break;
5413 case RTS_IPV6: {
5414 ws_in6_addr addr6;
5415 tvb_get_ipv6(tvb, offset, &addr6);
5416 proto_tree_add_ipv6_format_value(cn_rts_command_tree, hf_dcerpc_cmd_client_ipv6, tvb, offset, 16, &addr6, "%s", get_hostname6(&addr6));
5417 offset += 16;
5418 } break;
5420 padding = (uint8_t *)tvb_memdup(pinfo->pool, tvb, offset, 12);
5421 proto_tree_add_bytes(cn_rts_command_tree, hf_dcerpc_cn_rts_command_padding, tvb, offset, 12, padding);
5422 offset += 12;
5423 } break;
5424 case RTS_CMD_ASSOCIATIONGROUPID:
5425 offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_associationgroupid, NULL);
5426 break;
5427 case RTS_CMD_DESTINATION:
5428 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_forwarddestination, NULL);
5429 break;
5430 case RTS_CMD_PINGTRAFFICSENTNOTIFY:
5431 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_pingtrafficsentnotify, NULL);
5432 break;
5433 default:
5434 expert_add_info(pinfo, tf, &ei_dcerpc_cn_rts_command);
5435 break;
5439 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RPCH");
5441 /* Define which PDU Body we are dealing with */
5442 info_str = "unknown RTS PDU";
5444 switch (rts_flags) {
5445 case RTS_FLAG_NONE:
5446 switch (commands_nb) {
5447 case 1:
5448 if (cmd[0] == 0x2) {
5449 info_str = "CONN/A3";
5450 } else if (cmd[0] == 0x3) {
5451 info_str = "IN_R1/A5,IN_R1/A6,IN_R2/A2,IN_R2/A5,OUT_R2/A4";
5452 } else if (cmd[0] == 0x7) {
5453 info_str = "IN_R1/B1";
5454 } else if (cmd[0] == 0x0) {
5455 info_str = "IN_R1/B2";
5456 } else if (cmd[0] == 0xD) {
5457 info_str = "IN_R2/A3,IN_R2/A4";
5458 } else if (cmd[0] == 0xA) {
5459 info_str = "OUT_R1/A9,OUT_R1/A10,OUT_R1/A11,OUT_R2/B1,OUT_R2/B2";
5461 break;
5462 case 2:
5463 if ((cmd[0] == 0x0) && (cmd[1] == 0x6)) {
5464 info_str = "CONN/B3";
5465 } else if ((cmd[0] == 0xD) && (cmd[1] == 0xA)) {
5466 info_str = "OUT_R2/A5,OUT_R2/A6";
5468 break;
5469 case 3:
5470 if ((cmd[0] == 0x6) && (cmd[1] == 0x0) && (cmd[2] == 0x2)) {
5471 info_str = "CONN/C1,CONN/C2";
5473 break;
5474 case 4:
5475 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x0)) {
5476 info_str = "CONN/A1";
5477 } else if ((cmd[0] == 0xD) && (cmd[1] == 0x6) && (cmd[2] == 0x0) && (cmd[3] == 0x2)) {
5478 info_str = "IN_R1/A3,IN_R1/A4";
5480 break;
5481 case 6:
5482 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x4) && (cmd[4] == 0x5) && (cmd[5] == 0xC)) {
5483 info_str = "CONN/B1";
5485 break;
5486 default:
5487 break;
5489 break;
5490 case RTS_FLAG_PING:
5491 switch (commands_nb) {
5492 case 0:
5493 info_str = "Ping";
5494 break;
5495 case 1:
5496 if ((cmd[0] == 0x7) || (cmd[0] == 0x8)) {
5497 info_str = "OUT_R2/C1";
5499 break;
5500 default:
5501 break;
5503 break;
5504 case RTS_FLAG_OTHER_CMD:
5505 switch (commands_nb) {
5506 case 1:
5507 if (cmd[0] == 0x5) {
5508 info_str = "Keep-Alive";
5509 } else if (cmd[0] == 0xE) {
5510 info_str = "PingTrafficSentNotify";
5511 } else if (cmd[0] == 0x1) {
5512 info_str = "FlowControlAck";
5514 break;
5515 case 2:
5516 if ((cmd[0] == 0xD) && (cmd[1] == 0x1)) {
5517 info_str = "FlowControlAckWithDestination";
5519 break;
5520 default:
5521 break;
5523 break;
5524 case RTS_FLAG_RECYCLE_CHANNEL:
5525 switch (commands_nb) {
5526 case 1:
5527 if (cmd[0] == 0xD) {
5528 info_str = "OUT_R1/A1,OUT_R1/A2,OUT_R2/A1,OUT_R2/A2";
5530 break;
5531 case 4:
5532 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3)) {
5533 info_str = "IN_R1/A1,IN_R2/A1";
5535 break;
5536 case 5:
5537 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3) && (cmd[4] == 0x0)) {
5538 info_str = "OUT_R1/A3,OUT_R2/A3";
5540 break;
5541 default:
5542 break;
5544 break;
5545 case RTS_FLAG_IN_CHANNEL|RTS_FLAG_RECYCLE_CHANNEL:
5546 switch (commands_nb) {
5547 case 6:
5548 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3) && (cmd[4] == 0x0) && (cmd[5] == 0x2)) {
5549 info_str = "IN_R1/A2";
5551 break;
5552 default:
5553 break;
5555 break;
5556 case RTS_FLAG_IN_CHANNEL:
5557 switch (commands_nb) {
5558 case 7:
5559 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x0) && (cmd[4] == 0x2) && (cmd[5] == 0xC) && (cmd[6] == 0xB)) {
5560 info_str = "CONN/B2";
5562 break;
5563 default:
5564 break;
5566 break;
5567 case RTS_FLAG_OUT_CHANNEL|RTS_FLAG_RECYCLE_CHANNEL:
5568 switch (commands_nb) {
5569 case 7:
5570 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3) && (cmd[4] == 0x4) && (cmd[5] == 0) && (cmd[6] == 0x2)) {
5571 info_str = "OUT_R1/A4";
5573 break;
5574 default:
5575 break;
5577 break;
5578 case RTS_FLAG_OUT_CHANNEL:
5579 switch (commands_nb) {
5580 case 2:
5581 if ((cmd[0] == 0xD) && (cmd[1] == 0x3)) {
5582 info_str = "OUT_R1/A7,OUT_R1/A8,OUT_R2/A8";
5584 break;
5585 case 3:
5586 if ((cmd[0] == 0xD) && (cmd[1] == 0x6) && (cmd[2] == 0x2)) {
5587 info_str = "OUT_R1/A5,OUT_R1/A6";
5588 } else if ((cmd[0] == 0xD) && (cmd[1] == 0x3) && (cmd[2] == 0x6)) {
5589 info_str = "OUT_R2/A7";
5591 break;
5592 case 5:
5593 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x4) && (cmd[4] == 0x0)) {
5594 info_str = "CONN/A2";
5596 break;
5597 default:
5598 break;
5600 break;
5601 case RTS_FLAG_EOF:
5602 switch (commands_nb) {
5603 case 1:
5604 if (cmd[0] == 0xA) {
5605 info_str = "OUT_R2/B3";
5607 break;
5608 default:
5609 break;
5611 break;
5612 case RTS_FLAG_ECHO:
5613 switch (commands_nb) {
5614 case 0:
5615 info_str = "Echo";
5616 break;
5617 default:
5618 break;
5620 break;
5621 default:
5622 break;
5625 col_add_fstr(pinfo->cinfo, COL_INFO, "%s, ", info_str);
5626 col_set_fence(pinfo->cinfo,COL_INFO);
5628 parent_pi = proto_tree_get_parent(dcerpc_tree);
5629 if (parent_pi != NULL) {
5630 proto_item_append_text(parent_pi, ", %s", info_str);
5634 /* Test to see if this looks like a connection oriented PDU */
5635 static bool
5636 is_dcerpc(tvbuff_t *tvb, int offset, packet_info *pinfo _U_)
5638 uint8_t rpc_ver;
5639 uint8_t rpc_ver_minor;
5640 uint8_t ptype;
5641 uint8_t drep[4];
5642 uint16_t frag_len;
5644 if (!tvb_bytes_exist(tvb, offset, sizeof(e_dce_cn_common_hdr_t)))
5645 return false; /* not enough information to check */
5647 rpc_ver = tvb_get_uint8(tvb, offset++);
5648 if (rpc_ver != 5)
5649 return false;
5650 rpc_ver_minor = tvb_get_uint8(tvb, offset++);
5651 if ((rpc_ver_minor != 0) && (rpc_ver_minor != 1))
5652 return false;
5653 ptype = tvb_get_uint8(tvb, offset++);
5654 if (ptype > PDU_RTS)
5655 return false;
5656 /* Skip flags, nothing good to check */
5657 offset++;
5659 tvb_memcpy(tvb, (uint8_t *)drep, offset, sizeof (drep));
5660 if (drep[0]&0xee)
5661 return false;
5662 if (drep[1] > DCE_RPC_DREP_FP_IBM)
5663 return false;
5664 offset += (int)sizeof(drep);
5665 frag_len = dcerpc_tvb_get_ntohs(tvb, offset, drep);
5666 if (frag_len < sizeof(e_dce_cn_common_hdr_t)) {
5667 return false;
5670 return true;
5674 * DCERPC dissector for connection oriented calls.
5676 static bool
5677 dissect_dcerpc_cn(tvbuff_t *tvb, int offset, packet_info *pinfo,
5678 proto_tree *tree, bool can_desegment, int *pkt_len)
5680 static const uint8_t nulls[4] = { 0 };
5681 int start_offset;
5682 int padding = 0;
5683 int subtvb_len = 0;
5684 proto_item *ti = NULL;
5685 proto_item *tf = NULL;
5686 proto_tree *dcerpc_tree = NULL;
5687 e_dce_cn_common_hdr_t hdr;
5688 dcerpc_auth_info auth_info;
5689 tvbuff_t *fragment_tvb;
5690 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
5691 static int * const hdr_flags[] = {
5692 &hf_dcerpc_cn_flags_object,
5693 &hf_dcerpc_cn_flags_maybe,
5694 &hf_dcerpc_cn_flags_dne,
5695 &hf_dcerpc_cn_flags_mpx,
5696 &hf_dcerpc_cn_flags_reserved,
5697 &hf_dcerpc_cn_flags_cancel_pending,
5698 &hf_dcerpc_cn_flags_last_frag,
5699 &hf_dcerpc_cn_flags_first_frag,
5700 NULL
5704 * when done over nbt, dcerpc requests are padded with 4 bytes of null
5705 * data for some reason.
5707 * XXX - if that's always the case, the right way to do this would
5708 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
5709 * the 4 bytes of null padding, and make that the dissector
5710 * used for "netbios".
5712 if (tvb_memeql(tvb, offset, nulls, 4) == 0) {
5715 * Skip the padding.
5717 offset += 4;
5718 padding += 4;
5721 * Check if this looks like a C/O DCERPC call
5723 if (!is_dcerpc(tvb, offset, pinfo))
5724 return false;
5726 start_offset = offset;
5727 hdr.rpc_ver = tvb_get_uint8(tvb, offset++);
5728 hdr.rpc_ver_minor = tvb_get_uint8(tvb, offset++);
5729 hdr.ptype = tvb_get_uint8(tvb, offset++);
5731 hdr.flags = tvb_get_uint8(tvb, offset++);
5732 tvb_memcpy(tvb, (uint8_t *)hdr.drep, offset, sizeof (hdr.drep));
5733 offset += (int)sizeof (hdr.drep);
5735 hdr.frag_len = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5736 offset += 2;
5737 hdr.auth_len = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5738 offset += 2;
5739 hdr.call_id = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
5740 /*offset += 4;*/
5742 if (can_desegment && pinfo->can_desegment
5743 && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
5744 pinfo->desegment_offset = start_offset;
5745 pinfo->desegment_len = hdr.frag_len - tvb_reported_length_remaining(tvb, start_offset);
5746 *pkt_len = 0; /* desegmentation required */
5747 return true;
5750 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCERPC");
5752 if (decode_data->dcectxid != 0) {
5753 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
5754 * append a delimiter and set a column fence */
5755 col_append_str(pinfo->cinfo, COL_INFO, " # ");
5756 col_set_fence(pinfo->cinfo,COL_INFO);
5758 col_add_fstr(pinfo->cinfo, COL_INFO, "%s: call_id: %u",
5759 pckt_vals[hdr.ptype].strptr, hdr.call_id);
5761 if (decode_data->dcectxid != 0) {
5762 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU */
5763 expert_add_info(pinfo, NULL, &ei_dcerpc_fragment_multiple);
5766 offset = start_offset;
5767 tvb_ensure_bytes_exist(tvb, offset, 16);
5768 if (tree) {
5769 ti = proto_tree_add_item(tree, proto_dcerpc, tvb, offset, hdr.frag_len, ENC_NA);
5770 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
5773 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
5774 offset++;
5776 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset, 1, hdr.rpc_ver_minor);
5777 offset++;
5779 tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
5780 offset++;
5782 #if 0 /* XXX - too much "output noise", removed for now */
5783 if (hdr.ptype == PDU_BIND || hdr.ptype == PDU_ALTER ||
5784 hdr.ptype == PDU_BIND_ACK || hdr.ptype == PDU_ALTER_ACK)
5785 expert_add_info_format(pinfo, tf, &ei_dcerpc_context_change, "Context change: %s", val_to_str(hdr.ptype, pckt_vals, "(0x%x)"));
5786 #endif
5787 if (hdr.ptype == PDU_BIND_NAK)
5788 expert_add_info(pinfo, tf, &ei_dcerpc_bind_not_acknowledged);
5790 if (tree) {
5791 proto_item_append_text(ti, " %s, Fragment: %s",
5792 val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"),
5793 fragment_type(hdr.flags));
5796 proto_tree_add_bitmask_value_with_flags(dcerpc_tree, tvb, offset, hf_dcerpc_cn_flags,
5797 ett_dcerpc_cn_flags, hdr_flags, hdr.flags, BMT_NO_APPEND);
5798 offset++;
5800 col_append_fstr(pinfo->cinfo, COL_INFO, ", Fragment: %s", fragment_type(hdr.flags));
5802 proto_tree_add_dcerpc_drep(dcerpc_tree, tvb, offset, hdr.drep, (int)sizeof (hdr.drep));
5803 offset += (int)sizeof (hdr.drep);
5805 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
5806 offset += 2;
5808 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
5809 offset += 2;
5811 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
5812 offset += 4;
5814 if (ti) {
5815 proto_item_append_text(ti, ", FragLen: %u, Call: %u", hdr.frag_len, hdr.call_id);
5819 * None of the stuff done above should throw an exception, because
5820 * we would have rejected this as "not DCE RPC" if we didn't have all
5821 * of it. (XXX - perhaps we should request reassembly if we have
5822 * enough of the header to consider it DCE RPC but not enough to
5823 * get the fragment length; in that case the stuff still wouldn't
5824 * throw an exception.)
5826 * The rest of the stuff might, so return the PDU length to our caller.
5827 * XXX - should we construct a tvbuff containing only the PDU and
5828 * use that? Or should we have separate "is this a DCE RPC PDU",
5829 * "how long is it", and "dissect it" routines - which might let us
5830 * do most of the work in "tcp_dissect_pdus()"?
5832 if (pkt_len != NULL)
5833 *pkt_len = hdr.frag_len + padding;
5835 /* The remaining bytes in the current tvb might contain multiple
5836 * DCE/RPC fragments, so create a new tvb subset for this fragment.
5837 * Only limit the end of the fragment, but not the offset start,
5838 * as the authentication function dissect_dcerpc_cn_auth() will fail
5839 * (and other functions might fail as well) computing the right start
5840 * offset otherwise.
5842 subtvb_len = MIN(hdr.frag_len, tvb_reported_length(tvb));
5843 fragment_tvb = tvb_new_subset_length_caplen(tvb, start_offset,
5844 subtvb_len /* length */,
5845 hdr.frag_len /* reported_length */);
5848 * Packet type specific stuff is next.
5850 switch (hdr.ptype) {
5851 case PDU_BIND:
5852 case PDU_ALTER:
5853 dissect_dcerpc_cn_bind(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
5854 break;
5856 case PDU_BIND_ACK:
5857 case PDU_ALTER_ACK:
5858 dissect_dcerpc_cn_bind_ack(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
5859 break;
5861 case PDU_AUTH3:
5863 * Nothing after the common header other than credentials.
5865 dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr,
5866 &auth_info);
5867 break;
5869 case PDU_REQ:
5870 dissect_dcerpc_cn_rqst(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, tree, &hdr);
5871 break;
5873 case PDU_RESP:
5874 dissect_dcerpc_cn_resp(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, tree, &hdr);
5875 break;
5877 case PDU_FAULT:
5878 dissect_dcerpc_cn_fault(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
5879 break;
5881 case PDU_BIND_NAK:
5882 dissect_dcerpc_cn_bind_nak(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
5883 break;
5885 case PDU_CO_CANCEL:
5886 case PDU_ORPHANED:
5888 * Nothing after the common header other than an authentication
5889 * verifier.
5891 dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr,
5892 &auth_info);
5893 break;
5895 case PDU_SHUTDOWN:
5897 * Nothing after the common header, not even an authentication
5898 * verifier.
5900 break;
5901 case PDU_RTS:
5902 dissect_dcerpc_cn_rts(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
5903 break;
5905 default:
5906 /* might as well dissect the auth info */
5907 dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr,
5908 &auth_info);
5909 break;
5911 return true;
5915 * DCERPC dissector for connection oriented calls over packet-oriented
5916 * transports
5918 static bool
5919 dissect_dcerpc_cn_pk(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5921 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
5924 * Only one PDU per transport packet, and only one transport
5925 * packet per PDU.
5927 decode_data->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
5928 if (!dissect_dcerpc_cn(tvb, 0, pinfo, tree, false, NULL)) {
5930 * It wasn't a DCERPC PDU.
5932 return false;
5933 } else {
5935 * It was.
5937 return true;
5942 * DCERPC dissector for connection oriented calls over byte-stream
5943 * transports.
5944 * we need to distinguish here between SMB and non-TCP (more in the future?)
5945 * to be able to know what kind of private_data structure to expect.
5947 static bool
5948 dissect_dcerpc_cn_bs_body(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
5950 volatile int offset = 0;
5951 int pdu_len = 0;
5952 volatile int dcerpc_pdus = 0;
5953 volatile bool ret = false;
5956 * There may be multiple PDUs per transport packet; keep
5957 * processing them.
5959 while (tvb_reported_length_remaining(tvb, offset) != 0) {
5960 TRY {
5961 pdu_len = 0;
5962 if (dissect_dcerpc_cn(tvb, offset, pinfo, tree,
5963 dcerpc_cn_desegment, &pdu_len)) {
5964 dcerpc_pdus++;
5966 } CATCH_NONFATAL_ERRORS {
5968 * Somebody threw an exception that means that there
5969 * was a problem dissecting the payload; that means
5970 * that a dissector was found, so we don't need to
5971 * dissect the payload as data or update the protocol
5972 * or info columns.
5974 * Just show the exception and then continue dissecting
5975 * PDUs.
5977 show_exception(tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
5979 * Presumably it looked enough like a DCE RPC PDU that we
5980 * dissected enough of it to throw an exception.
5982 dcerpc_pdus++;
5983 } ENDTRY;
5985 if (dcerpc_pdus == 0) {
5986 bool try_desegment = false;
5987 if (dcerpc_cn_desegment && pinfo->can_desegment &&
5988 !tvb_bytes_exist(tvb, offset, sizeof(e_dce_cn_common_hdr_t))) {
5989 /* look for a previous occurrence of the DCE-RPC protocol */
5990 wmem_list_frame_t *cur;
5991 cur = wmem_list_frame_prev(wmem_list_tail(pinfo->layers));
5992 while (cur != NULL) {
5993 if (proto_dcerpc == (int)GPOINTER_TO_UINT(wmem_list_frame_data(cur))) {
5994 try_desegment = true;
5995 break;
5997 cur = wmem_list_frame_prev(cur);
6001 if (try_desegment) {
6002 /* It didn't look like DCE-RPC but we already had one DCE-RPC
6003 * layer in this packet and what we have is short. Assume that
6004 * it was just too short to tell and ask the TCP layer for more
6005 * data. */
6006 pinfo->desegment_offset = offset;
6007 pinfo->desegment_len = (uint32_t)(sizeof(e_dce_cn_common_hdr_t) - tvb_reported_length_remaining(tvb, offset));
6008 } else {
6009 /* Really not DCE-RPC */
6010 break;
6015 * Well, we've seen at least one DCERPC PDU.
6017 ret = true;
6019 /* if we had more than one Req/Resp in this PDU change the protocol column */
6020 /* this will formerly contain the last interface name, which may not be the same for all Req/Resp */
6021 if (dcerpc_pdus >= 2)
6022 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "%u*DCERPC", dcerpc_pdus);
6024 if (pdu_len == 0) {
6026 * Desegmentation required - bail now, but give the user a hint that desegmentation might be done later.
6028 proto_tree_add_uint_format(tree, hf_dcerpc_cn_deseg_req, tvb, offset,
6030 tvb_reported_length_remaining(tvb, offset),
6031 "[DCE RPC: %u byte%s left, desegmentation might follow]",
6032 tvb_reported_length_remaining(tvb, offset),
6033 plurality(tvb_reported_length_remaining(tvb, offset), "", "s"));
6034 break;
6038 * Step to the next PDU.
6040 offset += pdu_len;
6042 return ret;
6045 static bool
6046 dissect_dcerpc_cn_bs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
6048 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
6050 decode_data->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
6051 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
6054 static unsigned
6055 get_dcerpc_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb,
6056 int offset, void *data _U_)
6058 uint8_t drep[4];
6059 uint16_t frag_len;
6061 tvb_memcpy(tvb, (uint8_t *)drep, offset+4, sizeof(drep));
6062 frag_len = dcerpc_tvb_get_ntohs(tvb, offset+8, drep);
6064 if (!frag_len) {
6065 /* tcp_dissect_pdus() interprets a 0 return value as meaning
6066 * "a PDU starts here, but the length cannot be determined yet, so
6067 * we need at least one more segment." However, a frag_len of 0 here
6068 * is instead a bogus length. Instead return 1, another bogus length
6069 * also less than our fixed length, so that the TCP dissector will
6070 * correctly interpret it as a bogus and report an error.
6072 frag_len = 1;
6074 return frag_len;
6077 static int
6078 dissect_dcerpc_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
6080 int pdu_len = 0;
6081 dissect_dcerpc_cn(tvb, 0, pinfo, tree,
6082 /* Desegment is already handled by TCP, don't confuse it */
6083 false,
6084 &pdu_len);
6085 return pdu_len;
6088 static bool
6089 dissect_dcerpc_tcp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
6091 dcerpc_decode_as_data* decode_data;
6093 if (!is_dcerpc(tvb, 0, pinfo))
6094 return false;
6096 decode_data = dcerpc_get_decode_data(pinfo);
6097 decode_data->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
6099 tcp_dissect_pdus(tvb, pinfo, tree, dcerpc_cn_desegment, sizeof(e_dce_cn_common_hdr_t), get_dcerpc_pdu_len, dissect_dcerpc_pdu, data);
6100 return true;
6103 static int
6104 dissect_dcerpc_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
6106 dcerpc_decode_as_data* decode_data;
6108 decode_data = dcerpc_get_decode_data(pinfo);
6109 decode_data->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
6111 tcp_dissect_pdus(tvb, pinfo, tree, dcerpc_cn_desegment, sizeof(e_dce_cn_common_hdr_t), get_dcerpc_pdu_len, dissect_dcerpc_pdu, data);
6112 return tvb_captured_length(tvb);
6115 static bool
6116 dissect_dcerpc_cn_smbpipe(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
6118 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
6120 decode_data->dcetransporttype = DCE_CN_TRANSPORT_SMBPIPE;
6121 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
6124 static bool
6125 dissect_dcerpc_cn_smb2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
6127 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
6129 decode_data->dcetransporttype = DCE_CN_TRANSPORT_SMBPIPE;
6130 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
6135 static void
6136 dissect_dcerpc_dg_auth(tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
6137 e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
6139 proto_tree *auth_tree = NULL;
6140 uint8_t protection_level;
6143 * Initially set "*auth_level_p" to -1 to indicate that we haven't
6144 * yet seen any authentication level information.
6146 if (auth_level_p != NULL)
6147 *auth_level_p = -1;
6150 * The authentication information is at the *end* of the PDU; in
6151 * request and response PDUs, the request and response stub data
6152 * come before it.
6154 * If the full packet is here, and there's data past the end of the
6155 * packet body, then dissect the auth info.
6157 offset += hdr->frag_len;
6158 if (tvb_reported_length_remaining(tvb, offset) > 0) {
6159 switch (hdr->auth_proto) {
6161 case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
6162 auth_tree = proto_tree_add_subtree(dcerpc_tree, tvb, offset, -1, ett_dcerpc_krb5_auth_verf, NULL, "Kerberos authentication verifier");
6163 protection_level = tvb_get_uint8(tvb, offset);
6164 if (auth_level_p != NULL)
6165 *auth_level_p = protection_level;
6166 proto_tree_add_uint(auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
6167 offset++;
6168 proto_tree_add_item(auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, ENC_BIG_ENDIAN);
6169 offset++;
6170 if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
6171 offset += 6; /* 6 bytes of padding */
6172 else
6173 offset += 2; /* 2 bytes of padding */
6174 proto_tree_add_item(auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, ENC_NA);
6175 /*offset += 16;*/
6176 break;
6178 default:
6179 proto_tree_add_item(dcerpc_tree, hf_dcerpc_authentication_verifier, tvb, offset, -1, ENC_NA);
6180 break;
6185 static void
6186 dissect_dcerpc_dg_cancel_ack(tvbuff_t *tvb, int offset, packet_info *pinfo,
6187 proto_tree *dcerpc_tree,
6188 e_dce_dg_common_hdr_t *hdr)
6190 uint32_t version;
6192 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
6193 hdr->drep, hf_dcerpc_dg_cancel_vers,
6194 &version);
6196 switch (version) {
6198 case 0:
6199 /* The only version we know about */
6200 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
6201 hdr->drep, hf_dcerpc_dg_cancel_id,
6202 NULL);
6203 /*offset = */dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
6204 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
6205 NULL);
6206 break;
6210 static void
6211 dissect_dcerpc_dg_cancel(tvbuff_t *tvb, int offset, packet_info *pinfo,
6212 proto_tree *dcerpc_tree,
6213 e_dce_dg_common_hdr_t *hdr)
6215 uint32_t version;
6217 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
6218 hdr->drep, hf_dcerpc_dg_cancel_vers,
6219 &version);
6221 switch (version) {
6223 case 0:
6224 /* The only version we know about */
6225 /*offset = */dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
6226 hdr->drep, hf_dcerpc_dg_cancel_id,
6227 NULL);
6228 /* XXX - are NDR Booleans 32 bits? */
6230 /* XXX - the RPC reference in chapter: "the cancel PDU" doesn't mention
6231 the accepting_cancels field (it's only in the cancel_ack PDU)! */
6232 /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
6233 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
6234 NULL);*/
6235 break;
6239 static void
6240 dissect_dcerpc_dg_fack(tvbuff_t *tvb, int offset, packet_info *pinfo,
6241 proto_tree *dcerpc_tree,
6242 e_dce_dg_common_hdr_t *hdr)
6244 uint8_t version;
6245 uint16_t serial_num;
6246 uint16_t selack_len;
6247 unsigned i;
6249 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
6250 hdr->drep, hf_dcerpc_dg_fack_vers,
6251 &version);
6252 /* padding */
6253 offset++;
6255 switch (version) {
6257 case 0: /* The only version documented in the DCE RPC 1.1 spec */
6258 case 1: /* This appears to be the same */
6259 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
6260 hdr->drep, hf_dcerpc_dg_fack_window_size,
6261 NULL);
6262 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
6263 hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
6264 NULL);
6265 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
6266 hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
6267 NULL);
6268 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
6269 hdr->drep, hf_dcerpc_dg_fack_serial_num,
6270 &serial_num);
6271 col_append_fstr(pinfo->cinfo, COL_INFO, " serial: %u",
6272 serial_num);
6273 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
6274 hdr->drep, hf_dcerpc_dg_fack_selack_len,
6275 &selack_len);
6276 for (i = 0; i < selack_len; i++) {
6277 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
6278 hdr->drep, hf_dcerpc_dg_fack_selack,
6279 NULL);
6282 break;
6286 static void
6287 dissect_dcerpc_dg_reject_fault(tvbuff_t *tvb, int offset, packet_info *pinfo,
6288 proto_tree *dcerpc_tree,
6289 e_dce_dg_common_hdr_t *hdr)
6291 uint32_t status;
6293 /*offset = */dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
6294 hdr->drep, hf_dcerpc_dg_status,
6295 &status);
6297 col_append_fstr (pinfo->cinfo, COL_INFO,
6298 ": status: %s",
6299 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
6302 static void
6303 dissect_dcerpc_dg_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
6304 proto_tree *dcerpc_tree, proto_tree *tree,
6305 e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
6307 int length, reported_length, stub_length;
6308 bool save_fragmented;
6309 fragment_head *fd_head;
6310 tvbuff_t *next_tvb;
6311 proto_item *pi;
6312 proto_item *parent_pi;
6314 col_append_fstr(pinfo->cinfo, COL_INFO, " opnum: %u len: %u",
6315 di->call_data->opnum, hdr->frag_len );
6317 length = tvb_reported_length_remaining(tvb, offset);
6318 reported_length = tvb_reported_length_remaining(tvb, offset);
6319 stub_length = hdr->frag_len;
6320 if (length > stub_length)
6321 length = stub_length;
6322 if (reported_length > stub_length)
6323 reported_length = stub_length;
6325 save_fragmented = pinfo->fragmented;
6327 /* If we don't have reassembly enabled, or this packet contains
6328 the entire PDU, or if this is a short frame (or a frame
6329 not reassembled at a lower layer) that doesn't include all
6330 the data in the fragment, just call the handoff directly if
6331 this is the first fragment or the PDU isn't fragmented. */
6332 if ( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
6333 !tvb_bytes_exist(tvb, offset, stub_length) ) {
6334 if (hdr->frag_num == 0) {
6337 /* First fragment, possibly the only fragment */
6340 * XXX - authentication info?
6342 pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
6343 next_tvb = tvb_new_subset_length_caplen(tvb, offset, length,
6344 reported_length);
6345 dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb, true, hdr->drep, di, NULL);
6346 } else {
6347 /* PDU is fragmented and this isn't the first fragment */
6348 if (length > 0) {
6349 proto_tree_add_item(dcerpc_tree, hf_dcerpc_fragment_data, tvb, offset, stub_length, ENC_NA);
6352 } else {
6353 /* Reassembly is enabled, the PDU is fragmented, and
6354 we have all the data in the fragment; the first two
6355 of those mean we should attempt reassembly, and the
6356 third means we can attempt reassembly. */
6357 if (length > 0) {
6358 proto_tree_add_item(dcerpc_tree, hf_dcerpc_fragment_data, tvb, offset, stub_length, ENC_NA);
6361 fd_head = fragment_add_seq(&dcerpc_cl_reassembly_table,
6362 tvb, offset,
6363 pinfo, hdr->seqnum, (void *)hdr,
6364 hdr->frag_num, stub_length,
6365 !(hdr->flags1 & PFCL1_LASTFRAG), 0);
6366 if (fd_head != NULL) {
6367 /* We completed reassembly... */
6368 if (pinfo->num == fd_head->reassembled_in) {
6369 /* ...and this is the reassembled RPC PDU */
6370 next_tvb = tvb_new_chain(tvb, fd_head->tvb_data);
6371 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
6372 show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
6373 tree, pinfo, next_tvb, &pi);
6376 * XXX - authentication info?
6378 pinfo->fragmented = false;
6379 dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb, true, hdr->drep, di, NULL);
6380 } else {
6381 /* ...and this isn't the reassembled RPC PDU */
6382 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
6383 tvb, 0, 0, fd_head->reassembled_in);
6384 proto_item_set_generated(pi);
6385 parent_pi = proto_tree_get_parent(dcerpc_tree);
6386 if (parent_pi != NULL) {
6387 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
6389 col_append_fstr(pinfo->cinfo, COL_INFO,
6390 " [DCE/RPC fragment, reas: #%u]", fd_head->reassembled_in);
6394 pinfo->fragmented = save_fragmented;
6397 static void
6398 dissect_dcerpc_dg_rqst(tvbuff_t *tvb, int offset, packet_info *pinfo,
6399 proto_tree *dcerpc_tree, proto_tree *tree,
6400 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
6402 dcerpc_info *di;
6403 dcerpc_call_value *value;
6404 dcerpc_matched_key matched_key, *new_matched_key;
6405 proto_item *pi;
6406 proto_item *parent_pi;
6408 if (!(pinfo->fd->visited)) {
6409 dcerpc_call_value *call_value;
6410 dcerpc_dg_call_key *call_key;
6412 call_key = wmem_new(wmem_file_scope(), dcerpc_dg_call_key);
6413 call_key->conv = conv;
6414 call_key->seqnum = hdr->seqnum;
6415 call_key->act_id = hdr->act_id;
6417 call_value = wmem_new(wmem_file_scope(), dcerpc_call_value);
6418 call_value->uuid = hdr->if_id;
6419 call_value->ver = hdr->if_ver;
6420 call_value->object_uuid = hdr->obj_id;
6421 call_value->opnum = hdr->opnum;
6422 call_value->req_frame = pinfo->num;
6423 call_value->req_time = pinfo->abs_ts;
6424 call_value->rep_frame = 0;
6425 call_value->max_ptr = 0;
6426 call_value->se_data = NULL;
6427 call_value->private_data = NULL;
6428 call_value->pol = NULL;
6429 /* NDR64 is not available on dg transports ?*/
6430 call_value->flags = 0;
6432 wmem_map_insert(dcerpc_dg_calls, call_key, call_value);
6434 new_matched_key = wmem_new(wmem_file_scope(), dcerpc_matched_key);
6435 new_matched_key->frame = pinfo->num;
6436 new_matched_key->call_id = hdr->seqnum;
6437 wmem_map_insert(dcerpc_matched, new_matched_key, call_value);
6440 matched_key.frame = pinfo->num;
6441 matched_key.call_id = hdr->seqnum;
6442 value = (dcerpc_call_value *)wmem_map_lookup(dcerpc_matched, &matched_key);
6443 if (!value) {
6444 value = wmem_new(pinfo->pool, dcerpc_call_value);
6445 value->uuid = hdr->if_id;
6446 value->ver = hdr->if_ver;
6447 value->object_uuid = hdr->obj_id;
6448 value->opnum = hdr->opnum;
6449 value->req_frame = pinfo->num;
6450 value->rep_frame = 0;
6451 value->max_ptr = 0;
6452 value->se_data = NULL;
6453 value->private_data = NULL;
6456 di = wmem_new0(pinfo->pool, dcerpc_info);
6457 di->dcerpc_procedure_name = "";
6458 di->conv = conv;
6459 di->call_id = hdr->seqnum;
6460 di->transport_salt = -1;
6461 di->ptype = PDU_REQ;
6462 di->call_data = value;
6464 if (value->rep_frame != 0) {
6465 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
6466 tvb, 0, 0, value->rep_frame);
6467 proto_item_set_generated(pi);
6468 parent_pi = proto_tree_get_parent(dcerpc_tree);
6469 if (parent_pi != NULL) {
6470 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
6473 dissect_dcerpc_dg_stub(tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
6476 static void
6477 dissect_dcerpc_dg_resp(tvbuff_t *tvb, int offset, packet_info *pinfo,
6478 proto_tree *dcerpc_tree, proto_tree *tree,
6479 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
6481 dcerpc_info *di;
6482 dcerpc_call_value *value;
6483 dcerpc_matched_key matched_key, *new_matched_key;
6484 proto_item *pi;
6485 proto_item *parent_pi;
6487 if (!(pinfo->fd->visited)) {
6488 dcerpc_call_value *call_value;
6489 dcerpc_dg_call_key call_key;
6491 call_key.conv = conv;
6492 call_key.seqnum = hdr->seqnum;
6493 call_key.act_id = hdr->act_id;
6495 if ((call_value = (dcerpc_call_value *)wmem_map_lookup(dcerpc_dg_calls, &call_key))) {
6496 new_matched_key = wmem_new(wmem_file_scope(), dcerpc_matched_key);
6497 new_matched_key->frame = pinfo->num;
6498 new_matched_key->call_id = hdr->seqnum;
6499 wmem_map_insert(dcerpc_matched, new_matched_key, call_value);
6500 if (call_value->rep_frame == 0) {
6501 call_value->rep_frame = pinfo->num;
6506 matched_key.frame = pinfo->num;
6507 matched_key.call_id = hdr->seqnum;
6508 value = (dcerpc_call_value *)wmem_map_lookup(dcerpc_matched, &matched_key);
6509 if (!value) {
6510 value = wmem_new0(pinfo->pool, dcerpc_call_value);
6511 value->uuid = hdr->if_id;
6512 value->ver = hdr->if_ver;
6513 value->object_uuid = hdr->obj_id;
6514 value->opnum = hdr->opnum;
6515 value->rep_frame = pinfo->num;
6518 di = wmem_new0(pinfo->pool, dcerpc_info);
6519 di->dcerpc_procedure_name = "";
6520 di->conv = conv;
6521 di->transport_salt = -1;
6522 di->ptype = PDU_RESP;
6523 di->call_data = value;
6525 if (value->req_frame != 0) {
6526 nstime_t delta_ts;
6527 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
6528 tvb, 0, 0, value->req_frame);
6529 proto_item_set_generated(pi);
6530 parent_pi = proto_tree_get_parent(dcerpc_tree);
6531 if (parent_pi != NULL) {
6532 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
6534 nstime_delta(&delta_ts, &pinfo->abs_ts, &value->req_time);
6535 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
6536 proto_item_set_generated(pi);
6537 } else {
6538 proto_tree_add_expert(dcerpc_tree, pinfo, &ei_dcerpc_no_request_found, tvb, 0, 0);
6540 dissect_dcerpc_dg_stub(tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
6543 static void
6544 dissect_dcerpc_dg_ping_ack(tvbuff_t *tvb, int offset, packet_info *pinfo,
6545 proto_tree *dcerpc_tree,
6546 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
6548 proto_item *parent_pi;
6549 /* if (!(pinfo->fd->visited)) {*/
6550 dcerpc_call_value *call_value;
6551 dcerpc_dg_call_key call_key;
6553 call_key.conv = conv;
6554 call_key.seqnum = hdr->seqnum;
6555 call_key.act_id = hdr->act_id;
6557 if ((call_value = (dcerpc_call_value *)wmem_map_lookup(dcerpc_dg_calls, &call_key))) {
6558 proto_item *pi;
6559 nstime_t delta_ts;
6561 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
6562 tvb, 0, 0, call_value->req_frame);
6563 proto_item_set_generated(pi);
6564 parent_pi = proto_tree_get_parent(dcerpc_tree);
6565 if (parent_pi != NULL) {
6566 proto_item_append_text(parent_pi, ", [Req: #%u]", call_value->req_frame);
6569 col_append_fstr(pinfo->cinfo, COL_INFO, " [req: #%u]", call_value->req_frame);
6571 nstime_delta(&delta_ts, &pinfo->abs_ts, &call_value->req_time);
6572 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
6573 proto_item_set_generated(pi);
6574 /* }*/
6579 * DCERPC dissector for connectionless calls
6581 static bool
6582 dissect_dcerpc_dg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
6584 proto_item *ti = NULL;
6585 proto_tree *dcerpc_tree = NULL;
6586 e_dce_dg_common_hdr_t hdr;
6587 int offset = 0;
6588 conversation_t *conv;
6589 int auth_level;
6590 char *uuid_str;
6591 const char *uuid_name = NULL;
6592 static int * const hdr_flags1[] = {
6593 &hf_dcerpc_dg_flags1_rsrvd_80,
6594 &hf_dcerpc_dg_flags1_broadcast,
6595 &hf_dcerpc_dg_flags1_idempotent,
6596 &hf_dcerpc_dg_flags1_maybe,
6597 &hf_dcerpc_dg_flags1_nofack,
6598 &hf_dcerpc_dg_flags1_frag,
6599 &hf_dcerpc_dg_flags1_last_frag,
6600 &hf_dcerpc_dg_flags1_rsrvd_01,
6601 NULL
6604 static int * const hdr_flags2[] = {
6605 &hf_dcerpc_dg_flags2_rsrvd_80,
6606 &hf_dcerpc_dg_flags2_rsrvd_40,
6607 &hf_dcerpc_dg_flags2_rsrvd_20,
6608 &hf_dcerpc_dg_flags2_rsrvd_10,
6609 &hf_dcerpc_dg_flags2_rsrvd_08,
6610 &hf_dcerpc_dg_flags2_rsrvd_04,
6611 &hf_dcerpc_dg_flags2_cancel_pending,
6612 &hf_dcerpc_dg_flags2_rsrvd_01,
6613 NULL
6617 * Check if this looks like a CL DCERPC call. All dg packets
6618 * have an 80 byte header on them. Which starts with
6619 * version (4), pkt_type.
6621 if (tvb_reported_length(tvb) < sizeof (hdr)) {
6622 return false;
6625 /* Version must be 4 */
6626 hdr.rpc_ver = tvb_get_uint8(tvb, offset++);
6627 if (hdr.rpc_ver != 4)
6628 return false;
6630 /* Type must be <= PDU_CANCEL_ACK or it's not connectionless DCE/RPC */
6631 hdr.ptype = tvb_get_uint8(tvb, offset++);
6632 if (hdr.ptype > PDU_CANCEL_ACK)
6633 return false;
6635 /* flags1 has bit 1 and 8 as reserved for implementations, with no
6636 indication that they must be set to 0, so we don't check them.
6638 hdr.flags1 = tvb_get_uint8(tvb, offset++);
6640 /* flags2 has bit 1 reserved for implementations, bit 2 used,
6641 and the other bits reserved for future use and specified
6642 as "must be set to 0", so if any of the other bits are set
6643 it is probably not DCE/RPC.
6645 hdr.flags2 = tvb_get_uint8(tvb, offset++);
6646 if (hdr.flags2&0xfc)
6647 return false;
6649 tvb_memcpy(tvb, (uint8_t *)hdr.drep, offset, sizeof (hdr.drep));
6650 offset += (int)sizeof (hdr.drep);
6651 if (hdr.drep[0]&0xee)
6652 return false;
6653 if (hdr.drep[1] > DCE_RPC_DREP_FP_IBM)
6654 return false;
6656 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCERPC");
6657 col_add_str(pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
6659 hdr.serial_hi = tvb_get_uint8(tvb, offset++);
6660 dcerpc_tvb_get_uuid(tvb, offset, hdr.drep, &hdr.obj_id);
6661 offset += 16;
6662 dcerpc_tvb_get_uuid(tvb, offset, hdr.drep, &hdr.if_id);
6663 offset += 16;
6664 dcerpc_tvb_get_uuid(tvb, offset, hdr.drep, &hdr.act_id);
6665 offset += 16;
6666 hdr.server_boot = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
6667 offset += 4;
6668 hdr.if_ver = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
6669 offset += 4;
6670 hdr.seqnum = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
6671 offset += 4;
6672 hdr.opnum = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
6673 offset += 2;
6674 hdr.ihint = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
6675 offset += 2;
6676 hdr.ahint = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
6677 offset += 2;
6678 hdr.frag_len = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
6679 offset += 2;
6680 hdr.frag_num = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
6681 offset += 2;
6682 hdr.auth_proto = tvb_get_uint8(tvb, offset++);
6683 hdr.serial_lo = tvb_get_uint8(tvb, offset++);
6685 if (tree) {
6686 ti = proto_tree_add_item(tree, proto_dcerpc, tvb, 0, -1, ENC_NA);
6687 if (ti) {
6688 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
6689 proto_item_append_text(ti, " %s, Seq: %u, Serial: %u, Frag: %u, FragLen: %u",
6690 val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"),
6691 hdr.seqnum, hdr.serial_hi*256+hdr.serial_lo,
6692 hdr.frag_num, hdr.frag_len);
6695 offset = 0;
6697 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
6698 offset++;
6700 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
6701 offset++;
6703 proto_tree_add_bitmask_value(dcerpc_tree, tvb, offset, hf_dcerpc_dg_flags1,
6704 ett_dcerpc_dg_flags1, hdr_flags1, hdr.flags1);
6705 offset++;
6707 proto_tree_add_bitmask_value(dcerpc_tree, tvb, offset, hf_dcerpc_dg_flags2,
6708 ett_dcerpc_dg_flags2, hdr_flags2, hdr.flags2);
6709 offset++;
6711 if (tree) {
6712 proto_tree_add_dcerpc_drep(dcerpc_tree, tvb, offset, hdr.drep, (int)sizeof (hdr.drep));
6714 offset += (int)sizeof (hdr.drep);
6716 if (tree)
6717 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
6718 offset++;
6720 if (tree) {
6721 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
6722 offset, 16, (e_guid_t *) &hdr.obj_id, "Object UUID: %s",
6723 guid_to_str(pinfo->pool, (e_guid_t *) &hdr.obj_id));
6725 offset += 16;
6727 if (tree) {
6728 uuid_str = guid_to_str(pinfo->pool, (e_guid_t*)&hdr.if_id);
6729 uuid_name = guids_get_uuid_name(&hdr.if_id, pinfo->pool);
6730 if (uuid_name) {
6731 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
6732 offset, 16, (e_guid_t *) &hdr.if_id, "Interface: %s UUID: %s", uuid_name, uuid_str);
6733 } else {
6734 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
6735 offset, 16, (e_guid_t *) &hdr.if_id, "Interface UUID: %s", uuid_str);
6738 offset += 16;
6740 if (tree) {
6741 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
6742 offset, 16, (e_guid_t *) &hdr.act_id, "Activity: %s",
6743 guid_to_str(pinfo->pool, (e_guid_t *) &hdr.act_id));
6745 offset += 16;
6747 if (tree) {
6748 nstime_t server_boot;
6750 server_boot.secs = hdr.server_boot;
6751 server_boot.nsecs = 0;
6753 if (hdr.server_boot == 0)
6754 proto_tree_add_time_format_value(dcerpc_tree, hf_dcerpc_dg_server_boot,
6755 tvb, offset, 4, &server_boot,
6756 "Unknown (0)");
6757 else
6758 proto_tree_add_time(dcerpc_tree, hf_dcerpc_dg_server_boot,
6759 tvb, offset, 4, &server_boot);
6761 offset += 4;
6763 if (tree)
6764 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
6765 offset += 4;
6767 if (tree)
6768 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
6769 col_append_fstr(pinfo->cinfo, COL_INFO, ": seq: %u", hdr.seqnum);
6770 offset += 4;
6772 if (tree)
6773 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
6774 offset += 2;
6776 if (tree)
6777 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
6778 offset += 2;
6780 if (tree)
6781 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
6782 offset += 2;
6784 if (tree)
6785 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
6786 offset += 2;
6788 if (tree)
6789 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
6790 if (hdr.flags1 & PFCL1_FRAG) {
6791 /* Fragmented - put the fragment number into the Info column */
6792 col_append_fstr(pinfo->cinfo, COL_INFO, " frag: %u",
6793 hdr.frag_num);
6795 offset += 2;
6797 if (tree)
6798 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
6799 offset++;
6801 if (tree)
6802 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
6803 if (hdr.flags1 & PFCL1_FRAG) {
6804 /* Fragmented - put the serial number into the Info column */
6805 col_append_fstr(pinfo->cinfo, COL_INFO, " serial: %u",
6806 (hdr.serial_hi << 8) | hdr.serial_lo);
6808 offset++;
6810 if (tree) {
6812 * XXX - for Kerberos, we get a protection level; if it's
6813 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
6814 * stub data.
6816 dissect_dcerpc_dg_auth(tvb, offset, dcerpc_tree, &hdr,
6817 &auth_level);
6821 * keeping track of the conversation shouldn't really be necessary
6822 * for connectionless packets, because everything we need to know
6823 * to dissect is in the header for each packet. Unfortunately,
6824 * Microsoft's implementation is buggy and often puts the
6825 * completely wrong if_id in the header. go figure. So, keep
6826 * track of the seqnum and use that if possible. Note: that's not
6827 * completely correct. It should really be done based on both the
6828 * activity_id and seqnum. I haven't seen anywhere that it would
6829 * make a difference, but for future reference...
6831 conv = find_or_create_conversation(pinfo);
6834 * Packet type specific stuff is next.
6837 switch (hdr.ptype) {
6839 case PDU_CANCEL_ACK:
6840 /* Body is optional */
6841 /* XXX - we assume "frag_len" is the length of the body */
6842 if (hdr.frag_len != 0)
6843 dissect_dcerpc_dg_cancel_ack(tvb, offset, pinfo, dcerpc_tree, &hdr);
6844 break;
6846 case PDU_CL_CANCEL:
6848 * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
6849 * but in at least one capture none of the Cl_cancel PDUs had a
6850 * body.
6852 /* XXX - we assume "frag_len" is the length of the body */
6853 if (hdr.frag_len != 0)
6854 dissect_dcerpc_dg_cancel(tvb, offset, pinfo, dcerpc_tree, &hdr);
6855 break;
6857 case PDU_NOCALL:
6858 /* Body is optional; if present, it's the same as PDU_FACK */
6859 /* XXX - we assume "frag_len" is the length of the body */
6860 if (hdr.frag_len != 0)
6861 dissect_dcerpc_dg_fack(tvb, offset, pinfo, dcerpc_tree, &hdr);
6862 break;
6864 case PDU_FACK:
6865 /* Body is optional */
6866 /* XXX - we assume "frag_len" is the length of the body */
6867 if (hdr.frag_len != 0)
6868 dissect_dcerpc_dg_fack(tvb, offset, pinfo, dcerpc_tree, &hdr);
6869 break;
6871 case PDU_REJECT:
6872 case PDU_FAULT:
6873 dissect_dcerpc_dg_reject_fault(tvb, offset, pinfo, dcerpc_tree, &hdr);
6874 break;
6876 case PDU_REQ:
6877 dissect_dcerpc_dg_rqst(tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
6878 break;
6880 case PDU_RESP:
6881 dissect_dcerpc_dg_resp(tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
6882 break;
6884 /* these requests have no body */
6885 case PDU_ACK:
6886 case PDU_PING:
6887 dissect_dcerpc_dg_ping_ack(tvb, offset, pinfo, dcerpc_tree, &hdr, conv);
6888 break;
6889 case PDU_WORKING:
6890 default:
6891 break;
6894 return true;
6897 static void
6898 dcerpc_auth_subdissector_list_free(void *p, void *user_data _U_)
6900 g_free(p);
6903 static void
6904 dcerpc_shutdown(void)
6906 g_slist_foreach(dcerpc_auth_subdissector_list, dcerpc_auth_subdissector_list_free, NULL);
6907 g_slist_free(dcerpc_auth_subdissector_list);
6908 g_hash_table_destroy(dcerpc_uuids);
6909 tvb_free(tvb_trailer_signature);
6912 void
6913 proto_register_dcerpc(void)
6915 static hf_register_info hf[] = {
6916 { &hf_dcerpc_request_in,
6917 { "Request in frame", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE,
6918 FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0, "This packet is a response to the packet with this number", HFILL }},
6919 { &hf_dcerpc_response_in,
6920 { "Response in frame", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
6921 FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0, "This packet will be responded in the packet with this number", HFILL }},
6922 { &hf_dcerpc_referent_id32,
6923 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
6924 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
6925 { &hf_dcerpc_referent_id64,
6926 { "Referent ID", "dcerpc.referent_id64", FT_UINT64, BASE_HEX,
6927 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
6928 { &hf_dcerpc_ver,
6929 { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6930 { &hf_dcerpc_ver_minor,
6931 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6932 { &hf_dcerpc_packet_type,
6933 { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS(pckt_vals), 0x0, NULL, HFILL }},
6934 { &hf_dcerpc_cn_flags,
6935 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6936 { &hf_dcerpc_cn_flags_first_frag,
6937 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_FIRST_FRAG, NULL, HFILL }},
6938 { &hf_dcerpc_cn_flags_last_frag,
6939 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_LAST_FRAG, NULL, HFILL }},
6940 { &hf_dcerpc_cn_flags_cancel_pending,
6941 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_PENDING_CANCEL, NULL, HFILL }},
6942 { &hf_dcerpc_cn_flags_reserved,
6943 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_RESERVED_1, NULL, HFILL }},
6944 { &hf_dcerpc_cn_flags_mpx,
6945 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_CONC_MPX, NULL, HFILL }},
6946 { &hf_dcerpc_cn_flags_dne,
6947 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_DID_NOT_EXECUTE, NULL, HFILL }},
6948 { &hf_dcerpc_cn_flags_maybe,
6949 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_MAYBE, NULL, HFILL }},
6950 { &hf_dcerpc_cn_flags_object,
6951 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_OBJECT_UUID, NULL, HFILL }},
6952 { &hf_dcerpc_drep,
6953 { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6954 { &hf_dcerpc_drep_byteorder,
6955 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS(drep_byteorder_vals), 0x0, NULL, HFILL }},
6956 { &hf_dcerpc_ndr_padding,
6957 { "NDR-Padding", "dcerpc.ndr_padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6958 { &hf_dcerpc_drep_character,
6959 { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS(drep_character_vals), 0x0, NULL, HFILL }},
6960 { &hf_dcerpc_drep_fp,
6961 { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS(drep_fp_vals), 0x0, NULL, HFILL }},
6962 { &hf_dcerpc_cn_frag_len,
6963 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6964 { &hf_dcerpc_cn_auth_len,
6965 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6966 { &hf_dcerpc_cn_call_id,
6967 { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6968 { &hf_dcerpc_cn_max_xmit,
6969 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6970 { &hf_dcerpc_cn_max_recv,
6971 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6972 { &hf_dcerpc_cn_assoc_group,
6973 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6974 { &hf_dcerpc_cn_num_ctx_items,
6975 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6976 { &hf_dcerpc_cn_ctx_item,
6977 { "Ctx Item", "dcerpc.cn_ctx_item", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6978 { &hf_dcerpc_cn_ctx_id,
6979 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6980 { &hf_dcerpc_cn_num_trans_items,
6981 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6982 { &hf_dcerpc_cn_bind_abstract_syntax,
6983 { "Abstract Syntax", "dcerpc.cn_bind_abstract_syntax", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6984 { &hf_dcerpc_cn_bind_if_id,
6985 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6986 { &hf_dcerpc_cn_bind_if_ver,
6987 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6988 { &hf_dcerpc_cn_bind_if_ver_minor,
6989 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6990 { &hf_dcerpc_cn_bind_trans_syntax,
6991 { "Transfer Syntax", "dcerpc.cn_bind_trans", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6992 { &hf_dcerpc_cn_bind_trans_id,
6993 { "ID", "dcerpc.cn_bind_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6994 { &hf_dcerpc_cn_bind_trans_ver,
6995 { "ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6996 { &hf_dcerpc_cn_bind_trans_btfn, /* [MS-RPCE] 2.2.2.14 */
6997 {"Bind Time Features", "dcerpc.cn_bind_trans_btfn", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
6998 { &hf_dcerpc_cn_bind_trans_btfn_01,
6999 { "Security Context Multiplexing Supported", "dcerpc.cn_bind_trans_btfn.01", FT_BOOLEAN, 16, NULL, 0x0001, NULL, HFILL }},
7000 { &hf_dcerpc_cn_bind_trans_btfn_02,
7001 { "Keep Connection On Orphan Supported", "dcerpc.cn_bind_trans_btfn.02", FT_BOOLEAN, 16, NULL, 0x0002, NULL, HFILL }},
7002 { &hf_dcerpc_cn_bind_trans_btfn_04,
7003 { "Support SHA512 PREAUTH Verification", "dcerpc.cn_bind_trans_btfn.04", FT_BOOLEAN, 16, NULL, 0x0004, NULL, HFILL }},
7004 { &hf_dcerpc_cn_bind_trans_btfn_08,
7005 { "Support protection of all PDUs", "dcerpc.cn_bind_trans_btfn.08", FT_BOOLEAN, 16, NULL, 0x0008, NULL, HFILL }},
7006 { &hf_dcerpc_cn_alloc_hint,
7007 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7008 { &hf_dcerpc_cn_sec_addr_len,
7009 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7010 { &hf_dcerpc_cn_sec_addr,
7011 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7012 { &hf_dcerpc_cn_num_results,
7013 { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7014 { &hf_dcerpc_cn_ack_result,
7015 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, NULL, HFILL }},
7016 { &hf_dcerpc_cn_ack_reason,
7017 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, NULL, HFILL }},
7018 { &hf_dcerpc_cn_ack_trans_id,
7019 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7020 { &hf_dcerpc_cn_ack_trans_ver,
7021 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7022 { &hf_dcerpc_cn_reject_reason,
7023 { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, NULL, HFILL }},
7024 { &hf_dcerpc_cn_num_protocols,
7025 { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7026 { &hf_dcerpc_cn_protocol_ver_major,
7027 { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7028 { &hf_dcerpc_cn_protocol_ver_minor,
7029 { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7030 { &hf_dcerpc_cn_cancel_count,
7031 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7032 { &hf_dcerpc_cn_fault_flags,
7033 { "Fault flags", "dcerpc.cn_fault_flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
7034 { &hf_dcerpc_cn_fault_flags_extended_error_info,
7035 { "Extended error information present", "dcerpc.cn_fault_flags.extended_error", FT_BOOLEAN, 8, NULL, 0x1, NULL, HFILL }},
7036 { &hf_dcerpc_cn_status,
7037 { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, NULL, HFILL }},
7038 { &hf_dcerpc_cn_deseg_req,
7039 { "Desegmentation Required", "dcerpc.cn_deseg_req", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7040 { &hf_dcerpc_auth_type,
7041 { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS(authn_protocol_vals), 0x0, NULL, HFILL }},
7042 { &hf_dcerpc_auth_level,
7043 { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, NULL, HFILL }},
7044 { &hf_dcerpc_auth_pad_len,
7045 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7046 { &hf_dcerpc_auth_rsrvd,
7047 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7048 { &hf_dcerpc_auth_ctx_id,
7049 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7050 { &hf_dcerpc_dg_flags1,
7051 { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
7052 { &hf_dcerpc_dg_flags1_rsrvd_01,
7053 { "Reserved for implementation", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_RESERVED_01, NULL, HFILL }},
7054 { &hf_dcerpc_dg_flags1_last_frag,
7055 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_LASTFRAG, NULL, HFILL }},
7056 { &hf_dcerpc_dg_flags1_frag,
7057 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_FRAG, NULL, HFILL }},
7058 { &hf_dcerpc_dg_flags1_nofack,
7059 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_NOFACK, NULL, HFILL }},
7060 { &hf_dcerpc_dg_flags1_maybe,
7061 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_MAYBE, NULL, HFILL }},
7062 { &hf_dcerpc_dg_flags1_idempotent,
7063 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_IDEMPOTENT, NULL, HFILL }},
7064 { &hf_dcerpc_dg_flags1_broadcast,
7065 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_BROADCAST, NULL, HFILL }},
7066 { &hf_dcerpc_dg_flags1_rsrvd_80,
7067 { "Reserved for implementation", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_RESERVED_80, NULL, HFILL }},
7068 { &hf_dcerpc_dg_flags2,
7069 { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
7070 { &hf_dcerpc_dg_flags2_rsrvd_01,
7071 { "Reserved for implementation", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_01, NULL, HFILL }},
7072 { &hf_dcerpc_dg_flags2_cancel_pending,
7073 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_CANCEL_PENDING, NULL, HFILL }},
7074 { &hf_dcerpc_dg_flags2_rsrvd_04,
7075 { "Reserved for future use (MBZ)", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_04, NULL, HFILL }},
7076 { &hf_dcerpc_dg_flags2_rsrvd_08,
7077 { "Reserved for future use (MBZ)", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_08, NULL, HFILL }},
7078 { &hf_dcerpc_dg_flags2_rsrvd_10,
7079 { "Reserved for future use (MBZ)", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_10, NULL, HFILL }},
7080 { &hf_dcerpc_dg_flags2_rsrvd_20,
7081 { "Reserved for future use (MBZ)", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_20, NULL, HFILL }},
7082 { &hf_dcerpc_dg_flags2_rsrvd_40,
7083 { "Reserved for future use (MBZ)", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_40, NULL, HFILL }},
7084 { &hf_dcerpc_dg_flags2_rsrvd_80,
7085 { "Reserved for future use (MBZ)", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_80, NULL, HFILL }},
7086 { &hf_dcerpc_dg_serial_lo,
7087 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
7088 { &hf_dcerpc_dg_serial_hi,
7089 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
7090 { &hf_dcerpc_dg_ahint,
7091 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
7092 { &hf_dcerpc_dg_ihint,
7093 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
7094 { &hf_dcerpc_dg_frag_len,
7095 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7096 { &hf_dcerpc_dg_frag_num,
7097 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7098 { &hf_dcerpc_dg_auth_proto,
7099 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS(authn_protocol_vals), 0x0, NULL, HFILL }},
7100 { &hf_dcerpc_dg_seqnum,
7101 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7102 { &hf_dcerpc_dg_server_boot,
7103 { "Server boot time", "dcerpc.dg_server_boot", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0, NULL, HFILL }},
7104 { &hf_dcerpc_dg_if_ver,
7105 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7106 { &hf_dcerpc_krb5_av_prot_level,
7107 { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, NULL, HFILL }},
7108 { &hf_dcerpc_krb5_av_key_vers_num,
7109 { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7110 { &hf_dcerpc_krb5_av_key_auth_verifier,
7111 { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7112 { &hf_dcerpc_obj_id,
7113 { "Object", "dcerpc.obj_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7114 { &hf_dcerpc_dg_if_id,
7115 { "Interface", "dcerpc.dg_if_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7116 { &hf_dcerpc_dg_act_id,
7117 { "Activity", "dcerpc.dg_act_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7118 { &hf_dcerpc_opnum,
7119 { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7121 { &hf_dcerpc_dg_cancel_vers,
7122 { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7124 { &hf_dcerpc_dg_cancel_id,
7125 { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7127 { &hf_dcerpc_dg_server_accepting_cancels,
7128 { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7130 { &hf_dcerpc_dg_fack_vers,
7131 { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7133 { &hf_dcerpc_dg_fack_window_size,
7134 { "Window Size", "dcerpc.fack_window_size", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7136 { &hf_dcerpc_dg_fack_max_tsdu,
7137 { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7139 { &hf_dcerpc_dg_fack_max_frag_size,
7140 { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7142 { &hf_dcerpc_dg_fack_serial_num,
7143 { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7145 { &hf_dcerpc_dg_fack_selack_len,
7146 { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7148 { &hf_dcerpc_dg_fack_selack,
7149 { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
7151 { &hf_dcerpc_dg_status,
7152 { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, NULL, HFILL }},
7154 { &hf_dcerpc_array_max_count,
7155 { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
7157 { &hf_dcerpc_array_offset,
7158 { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
7160 { &hf_dcerpc_array_actual_count,
7161 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
7163 { &hf_dcerpc_op,
7164 { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7166 { &hf_dcerpc_null_pointer,
7167 { "NULL Pointer", "dcerpc.null_pointer", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7169 { &hf_dcerpc_fragments,
7170 { "Reassembled DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
7171 NULL, 0x0, NULL, HFILL }},
7173 { &hf_dcerpc_fragment,
7174 { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM, BASE_NONE,
7175 NULL, 0x0, NULL, HFILL }},
7177 { &hf_dcerpc_fragment_overlap,
7178 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE,
7179 NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
7181 { &hf_dcerpc_fragment_overlap_conflict,
7182 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE,
7183 NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
7185 { &hf_dcerpc_fragment_multiple_tails,
7186 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE,
7187 NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
7189 { &hf_dcerpc_fragment_too_long_fragment,
7190 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE,
7191 NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
7193 { &hf_dcerpc_fragment_error,
7194 { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE,
7195 NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
7197 { &hf_dcerpc_fragment_count,
7198 { "Fragment count", "dcerpc.fragment.count", FT_UINT32, BASE_DEC,
7199 NULL, 0x0, NULL, HFILL }},
7201 { &hf_dcerpc_time,
7202 { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE,
7203 NULL, 0, "Time between Request and Response for DCE-RPC calls", HFILL }},
7205 { &hf_dcerpc_reassembled_in,
7206 { "Reassembled PDU in frame", "dcerpc.reassembled_in", FT_FRAMENUM, BASE_NONE,
7207 NULL, 0x0, "The DCE/RPC PDU is completely reassembled in the packet with this number", HFILL }},
7209 { &hf_dcerpc_reassembled_length,
7210 { "Reassembled DCE/RPC length", "dcerpc.reassembled.length", FT_UINT32, BASE_DEC,
7211 NULL, 0x0, "The total length of the reassembled payload", HFILL }},
7213 { &hf_dcerpc_unknown_if_id,
7214 { "Unknown DCERPC interface id", "dcerpc.unknown_if_id", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7216 { &hf_dcerpc_cn_rts_flags,
7217 { "RTS Flags", "dcerpc.cn_rts_flags", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
7218 { &hf_dcerpc_cn_rts_flags_ping,
7219 { "Ping", "dcerpc.cn_rts.flags.ping", FT_BOOLEAN, 16, TFS(&tfs_set_notset), RTS_FLAG_PING, NULL, HFILL }},
7220 { &hf_dcerpc_cn_rts_flags_other_cmd,
7221 { "Other Cmd", "dcerpc.cn_rts_flags.other_cmd", FT_BOOLEAN, 16, TFS(&tfs_set_notset), RTS_FLAG_OTHER_CMD, NULL, HFILL }},
7222 { &hf_dcerpc_cn_rts_flags_recycle_channel,
7223 { "Recycle Channel", "dcerpc.cn_rts_flags.recycle_channel", FT_BOOLEAN, 16, TFS(&tfs_set_notset), RTS_FLAG_RECYCLE_CHANNEL, NULL, HFILL }},
7224 { &hf_dcerpc_cn_rts_flags_in_channel,
7225 { "In Channel", "dcerpc.cn_rts_flags.in_channel", FT_BOOLEAN, 16, TFS(&tfs_set_notset), RTS_FLAG_IN_CHANNEL, NULL, HFILL }},
7226 { &hf_dcerpc_cn_rts_flags_out_channel,
7227 { "Out Channel", "dcerpc.cn_rts_flags.out_channel", FT_BOOLEAN, 16, TFS(&tfs_set_notset), RTS_FLAG_OUT_CHANNEL, NULL, HFILL }},
7228 { &hf_dcerpc_cn_rts_flags_eof,
7229 { "EOF", "dcerpc.cn_rts_flags.eof", FT_BOOLEAN, 16, TFS(&tfs_set_notset), RTS_FLAG_EOF, NULL, HFILL }},
7230 { &hf_dcerpc_cn_rts_commands_nb,
7231 { "RTS Number of Commands", "dcerpc.cn_rts_commands_nb", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7232 { &hf_dcerpc_cn_rts_command,
7233 { "RTS Command", "dcerpc.cn_rts_command", FT_UINT32, BASE_HEX, VALS(rts_command_vals), 0x0, NULL, HFILL }},
7234 { &hf_dcerpc_cn_rts_command_receivewindowsize,
7235 {"Receive Window Size", "dcerpc.cn_rts_command.receivewindowsize", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
7236 { &hf_dcerpc_cn_rts_command_fack_bytesreceived,
7237 {"Bytes Received", "dcerpc.cn_rts_command.fack.bytesreceived", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
7238 { &hf_dcerpc_cn_rts_command_fack_availablewindow,
7239 {"Available Window", "dcerpc.cn_rts_command.fack.availablewindow", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
7240 { &hf_dcerpc_cn_rts_command_fack_channelcookie,
7241 {"Channel Cookie", "dcerpc.cn_rts_command.fack.channelcookie", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7242 { &hf_dcerpc_cn_rts_command_connectiontimeout,
7243 {"Connection Timeout", "dcerpc.cn_rts_command.connectiontimeout", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7244 { &hf_dcerpc_cn_rts_command_cookie,
7245 {"Cookie", "dcerpc.cn_rts_command.cookie", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7246 { &hf_dcerpc_cn_rts_command_channellifetime,
7247 {"Channel Lifetime", "dcerpc.cn_rts_command.channellifetime", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7248 { &hf_dcerpc_cn_rts_command_clientkeepalive,
7249 {"Client Keepalive", "dcerpc.cn_rts_command.clientkeepalive", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
7250 { &hf_dcerpc_cn_rts_command_version,
7251 {"Version", "dcerpc.cn_rts_command.version", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
7252 { &hf_dcerpc_cn_rts_command_conformancecount,
7253 {"Conformance Count", "dcerpc.cn_rts_command.padding.conformancecount", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
7254 { &hf_dcerpc_cn_rts_command_padding,
7255 { "Padding", "dcerpc.cn_rts_command.padding.padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
7256 { &hf_dcerpc_cn_rts_command_addrtype,
7257 { "Address Type", "dcerpc.cn_rts_command.addrtype", FT_UINT32, BASE_DEC, VALS(rts_addresstype_vals), 0x0, NULL, HFILL }},
7258 { &hf_dcerpc_cn_rts_command_associationgroupid,
7259 {"Association Group ID", "dcerpc.cn_rts_command.associationgroupid", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7260 { &hf_dcerpc_cn_rts_command_forwarddestination,
7261 {"Forward Destination", "dcerpc.cn_rts_command.forwarddestination", FT_UINT32, BASE_DEC, VALS(rts_forward_destination_vals), 0x0, NULL, HFILL }},
7262 { &hf_dcerpc_cn_rts_command_pingtrafficsentnotify,
7263 {"Ping Traffic Sent Notify", "dcerpc.cn_rts_command.pingtrafficsentnotify", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
7264 { &hf_dcerpc_sec_vt_signature,
7265 {"SEC_VT_SIGNATURE", "dcerpc.rpc_sec_vt.signature", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7266 { &hf_dcerpc_sec_vt_command_end,
7267 {"SEC_VT_COMMAND_END", "dcerpc.rpc_sec_vt.command.end", FT_BOOLEAN, 16, NULL, 0x4000, NULL, HFILL }},
7268 { &hf_dcerpc_sec_vt_command_must,
7269 {"SEC_VT_MUST_PROCESS_COMMAND", "dcerpc.rpc_sec_vt.command.must_process", FT_BOOLEAN, 16, NULL, 0x8000, NULL, HFILL }},
7270 { &hf_dcerpc_sec_vt_command_cmd,
7271 {"Cmd", "dcerpc.rpc_sec_vt.command.cmd", FT_UINT16, BASE_HEX, VALS(sec_vt_command_cmd_vals), 0x3fff, NULL, HFILL }},
7272 { &hf_dcerpc_sec_vt_command,
7273 {"Command", "dcerpc.rpc_sec_vt.command", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
7274 { &hf_dcerpc_sec_vt_command_length,
7275 {"Length", "dcerpc.rpc_sec_vt.command.length", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL}},
7276 { &hf_dcerpc_sec_vt_bitmask,
7277 {"rpc_sec_vt_bitmask", "dcerpc.rpc_sec_vt.bitmask", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
7278 { &hf_dcerpc_sec_vt_bitmask_sign,
7279 {"CLIENT_SUPPORT_HEADER_SIGNING", "dcerpc.rpc_sec_vt.bitmask.sign", FT_BOOLEAN, 32, NULL, 0x1, NULL, HFILL }},
7280 { &hf_dcerpc_sec_vt_pcontext_uuid,
7281 {"UUID", "dcerpc.rpc_sec_vt.pcontext.interface.uuid", FT_GUID, BASE_NONE, NULL, 0, NULL, HFILL }},
7282 { &hf_dcerpc_sec_vt_pcontext_ver,
7283 {"Version", "dcerpc.rpc_sec_vt.pcontext.interface.ver", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
7284 { &hf_dcerpc_sec_vt_preauth_salt,
7285 {"Salt", "dcerpc.rpc_sec_vt.preauth.salt", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7286 { &hf_dcerpc_sec_vt_preauth_sha512,
7287 {"SHA512 Hash", "dcerpc.rpc_sec_vt.preauth.sha512", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7288 { &hf_dcerpc_reserved,
7289 {"Reserved", "dcerpc.reserved", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
7290 { &hf_dcerpc_unknown,
7291 {"Unknown", "dcerpc.unknown", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
7292 { &hf_dcerpc_missalign,
7293 {"missalign", "dcerpc.missalign", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
7294 /* Generated from convert_proto_tree_add_text.pl */
7295 { &hf_dcerpc_duplicate_ptr, { "duplicate PTR", "dcerpc.duplicate_ptr", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7296 { &hf_dcerpc_encrypted_stub_data, { "Encrypted stub data", "dcerpc.encrypted_stub_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7297 { &hf_dcerpc_decrypted_stub_data, { "Decrypted stub data", "dcerpc.decrypted_stub_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7298 { &hf_dcerpc_payload_stub_data, { "Payload stub data", "dcerpc.payload_stub_data", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7299 { &hf_dcerpc_stub_data_with_sec_vt, { "Stub data with rpc_sec_verification_trailer", "dcerpc.stub_data_with_sec_vt", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7300 { &hf_dcerpc_stub_data, { "Stub data", "dcerpc.stub_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7301 { &hf_dcerpc_auth_padding, { "Auth Padding", "dcerpc.auth_padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7302 { &hf_dcerpc_auth_info, { "Auth Info", "dcerpc.auth_info", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7303 { &hf_dcerpc_auth_credentials, { "Auth Credentials", "dcerpc.auth_credentials", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7304 { &hf_dcerpc_fault_stub_data, { "Fault stub data", "dcerpc.fault_stub_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7305 { &hf_dcerpc_fragment_data, { "Fragment data", "dcerpc.fragment_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7306 { &hf_dcerpc_cmd_client_ipv4, { "RTS Client address", "dcerpc.cmd_client_ipv4", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7307 { &hf_dcerpc_cmd_client_ipv6, { "RTS Client address", "dcerpc.cmd_client_ipv6", FT_IPv6, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7308 { &hf_dcerpc_authentication_verifier, { "Authentication verifier", "dcerpc.authentication_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7310 static int *ett[] = {
7311 &ett_dcerpc,
7312 &ett_dcerpc_cn_flags,
7313 &ett_dcerpc_cn_ctx,
7314 &ett_dcerpc_cn_iface,
7315 &ett_dcerpc_cn_trans_syntax,
7316 &ett_dcerpc_cn_trans_btfn,
7317 &ett_dcerpc_cn_bind_trans_btfn,
7318 &ett_dcerpc_cn_rts_flags,
7319 &ett_dcerpc_cn_rts_command,
7320 &ett_dcerpc_cn_rts_pdu,
7321 &ett_dcerpc_drep,
7322 &ett_dcerpc_dg_flags1,
7323 &ett_dcerpc_dg_flags2,
7324 &ett_dcerpc_pointer_data,
7325 &ett_dcerpc_string,
7326 &ett_dcerpc_fragments,
7327 &ett_dcerpc_fragment,
7328 &ett_dcerpc_krb5_auth_verf,
7329 &ett_dcerpc_auth_info,
7330 &ett_dcerpc_verification_trailer,
7331 &ett_dcerpc_sec_vt_command,
7332 &ett_dcerpc_sec_vt_bitmask,
7333 &ett_dcerpc_sec_vt_pcontext,
7334 &ett_dcerpc_sec_vt_header,
7335 &ett_dcerpc_sec_vt_preauth,
7336 &ett_dcerpc_complete_stub_data,
7337 &ett_dcerpc_fault_flags,
7338 &ett_dcerpc_fault_stub_data,
7341 static ei_register_info ei[] = {
7342 { &ei_dcerpc_fragment, { "dcerpc.fragment.reassemble", PI_REASSEMBLE, PI_CHAT, "Fragment", EXPFILL }},
7343 { &ei_dcerpc_fragment_reassembled, { "dcerpc.fragment_reassembled", PI_REASSEMBLE, PI_CHAT, "Fragment, reassembled", EXPFILL }},
7344 { &ei_dcerpc_cn_ctx_id_no_bind, { "dcerpc.cn_ctx_id.no_bind", PI_UNDECODED, PI_NOTE, "No bind info for interface Context ID", EXPFILL }},
7345 { &ei_dcerpc_no_request_found, { "dcerpc.no_request_found", PI_SEQUENCE, PI_NOTE, "No request to this DCE/RPC call found", EXPFILL }},
7346 { &ei_dcerpc_cn_status, { "dcerpc.cn_status.expert", PI_RESPONSE_CODE, PI_NOTE, "Fault", EXPFILL }},
7347 { &ei_dcerpc_fragment_multiple, { "dcerpc.fragment_multiple", PI_SEQUENCE, PI_CHAT, "Multiple DCE/RPC fragments/PDU's in one packet", EXPFILL }},
7348 #if 0 /* XXX - too much "output noise", removed for now */
7349 { &ei_dcerpc_context_change, { "dcerpc.context_change", PI_SEQUENCE, PI_CHAT, "Context change", EXPFILL }},
7350 #endif
7351 { &ei_dcerpc_bind_not_acknowledged, { "dcerpc.bind_not_acknowledged", PI_SEQUENCE, PI_WARN, "Bind not acknowledged", EXPFILL }},
7352 { &ei_dcerpc_verifier_unavailable, { "dcerpc.verifier_unavailable", PI_UNDECODED, PI_WARN, "Verifier unavailable", EXPFILL }},
7353 { &ei_dcerpc_invalid_pdu_authentication_attempt, { "dcerpc.invalid_pdu_authentication_attempt", PI_UNDECODED, PI_WARN, "Invalid authentication attempt", EXPFILL }},
7354 /* Generated from convert_proto_tree_add_text.pl */
7355 { &ei_dcerpc_long_frame, { "dcerpc.long_frame", PI_PROTOCOL, PI_WARN, "Long frame", EXPFILL }},
7356 { &ei_dcerpc_cn_rts_command, { "dcerpc.cn_rts_command.unknown", PI_PROTOCOL, PI_WARN, "unknown RTS command number", EXPFILL }},
7357 { &ei_dcerpc_not_implemented, { "dcerpc.not_implemented", PI_UNDECODED, PI_WARN, "dissection not implemented", EXPFILL }},
7360 /* Decode As handling */
7361 static build_valid_func dcerpc_da_build_value[1] = {dcerpc_value};
7362 static decode_as_value_t dcerpc_da_values = {dcerpc_prompt, 1, dcerpc_da_build_value};
7363 static decode_as_t dcerpc_da = {"dcerpc", "dcerpc.uuid",
7364 1, 0, &dcerpc_da_values, NULL, NULL,
7365 dcerpc_populate_list, decode_dcerpc_binding_reset, dcerpc_decode_as_change, dcerpc_decode_as_free};
7367 module_t *dcerpc_module;
7368 expert_module_t* expert_dcerpc;
7370 proto_dcerpc = proto_register_protocol("Distributed Computing Environment / Remote Procedure Call (DCE/RPC)", "DCERPC", "dcerpc");
7371 proto_register_field_array(proto_dcerpc, hf, array_length(hf));
7372 proto_register_subtree_array(ett, array_length(ett));
7373 expert_dcerpc = expert_register_protocol(proto_dcerpc);
7374 expert_register_field_array(expert_dcerpc, ei, array_length(ei));
7376 uuid_dissector_table = register_dissector_table(DCERPC_TABLE_NAME, "DCE/RPC UUIDs", proto_dcerpc, FT_GUID, BASE_HEX);
7379 * structures and data for
7380 * - per connection,
7381 * - per presentation context (bind)
7382 * - per authentication context
7384 dcerpc_connections = wmem_map_new_autoreset(wmem_epan_scope(),
7385 wmem_file_scope(),
7386 dcerpc_connection_hash,
7387 dcerpc_connection_equal);
7389 dcerpc_binds = wmem_map_new_autoreset(wmem_epan_scope(),
7390 wmem_file_scope(),
7391 dcerpc_bind_hash,
7392 dcerpc_bind_equal);
7394 dcerpc_auths = wmem_map_new_autoreset(wmem_epan_scope(),
7395 wmem_file_scope(),
7396 dcerpc_auth_context_hash,
7397 dcerpc_auth_context_equal);
7399 /* structures and data for CALL */
7400 dcerpc_cn_calls = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), dcerpc_cn_call_hash, dcerpc_cn_call_equal);
7401 dcerpc_dg_calls = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), dcerpc_dg_call_hash, dcerpc_dg_call_equal);
7403 /* structure and data for MATCHED */
7404 dcerpc_matched = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), dcerpc_matched_hash, dcerpc_matched_equal);
7406 register_init_routine(decode_dcerpc_inject_bindings);
7408 dcerpc_module = prefs_register_protocol(proto_dcerpc, NULL);
7409 prefs_register_bool_preference(dcerpc_module,
7410 "desegment_dcerpc",
7411 "Reassemble DCE/RPC messages spanning multiple TCP segments",
7412 "Whether the DCE/RPC dissector should reassemble messages"
7413 " spanning multiple TCP segments."
7414 " To use this option, you must also enable"
7415 " \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
7416 &dcerpc_cn_desegment);
7417 prefs_register_bool_preference(dcerpc_module,
7418 "reassemble_dcerpc",
7419 "Reassemble DCE/RPC fragments",
7420 "Whether the DCE/RPC dissector should reassemble fragmented DCE/RPC PDUs",
7421 &dcerpc_reassemble);
7424 * XXX - addresses_ports_reassembly_table_functions?
7425 * Or can a single connection-oriented DCE RPC session persist
7426 * over multiple transport layer connections?
7428 reassembly_table_register(&dcerpc_co_reassembly_table,
7429 &addresses_reassembly_table_functions);
7430 reassembly_table_register(&dcerpc_cl_reassembly_table,
7431 &dcerpc_cl_reassembly_table_functions);
7433 dcerpc_uuids = g_hash_table_new_full(dcerpc_uuid_hash, dcerpc_uuid_equal, g_free, g_free);
7434 dcerpc_tap = register_tap("dcerpc");
7436 register_decode_as(&dcerpc_da);
7438 register_srt_table(proto_dcerpc, NULL, 1, dcerpcstat_packet, dcerpcstat_init, dcerpcstat_param);
7440 tvb_trailer_signature = tvb_new_real_data(TRAILER_SIGNATURE,
7441 sizeof(TRAILER_SIGNATURE),
7442 sizeof(TRAILER_SIGNATURE));
7444 dcerpc_tcp_handle = register_dissector("dcerpc.tcp", dissect_dcerpc_tcp, proto_dcerpc);
7446 register_shutdown_routine(dcerpc_shutdown);
7449 void
7450 proto_reg_handoff_dcerpc(void)
7452 heur_dissector_add("tcp", dissect_dcerpc_tcp_heur, "DCE/RPC over TCP", "dcerpc_tcp", proto_dcerpc, HEURISTIC_ENABLE);
7453 heur_dissector_add("netbios", dissect_dcerpc_cn_pk, "DCE/RPC over NetBios", "dcerpc_netbios", proto_dcerpc, HEURISTIC_ENABLE);
7454 heur_dissector_add("udp", dissect_dcerpc_dg, "DCE/RPC over UDP", "dcerpc_udp", proto_dcerpc, HEURISTIC_ENABLE);
7455 heur_dissector_add("smb_transact", dissect_dcerpc_cn_smbpipe, "DCE/RPC over SMB", "dcerpc_smb_transact", proto_dcerpc, HEURISTIC_ENABLE);
7456 heur_dissector_add("smb2_pipe_subdissectors", dissect_dcerpc_cn_smb2, "DCE/RPC over SMB2", "dcerpc_smb2", proto_dcerpc, HEURISTIC_ENABLE);
7457 heur_dissector_add("http", dissect_dcerpc_cn_bs, "DCE/RPC over HTTP", "dcerpc_http", proto_dcerpc, HEURISTIC_ENABLE);
7458 dcerpc_smb_init(proto_dcerpc);
7460 dissector_add_for_decode_as("tcp.port", dcerpc_tcp_handle);
7462 guids_add_uuid(&uuid_data_repr_proto, "32bit NDR");
7463 guids_add_uuid(&uuid_ndr64, "64bit NDR");
7464 guids_add_uuid(&uuid_asyncemsmdb, "async MAPI");
7468 * Editor modelines - https://www.wireshark.org/tools/modelines.html
7470 * Local variables:
7471 * c-basic-offset: 4
7472 * tab-width: 8
7473 * indent-tabs-mode: nil
7474 * End:
7476 * vi: set shiftwidth=4 tabstop=8 expandtab:
7477 * :indentSize=4:tabSize=8:noTabs=true: