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 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 /* The DCE RPC specification can be found at:
27 * http://www.opengroup.org/dce/
33 #include <epan/packet.h>
34 #include <epan/exceptions.h>
35 #include <epan/prefs.h>
36 #include <epan/reassemble.h>
38 #include <epan/srt_table.h>
39 #include <epan/expert.h>
40 #include <epan/addr_resolv.h>
41 #include <epan/show_exception.h>
42 #include <epan/decode_as.h>
43 #include <epan/proto_data.h>
45 #include <wsutil/str_util.h>
46 #include "packet-tcp.h"
47 #include "packet-dcerpc.h"
48 #include "packet-dcerpc-nt.h"
50 void proto_register_dcerpc(void);
51 void proto_reg_handoff_dcerpc(void);
53 static int dcerpc_tap = -1;
55 /* 32bit Network Data Representation, see DCE/RPC Appendix I */
56 static e_guid_t uuid_data_repr_proto = { 0x8a885d04, 0x1ceb, 0x11c9,
57 { 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60 } };
59 /* 64bit Network Data Representation, introduced in Windows Server 2008 */
60 static e_guid_t uuid_ndr64 = { 0x71710533, 0xbeba, 0x4937,
61 { 0x83, 0x19, 0xb5, 0xdb, 0xef, 0x9c, 0xcc, 0x36 } };
63 /* see [MS-OXRPC] Appendix A: Full IDL, http://msdn.microsoft.com/en-us/library/ee217991%28v=exchg.80%29.aspx */
64 static e_guid_t uuid_asyncemsmdb = { 0x5261574a, 0x4572, 0x206e,
65 { 0xb2, 0x68, 0x6b, 0x19, 0x92, 0x13, 0xb4, 0xe4 } };
67 static const value_string pckt_vals[] = {
68 { PDU_REQ, "Request"},
70 { PDU_RESP, "Response"},
71 { PDU_FAULT, "Fault"},
72 { PDU_WORKING, "Working"},
73 { PDU_NOCALL, "Nocall"},
74 { PDU_REJECT, "Reject"},
76 { PDU_CL_CANCEL, "Cl_cancel"},
78 { PDU_CANCEL_ACK, "Cancel_ack"},
80 { PDU_BIND_ACK, "Bind_ack"},
81 { PDU_BIND_NAK, "Bind_nak"},
82 { PDU_ALTER, "Alter_context"},
83 { PDU_ALTER_ACK, "Alter_context_resp"},
84 { PDU_AUTH3, "AUTH3"},
85 { PDU_SHUTDOWN, "Shutdown"},
86 { PDU_CO_CANCEL, "Co_cancel"},
87 { PDU_ORPHANED, "Orphaned"},
88 { PDU_RTS, "RPC-over-HTTP RTS"},
92 static const value_string drep_byteorder_vals[] = {
94 { 1, "Little-endian" },
98 static const value_string drep_character_vals[] = {
104 #define DCE_RPC_DREP_FP_IEEE 0
105 #define DCE_RPC_DREP_FP_VAX 1
106 #define DCE_RPC_DREP_FP_CRAY 2
107 #define DCE_RPC_DREP_FP_IBM 3
109 static const value_string drep_fp_vals[] = {
110 { DCE_RPC_DREP_FP_IEEE, "IEEE" },
111 { DCE_RPC_DREP_FP_VAX, "VAX" },
112 { DCE_RPC_DREP_FP_CRAY, "Cray" },
113 { DCE_RPC_DREP_FP_IBM, "IBM" },
118 * Authentication services.
120 static const value_string authn_protocol_vals[] = {
121 { DCE_C_RPC_AUTHN_PROTOCOL_NONE, "None" },
122 { DCE_C_RPC_AUTHN_PROTOCOL_KRB5, "Kerberos 5" },
123 { DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO, "SPNEGO" },
124 { DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP, "NTLMSSP" },
125 { DCE_C_RPC_AUTHN_PROTOCOL_GSS_SCHANNEL, "SCHANNEL SSP" },
126 { DCE_C_RPC_AUTHN_PROTOCOL_GSS_KERBEROS, "Kerberos SSP" },
127 { DCE_C_RPC_AUTHN_PROTOCOL_DPA,
128 "Distributed Password Authentication SSP"},
129 { DCE_C_RPC_AUTHN_PROTOCOL_MSN, "MSN SSP"},
130 { DCE_C_RPC_AUTHN_PROTOCOL_DIGEST, "Digest SSP"},
131 { DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN, "NETLOGON Secure Channel" },
132 { DCE_C_RPC_AUTHN_PROTOCOL_MQ, "MSMQ SSP"},
139 static const value_string authn_level_vals[] = {
140 { DCE_C_AUTHN_LEVEL_NONE, "None" },
141 { DCE_C_AUTHN_LEVEL_CONNECT, "Connect" },
142 { DCE_C_AUTHN_LEVEL_CALL, "Call" },
143 { DCE_C_AUTHN_LEVEL_PKT, "Packet" },
144 { DCE_C_AUTHN_LEVEL_PKT_INTEGRITY, "Packet integrity" },
145 { DCE_C_AUTHN_LEVEL_PKT_PRIVACY, "Packet privacy" },
150 * Flag bits in first flag field in connectionless PDU header.
152 #define PFCL1_RESERVED_01 0x01 /* Reserved for use by implementations */
153 #define PFCL1_LASTFRAG 0x02 /* If set, the PDU is the last
154 * fragment of a multi-PDU
156 #define PFCL1_FRAG 0x04 /* If set, the PDU is a fragment of
157 a multi-PDU transmission */
158 #define PFCL1_NOFACK 0x08 /* If set, the receiver is not
159 * requested to send a `fack' PDU
160 * for the fragment */
161 #define PFCL1_MAYBE 0x10 /* If set, the PDU is for a `maybe'
163 #define PFCL1_IDEMPOTENT 0x20 /* If set, the PDU is for an idempotent
165 #define PFCL1_BROADCAST 0x40 /* If set, the PDU is for a broadcast
167 #define PFCL1_RESERVED_80 0x80 /* Reserved for use by implementations */
170 * Flag bits in second flag field in connectionless PDU header.
172 #define PFCL2_RESERVED_01 0x01 /* Reserved for use by implementations */
173 #define PFCL2_CANCEL_PENDING 0x02 /* Cancel pending at the call end */
174 #define PFCL2_RESERVED_04 0x04 /* Reserved for future use */
175 #define PFCL2_RESERVED_08 0x08 /* Reserved for future use */
176 #define PFCL2_RESERVED_10 0x10 /* Reserved for future use */
177 #define PFCL2_RESERVED_20 0x20 /* Reserved for future use */
178 #define PFCL2_RESERVED_40 0x40 /* Reserved for future use */
179 #define PFCL2_RESERVED_80 0x80 /* Reserved for future use */
182 * Flag bits in connection-oriented PDU header.
184 #define PFC_FIRST_FRAG 0x01 /* First fragment */
185 #define PFC_LAST_FRAG 0x02 /* Last fragment */
186 #define PFC_PENDING_CANCEL 0x04 /* Cancel was pending at sender */
187 #define PFC_RESERVED_1 0x08
188 #define PFC_CONC_MPX 0x10 /* supports concurrent multiplexing
189 * of a single connection. */
190 #define PFC_DID_NOT_EXECUTE 0x20 /* only meaningful on `fault' packet;
191 * if true, guaranteed call did not
193 #define PFC_MAYBE 0x40 /* `maybe' call semantics requested */
194 #define PFC_OBJECT_UUID 0x80 /* if true, a non-nil object UUID
195 * was specified in the handle, and
196 * is present in the optional object
197 * field. If false, the object field
201 * Tests whether a connection-oriented PDU is fragmented; returns TRUE if
202 * it's not fragmented (i.e., this is both the first *and* last fragment),
203 * and FALSE otherwise.
205 #define PFC_NOT_FRAGMENTED(hdr) \
206 ((hdr->flags&(PFC_FIRST_FRAG|PFC_LAST_FRAG)) == (PFC_FIRST_FRAG|PFC_LAST_FRAG))
209 * Presentation context negotiation result.
211 static const value_string p_cont_result_vals[] = {
213 { 1, "User rejection" },
214 { 2, "Provider rejection" },
215 { 3, "Negotiate ACK" }, /* [MS-RPCE] 2.2.2.4 */
220 * Presentation context negotiation rejection reasons.
222 static const value_string p_provider_reason_vals[] = {
223 { 0, "Reason not specified" },
224 { 1, "Abstract syntax not supported" },
225 { 2, "Proposed transfer syntaxes not supported" },
226 { 3, "Local limit exceeded" },
233 #define REASON_NOT_SPECIFIED 0
234 #define TEMPORARY_CONGESTION 1
235 #define LOCAL_LIMIT_EXCEEDED 2
236 #define CALLED_PADDR_UNKNOWN 3 /* not used */
237 #define PROTOCOL_VERSION_NOT_SUPPORTED 4
238 #define DEFAULT_CONTEXT_NOT_SUPPORTED 5 /* not used */
239 #define USER_DATA_NOT_READABLE 6 /* not used */
240 #define NO_PSAP_AVAILABLE 7 /* not used */
241 #define AUTH_TYPE_NOT_RECOGNIZED 8 /* [MS-RPCE] 2.2.2.5 */
242 #define INVALID_CHECKSUM 9 /* [MS-RPCE] 2.2.2.5 */
244 static const value_string reject_reason_vals[] = {
245 { REASON_NOT_SPECIFIED, "Reason not specified" },
246 { TEMPORARY_CONGESTION, "Temporary congestion" },
247 { LOCAL_LIMIT_EXCEEDED, "Local limit exceeded" },
248 { CALLED_PADDR_UNKNOWN, "Called paddr unknown" },
249 { PROTOCOL_VERSION_NOT_SUPPORTED, "Protocol version not supported" },
250 { DEFAULT_CONTEXT_NOT_SUPPORTED, "Default context not supported" },
251 { USER_DATA_NOT_READABLE, "User data not readable" },
252 { NO_PSAP_AVAILABLE, "No PSAP available" },
253 { AUTH_TYPE_NOT_RECOGNIZED, "Authentication type not recognized" },
254 { INVALID_CHECKSUM, "Invalid checksum" },
259 * Reject status codes.
261 static const value_string reject_status_vals[] = {
262 { 0, "Stub-defined exception" },
263 { 0x00000001, "nca_s_fault_other" },
264 { 0x00000005, "nca_s_fault_access_denied" },
265 { 0x000006f7, "nca_s_fault_ndr" },
266 { 0x000006d8, "nca_s_fault_cant_perform" },
267 { 0x00000721, "nca_s_fault_sec_pkg_error" },
268 { 0x1c000001, "nca_s_fault_int_div_by_zero" },
269 { 0x1c000002, "nca_s_fault_addr_error" },
270 { 0x1c000003, "nca_s_fault_fp_div_zero" },
271 { 0x1c000004, "nca_s_fault_fp_underflow" },
272 { 0x1c000005, "nca_s_fault_fp_overflow" },
273 { 0x1c000006, "nca_s_fault_invalid_tag" },
274 { 0x1c000007, "nca_s_fault_invalid_bound" },
275 { 0x1c000008, "nca_rpc_version_mismatch" },
276 { 0x1c000009, "nca_unspec_reject" },
277 { 0x1c00000a, "nca_s_bad_actid" },
278 { 0x1c00000b, "nca_who_are_you_failed" },
279 { 0x1c00000c, "nca_manager_not_entered" },
280 { 0x1c00000d, "nca_s_fault_cancel" },
281 { 0x1c00000e, "nca_s_fault_ill_inst" },
282 { 0x1c00000f, "nca_s_fault_fp_error" },
283 { 0x1c000010, "nca_s_fault_int_overflow" },
284 { 0x1c000014, "nca_s_fault_pipe_empty" },
285 { 0x1c000015, "nca_s_fault_pipe_closed" },
286 { 0x1c000016, "nca_s_fault_pipe_order" },
287 { 0x1c000017, "nca_s_fault_pipe_discipline" },
288 { 0x1c000018, "nca_s_fault_pipe_comm_error" },
289 { 0x1c000019, "nca_s_fault_pipe_memory" },
290 { 0x1c00001a, "nca_s_fault_context_mismatch" },
291 { 0x1c00001b, "nca_s_fault_remote_no_memory" },
292 { 0x1c00001c, "nca_invalid_pres_context_id" },
293 { 0x1c00001d, "nca_unsupported_authn_level" },
294 { 0x1c00001f, "nca_invalid_checksum" },
295 { 0x1c000020, "nca_invalid_crc" },
296 { 0x1c000021, "ncs_s_fault_user_defined" },
297 { 0x1c000022, "nca_s_fault_tx_open_failed" },
298 { 0x1c000023, "nca_s_fault_codeset_conv_error" },
299 { 0x1c000024, "nca_s_fault_object_not_found" },
300 { 0x1c000025, "nca_s_fault_no_client_stub" },
301 { 0x1c010002, "nca_op_rng_error" },
302 { 0x1c010003, "nca_unk_if"},
303 { 0x1c010006, "nca_wrong_boot_time" },
304 { 0x1c010009, "nca_s_you_crashed" },
305 { 0x1c01000b, "nca_proto_error" },
306 { 0x1c010013, "nca_out_args_too_big" },
307 { 0x1c010014, "nca_server_too_busy" },
308 { 0x1c010017, "nca_unsupported_type" },
309 /* MS Windows specific values
310 * see: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/system_error_codes__1700-3999_.asp
311 * and: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/seccrypto/security/common_hresult_values.asp
312 * and: http://www.megos.ch/support/doserrors.txt
314 * XXX - we might need a way to dynamically add entries here, as higher layer protocols use these values too,
315 * at least MS protocols (like DCOM) do it that way ... */
316 { 0x80004001, "E_NOTIMPL" },
317 { 0x80004003, "E_POINTER" },
318 { 0x80004004, "E_ABORT" },
319 { 0x8000FFFF, "E_UNEXPECTED" },
320 { 0x80010105, "RPC_E_SERVERFAULT" },
321 { 0x80010108, "RPC_E_DISCONNECTED" },
322 { 0x80010113, "RPC_E_INVALID_IPID" },
323 { 0x8001011F, "RPC_E_TIMEOUT" },
324 { 0x80020003, "DISP_E_MEMBERNOTFOUND" },
325 { 0x80020006, "DISP_E_UNKNOWNNAME" },
326 { 0x8002000E, "DISP_E_BADPARAMCOUNT" },
327 { 0x8004CB00, "CBA_E_MALFORMED" },
328 { 0x8004CB01, "CBA_E_UNKNOWNOBJECT" },
329 { 0x8004CB05, "CBA_E_INVALIDID" },
330 { 0x8004CB09, "CBA_E_INVALIDCOOKIE" },
331 { 0x8004CB0B, "CBA_E_QOSTYPEUNSUPPORTED" },
332 { 0x8004CB0C, "CBA_E_QOSVALUEUNSUPPORTED" },
333 { 0x8004CB0F, "CBA_E_NOTAPPLICABLE" },
334 { 0x8004CB12, "CBA_E_LIMITVIOLATION" },
335 { 0x8004CB13, "CBA_E_QOSTYPENOTAPPLICABLE" },
336 { 0x8004CB18, "CBA_E_OUTOFPARTNERACCOS" },
337 { 0x8004CB1C, "CBA_E_FLAGUNSUPPORTED" },
338 { 0x8004CB23, "CBA_E_FRAMECOUNTUNSUPPORTED" },
339 { 0x8004CB25, "CBA_E_MODECHANGE" },
340 { 0x8007000E, "E_OUTOFMEMORY" },
341 { 0x80070057, "E_INVALIDARG" },
342 { 0x800706d1, "RPC_S_PROCNUM_OUT_OF_RANGE" },
343 { 0x80070776, "OR_INVALID_OXID" },
351 #define RTS_FLAG_NONE 0x0000
352 #define RTS_FLAG_PING 0x0001
353 #define RTS_FLAG_OTHER_CMD 0x0002
354 #define RTS_FLAG_RECYCLE_CHANNEL 0x0004
355 #define RTS_FLAG_IN_CHANNEL 0x0008
356 #define RTS_FLAG_OUT_CHANNEL 0x0010
357 #define RTS_FLAG_EOF 0x0020
358 #define RTS_FLAG_ECHO 0x0040
364 #define RTS_CMD_RECEIVEWINDOWSIZE 0x0
365 #define RTS_CMD_FLOWCONTROLACK 0x1
366 #define RTS_CMD_CONNECTIONTIMEOUT 0x2
367 #define RTS_CMD_COOKIE 0x3
368 #define RTS_CMD_CHANNELLIFETIME 0x4
369 #define RTS_CMD_CLIENTKEEPALIVE 0x5
370 #define RTS_CMD_VERSION 0x6
371 #define RTS_CMD_EMPTY 0x7
372 #define RTS_CMD_PADDING 0x8
373 #define RTS_CMD_NEGATIVEANCE 0x9
374 #define RTS_CMD_ANCE 0xA
375 #define RTS_CMD_CLIENTADDRESS 0xB
376 #define RTS_CMD_ASSOCIATIONGROUPID 0xC
377 #define RTS_CMD_DESTINATION 0xD
378 #define RTS_CMD_PINGTRAFFICSENTNOTIFY 0xE
380 static const value_string rts_command_vals[] = {
381 { RTS_CMD_RECEIVEWINDOWSIZE, "ReceiveWindowSize" },
382 { RTS_CMD_FLOWCONTROLACK, "FlowControlAck" },
383 { RTS_CMD_CONNECTIONTIMEOUT, "ConnectionTimeOut" },
384 { RTS_CMD_COOKIE, "Cookie" },
385 { RTS_CMD_CHANNELLIFETIME, "ChannelLifetime" },
386 { RTS_CMD_CLIENTKEEPALIVE, "ClientKeepalive" },
387 { RTS_CMD_VERSION, "Version" },
388 { RTS_CMD_EMPTY, "Empty" },
389 { RTS_CMD_PADDING, "Padding" },
390 { RTS_CMD_NEGATIVEANCE, "NegativeANCE" },
391 { RTS_CMD_ANCE, "ANCE" },
392 { RTS_CMD_CLIENTADDRESS, "ClientAddress" },
393 { RTS_CMD_ASSOCIATIONGROUPID, "AssociationGroupId" },
394 { RTS_CMD_DESTINATION, "Destination" },
395 { RTS_CMD_PINGTRAFFICSENTNOTIFY, "PingTrafficSentNotify" },
400 * RTS client address type
405 static const value_string rts_addresstype_vals[] = {
406 { RTS_IPV4, "IPV4" },
407 { RTS_IPV6, "IPV6" },
412 * RTS Forward destination
415 static const value_string rts_forward_destination_vals[] = {
417 { 0x1, "FDInProxy" },
419 { 0x3, "FDOutProxy" },
423 /* we need to keep track of what transport were used, ie what handle we came
424 * in through so we know what kind of pinfo->dce_smb_fid was passed to us.
426 /* Value of -1 is reserved for "not DCE packet" in packet_info.dcetransporttype. */
427 #define DCE_TRANSPORT_UNKNOWN 0
428 #define DCE_CN_TRANSPORT_SMBPIPE 1
431 static int proto_dcerpc = -1;
434 static int hf_dcerpc_request_in = -1;
435 static int hf_dcerpc_time = -1;
436 static int hf_dcerpc_response_in = -1;
437 static int hf_dcerpc_ver = -1;
438 static int hf_dcerpc_ver_minor = -1;
439 static int hf_dcerpc_packet_type = -1;
440 static int hf_dcerpc_cn_flags = -1;
441 static int hf_dcerpc_cn_flags_first_frag = -1;
442 static int hf_dcerpc_cn_flags_last_frag = -1;
443 static int hf_dcerpc_cn_flags_cancel_pending = -1;
444 static int hf_dcerpc_cn_flags_reserved = -1;
445 static int hf_dcerpc_cn_flags_mpx = -1;
446 static int hf_dcerpc_cn_flags_dne = -1;
447 static int hf_dcerpc_cn_flags_maybe = -1;
448 static int hf_dcerpc_cn_flags_object = -1;
449 static int hf_dcerpc_drep = -1;
450 int hf_dcerpc_drep_byteorder = -1;
451 int hf_dcerpc_ndr_padding = -1;
452 static int hf_dcerpc_drep_character = -1;
453 static int hf_dcerpc_drep_fp = -1;
454 static int hf_dcerpc_cn_frag_len = -1;
455 static int hf_dcerpc_cn_auth_len = -1;
456 static int hf_dcerpc_cn_call_id = -1;
457 static int hf_dcerpc_cn_max_xmit = -1;
458 static int hf_dcerpc_cn_max_recv = -1;
459 static int hf_dcerpc_cn_assoc_group = -1;
460 static int hf_dcerpc_cn_num_ctx_items = -1;
461 static int hf_dcerpc_cn_ctx_item = -1;
462 static int hf_dcerpc_cn_ctx_id = -1;
463 static int hf_dcerpc_cn_num_trans_items = -1;
464 static int hf_dcerpc_cn_bind_abstract_syntax = -1;
465 static int hf_dcerpc_cn_bind_if_id = -1;
466 static int hf_dcerpc_cn_bind_if_ver = -1;
467 static int hf_dcerpc_cn_bind_if_ver_minor = -1;
468 static int hf_dcerpc_cn_bind_trans_syntax = -1;
469 static int hf_dcerpc_cn_bind_trans_id = -1;
470 static int hf_dcerpc_cn_bind_trans_ver = -1;
471 static int hf_dcerpc_cn_bind_trans_btfn = -1;
472 static int hf_dcerpc_cn_bind_trans_btfn_01 = -1;
473 static int hf_dcerpc_cn_bind_trans_btfn_02 = -1;
474 static int hf_dcerpc_cn_alloc_hint = -1;
475 static int hf_dcerpc_cn_sec_addr_len = -1;
476 static int hf_dcerpc_cn_sec_addr = -1;
477 static int hf_dcerpc_cn_num_results = -1;
478 static int hf_dcerpc_cn_ack_result = -1;
479 static int hf_dcerpc_cn_ack_reason = -1;
480 static int hf_dcerpc_cn_ack_trans_id = -1;
481 static int hf_dcerpc_cn_ack_trans_ver = -1;
482 static int hf_dcerpc_cn_reject_reason = -1;
483 static int hf_dcerpc_cn_num_protocols = -1;
484 static int hf_dcerpc_cn_protocol_ver_major = -1;
485 static int hf_dcerpc_cn_protocol_ver_minor = -1;
486 static int hf_dcerpc_cn_cancel_count = -1;
487 static int hf_dcerpc_cn_status = -1;
488 static int hf_dcerpc_cn_deseg_req = -1;
489 static int hf_dcerpc_cn_rts_flags = -1;
490 static int hf_dcerpc_cn_rts_flags_none = -1;
491 static int hf_dcerpc_cn_rts_flags_ping = -1;
492 static int hf_dcerpc_cn_rts_flags_other_cmd = -1;
493 static int hf_dcerpc_cn_rts_flags_recycle_channel = -1;
494 static int hf_dcerpc_cn_rts_flags_in_channel = -1;
495 static int hf_dcerpc_cn_rts_flags_out_channel = -1;
496 static int hf_dcerpc_cn_rts_flags_eof = -1;
497 static int hf_dcerpc_cn_rts_commands_nb = -1;
498 static int hf_dcerpc_cn_rts_command = -1;
499 static int hf_dcerpc_cn_rts_command_receivewindowsize = -1;
500 static int hf_dcerpc_cn_rts_command_fack_bytesreceived = -1;
501 static int hf_dcerpc_cn_rts_command_fack_availablewindow = -1;
502 static int hf_dcerpc_cn_rts_command_fack_channelcookie = -1;
503 static int hf_dcerpc_cn_rts_command_connectiontimeout = -1;
504 static int hf_dcerpc_cn_rts_command_cookie = -1;
505 static int hf_dcerpc_cn_rts_command_channellifetime = -1;
506 static int hf_dcerpc_cn_rts_command_clientkeepalive = -1;
507 static int hf_dcerpc_cn_rts_command_version = -1;
508 static int hf_dcerpc_cn_rts_command_conformancecount = -1;
509 static int hf_dcerpc_cn_rts_command_padding = -1;
510 static int hf_dcerpc_cn_rts_command_addrtype = -1;
511 static int hf_dcerpc_cn_rts_command_associationgroupid = -1;
512 static int hf_dcerpc_cn_rts_command_forwarddestination = -1;
513 static int hf_dcerpc_cn_rts_command_pingtrafficsentnotify = -1;
514 static int hf_dcerpc_auth_type = -1;
515 static int hf_dcerpc_auth_level = -1;
516 static int hf_dcerpc_auth_pad_len = -1;
517 static int hf_dcerpc_auth_rsrvd = -1;
518 static int hf_dcerpc_auth_ctx_id = -1;
519 static int hf_dcerpc_dg_flags1 = -1;
520 static int hf_dcerpc_dg_flags1_rsrvd_01 = -1;
521 static int hf_dcerpc_dg_flags1_last_frag = -1;
522 static int hf_dcerpc_dg_flags1_frag = -1;
523 static int hf_dcerpc_dg_flags1_nofack = -1;
524 static int hf_dcerpc_dg_flags1_maybe = -1;
525 static int hf_dcerpc_dg_flags1_idempotent = -1;
526 static int hf_dcerpc_dg_flags1_broadcast = -1;
527 static int hf_dcerpc_dg_flags1_rsrvd_80 = -1;
528 static int hf_dcerpc_dg_flags2 = -1;
529 static int hf_dcerpc_dg_flags2_rsrvd_01 = -1;
530 static int hf_dcerpc_dg_flags2_cancel_pending = -1;
531 static int hf_dcerpc_dg_flags2_rsrvd_04 = -1;
532 static int hf_dcerpc_dg_flags2_rsrvd_08 = -1;
533 static int hf_dcerpc_dg_flags2_rsrvd_10 = -1;
534 static int hf_dcerpc_dg_flags2_rsrvd_20 = -1;
535 static int hf_dcerpc_dg_flags2_rsrvd_40 = -1;
536 static int hf_dcerpc_dg_flags2_rsrvd_80 = -1;
537 static int hf_dcerpc_dg_serial_hi = -1;
538 static int hf_dcerpc_obj_id = -1;
539 static int hf_dcerpc_dg_if_id = -1;
540 static int hf_dcerpc_dg_act_id = -1;
541 static int hf_dcerpc_dg_serial_lo = -1;
542 static int hf_dcerpc_dg_ahint = -1;
543 static int hf_dcerpc_dg_ihint = -1;
544 static int hf_dcerpc_dg_frag_len = -1;
545 static int hf_dcerpc_dg_frag_num = -1;
546 static int hf_dcerpc_dg_auth_proto = -1;
547 static int hf_dcerpc_opnum = -1;
548 static int hf_dcerpc_dg_seqnum = -1;
549 static int hf_dcerpc_dg_server_boot = -1;
550 static int hf_dcerpc_dg_if_ver = -1;
551 static int hf_dcerpc_krb5_av_prot_level = -1;
552 static int hf_dcerpc_krb5_av_key_vers_num = -1;
553 static int hf_dcerpc_krb5_av_key_auth_verifier = -1;
554 static int hf_dcerpc_dg_cancel_vers = -1;
555 static int hf_dcerpc_dg_cancel_id = -1;
556 static int hf_dcerpc_dg_server_accepting_cancels = -1;
557 static int hf_dcerpc_dg_fack_vers = -1;
558 static int hf_dcerpc_dg_fack_window_size = -1;
559 static int hf_dcerpc_dg_fack_max_tsdu = -1;
560 static int hf_dcerpc_dg_fack_max_frag_size = -1;
561 static int hf_dcerpc_dg_fack_serial_num = -1;
562 static int hf_dcerpc_dg_fack_selack_len = -1;
563 static int hf_dcerpc_dg_fack_selack = -1;
564 static int hf_dcerpc_dg_status = -1;
565 static int hf_dcerpc_array_max_count = -1;
566 static int hf_dcerpc_array_offset = -1;
567 static int hf_dcerpc_array_actual_count = -1;
568 static int hf_dcerpc_op = -1;
569 static int hf_dcerpc_referent_id32 = -1;
570 static int hf_dcerpc_referent_id64 = -1;
571 static int hf_dcerpc_null_pointer = -1;
572 static int hf_dcerpc_fragments = -1;
573 static int hf_dcerpc_fragment = -1;
574 static int hf_dcerpc_fragment_overlap = -1;
575 static int hf_dcerpc_fragment_overlap_conflict = -1;
576 static int hf_dcerpc_fragment_multiple_tails = -1;
577 static int hf_dcerpc_fragment_too_long_fragment = -1;
578 static int hf_dcerpc_fragment_error = -1;
579 static int hf_dcerpc_fragment_count = -1;
580 static int hf_dcerpc_reassembled_in = -1;
581 static int hf_dcerpc_reassembled_length = -1;
582 static int hf_dcerpc_unknown_if_id = -1;
583 static int hf_dcerpc_sec_vt_signature = -1;
584 static int hf_dcerpc_sec_vt_command = -1;
585 static int hf_dcerpc_sec_vt_command_cmd = -1;
586 static int hf_dcerpc_sec_vt_command_end = -1;
587 static int hf_dcerpc_sec_vt_command_must = -1;
588 static int hf_dcerpc_sec_vt_command_length = -1;
589 static int hf_dcerpc_sec_vt_bitmask = -1;
590 static int hf_dcerpc_sec_vt_bitmask_sign = -1;
591 static int hf_dcerpc_sec_vt_pcontext_uuid = -1;
592 static int hf_dcerpc_sec_vt_pcontext_ver = -1;
594 static const int *sec_vt_command_fields[] = {
595 &hf_dcerpc_sec_vt_command_cmd,
596 &hf_dcerpc_sec_vt_command_end,
597 &hf_dcerpc_sec_vt_command_must,
600 static int hf_dcerpc_reserved = -1;
601 static int hf_dcerpc_unknown = -1;
602 static int hf_dcerpc_missalign = -1;
604 /* Generated from convert_proto_tree_add_text.pl */
605 static int hf_dcerpc_duplicate_ptr = -1;
606 static int hf_dcerpc_encrypted_stub_data = -1;
607 static int hf_dcerpc_decrypted_stub_data = -1;
608 static int hf_dcerpc_payload_stub_data = -1;
609 static int hf_dcerpc_stub_data_with_sec_vt = -1;
610 static int hf_dcerpc_stub_data = -1;
611 static int hf_dcerpc_auth_padding = -1;
612 static int hf_dcerpc_auth_verifier = -1;
613 static int hf_dcerpc_auth_credentials = -1;
614 static int hf_dcerpc_fault_stub_data = -1;
615 static int hf_dcerpc_fragment_data = -1;
616 static int hf_dcerpc_cmd_client_ipv4 = -1;
617 static int hf_dcerpc_cmd_client_ipv6 = -1;
618 static int hf_dcerpc_authentication_verifier = -1;
620 static const int *dcerpc_cn_bind_trans_btfn_fields[] = {
621 &hf_dcerpc_cn_bind_trans_btfn_01,
622 &hf_dcerpc_cn_bind_trans_btfn_02,
626 static const int *sec_vt_bitmask_fields[] = {
627 &hf_dcerpc_sec_vt_bitmask_sign,
631 static const value_string sec_vt_command_cmd_vals[] = {
638 static gint ett_dcerpc = -1;
639 static gint ett_dcerpc_cn_flags = -1;
640 static gint ett_dcerpc_cn_ctx = -1;
641 static gint ett_dcerpc_cn_iface = -1;
642 static gint ett_dcerpc_cn_trans_syntax = -1;
643 static gint ett_dcerpc_cn_trans_btfn = -1;
644 static gint ett_dcerpc_cn_bind_trans_btfn = -1;
645 static gint ett_dcerpc_cn_rts_flags = -1;
646 static gint ett_dcerpc_cn_rts_command = -1;
647 static gint ett_dcerpc_cn_rts_pdu = -1;
648 static gint ett_dcerpc_drep = -1;
649 static gint ett_dcerpc_dg_flags1 = -1;
650 static gint ett_dcerpc_dg_flags2 = -1;
651 static gint ett_dcerpc_pointer_data = -1;
652 static gint ett_dcerpc_string = -1;
653 static gint ett_dcerpc_fragments = -1;
654 static gint ett_dcerpc_fragment = -1;
655 static gint ett_dcerpc_krb5_auth_verf = -1;
656 static gint ett_dcerpc_verification_trailer = -1;
657 static gint ett_dcerpc_sec_vt_command = -1;
658 static gint ett_dcerpc_sec_vt_bitmask = -1;
659 static gint ett_dcerpc_sec_vt_pcontext = -1;
660 static gint ett_dcerpc_sec_vt_header = -1;
661 static gint ett_dcerpc_complete_stub_data = -1;
663 static expert_field ei_dcerpc_fragment_multiple = EI_INIT;
664 static expert_field ei_dcerpc_cn_status = EI_INIT;
665 static expert_field ei_dcerpc_fragment_reassembled = EI_INIT;
666 static expert_field ei_dcerpc_fragment = EI_INIT;
667 static expert_field ei_dcerpc_no_request_found = EI_INIT;
668 static expert_field ei_dcerpc_context_change = EI_INIT;
669 static expert_field ei_dcerpc_cn_ctx_id_no_bind = EI_INIT;
670 static expert_field ei_dcerpc_bind_not_acknowledged = EI_INIT;
671 static expert_field ei_dcerpc_verifier_unavailable = EI_INIT;
672 static expert_field ei_dcerpc_invalid_pdu_authentication_attempt = EI_INIT;
673 /* Generated from convert_proto_tree_add_text.pl */
674 static expert_field ei_dcerpc_long_frame = EI_INIT;
675 static expert_field ei_dcerpc_cn_rts_command = EI_INIT;
677 static const guint8 TRAILER_SIGNATURE[] = {0x8a, 0xe3, 0x13, 0x71, 0x02, 0xf4, 0x36, 0x71};
678 static tvbuff_t *tvb_trailer_signature = NULL;
680 static GSList *decode_dcerpc_bindings = NULL;
682 * To keep track of ctx_id mappings.
684 * Every time we see a bind call we update this table.
685 * Note that we always specify a SMB FID. For non-SMB transports this
688 static GHashTable *dcerpc_binds = NULL;
690 typedef struct _dcerpc_bind_key {
691 conversation_t *conv;
693 guint64 transport_salt;
696 typedef struct _dcerpc_bind_value {
702 /* Extra data for DCERPC handling and tracking of context ids */
703 typedef struct _dcerpc_decode_as_data {
704 guint16 dcectxid; /**< Context ID (DCERPC-specific) */
705 int dcetransporttype; /**< Transport type
706 * Value -1 means "not a DCERPC packet"
708 guint64 dcetransportsalt; /**< fid: if transporttype==DCE_CN_TRANSPORT_SMBPIPE */
709 } dcerpc_decode_as_data;
711 static dcerpc_decode_as_data*
712 dcerpc_get_decode_data(packet_info* pinfo)
714 dcerpc_decode_as_data* data = (dcerpc_decode_as_data*)p_get_proto_data(pinfo->pool, pinfo, proto_dcerpc, 0);
717 data = wmem_new0(pinfo->pool, dcerpc_decode_as_data);
718 data->dcetransporttype = -1;
719 p_add_proto_data(pinfo->pool, pinfo, proto_dcerpc, 0, data);
726 * Registers a conversation/UUID binding association, so that
727 * we can invoke the proper sub-dissector for a given DCERPC
730 * @param binding all values needed to create and bind a new conversation
732 * @return Pointer to newly-added UUID/conversation binding.
734 static struct _dcerpc_bind_value *
735 dcerpc_add_conv_to_bind_table(decode_dcerpc_bind_values_t *binding)
737 dcerpc_bind_value *bind_value;
738 dcerpc_bind_key *key;
739 conversation_t *conv;
741 conv = find_conversation(
751 conv = conversation_new(
761 bind_value = (dcerpc_bind_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_value));
762 bind_value->uuid = binding->uuid;
763 bind_value->ver = binding->ver;
764 /* For now, assume all DCE/RPC we pick from "decode as" is using
765 standard ndr and not ndr64.
766 We should make this selectable from the dialog in the future
768 bind_value->transport = uuid_data_repr_proto;
770 key = (dcerpc_bind_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_key));
772 key->ctx_id = binding->ctx_id;
773 key->transport_salt = binding->transport_salt;
775 /* add this entry to the bind table */
776 g_hash_table_insert(dcerpc_binds, key, bind_value);
782 /* inject one of our bindings into the dcerpc binding table */
784 decode_dcerpc_inject_binding(gpointer data, gpointer user_data _U_)
786 dcerpc_add_conv_to_bind_table((decode_dcerpc_bind_values_t *) data);
789 /* inject all of our bindings into the dcerpc binding table */
791 decode_dcerpc_inject_bindings(void) {
792 g_slist_foreach(decode_dcerpc_bindings, decode_dcerpc_inject_binding, NULL /* user_data */);
797 decode_dcerpc_binding_free(void *binding_in)
799 decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t *)binding_in;
801 free_address(&binding->addr_a);
802 free_address(&binding->addr_b);
804 g_string_free(binding->ifname, TRUE);
809 dcerpc_decode_as_free(gpointer value)
811 decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t *)value;
813 decode_dcerpc_binding_free(binding);
816 /* removes all bindings */
818 decode_dcerpc_reset_all(void)
820 decode_dcerpc_bind_values_t *binding;
822 while (decode_dcerpc_bindings) {
823 binding = (decode_dcerpc_bind_values_t *)decode_dcerpc_bindings->data;
825 decode_dcerpc_binding_free(binding);
826 decode_dcerpc_bindings = g_slist_remove(
827 decode_dcerpc_bindings,
828 decode_dcerpc_bindings->data);
834 decode_dcerpc_add_show_list(decode_add_show_list_func func, gpointer user_data)
836 g_slist_foreach(decode_dcerpc_bindings, func, user_data);
840 dcerpc_prompt(packet_info *pinfo, gchar* result)
842 GString *str = g_string_new("Replace binding between:\r\n"),
843 *address_str = g_string_new("");
844 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
846 switch (pinfo->ptype) {
848 g_string_append(address_str, "Address: ToBeDone TCP port");
851 g_string_append(address_str, "Address: ToBeDone UDP port");
854 g_string_append(address_str, "Address: ToBeDone Unknown port type");
857 g_string_append_printf(str, "%s: %u\r\n", address_str->str, pinfo->srcport);
858 g_string_append(str, "&\r\n");
859 g_string_append_printf(str, "%s: %u\r\n", address_str->str, pinfo->destport);
860 g_string_append_printf(str, "&\r\nContext ID: %u\r\n", decode_data->dcectxid);
861 g_string_append_printf(str, "&\r\nSMB FID: %"G_GINT64_MODIFIER"u\r\n",
862 dcerpc_get_transport_salt(pinfo));
863 g_string_append(str, "with:\r\n");
865 g_strlcpy(result, str->str, MAX_DECODE_AS_PROMPT_LEN);
866 g_string_free(str, TRUE);
867 g_string_free(address_str, TRUE);
871 dcerpc_value(packet_info *pinfo)
873 decode_dcerpc_bind_values_t *binding;
874 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
877 binding = g_new(decode_dcerpc_bind_values_t,1);
878 copy_address(&binding->addr_a, &pinfo->src);
879 copy_address(&binding->addr_b, &pinfo->dst);
880 binding->ptype = pinfo->ptype;
881 binding->port_a = pinfo->srcport;
882 binding->port_b = pinfo->destport;
883 binding->ctx_id = decode_data->dcectxid;
884 binding->transport_salt = dcerpc_get_transport_salt(pinfo);
885 binding->ifname = NULL;
886 /*binding->uuid = NULL;*/
892 struct dcerpc_decode_as_populate
894 decode_as_add_to_list_func add_to_list;
899 decode_dcerpc_add_to_list(gpointer key, gpointer value, gpointer user_data)
901 struct dcerpc_decode_as_populate* populate = (struct dcerpc_decode_as_populate*)user_data;
903 /*guid_key *k = key;*/
904 dcerpc_uuid_value *v = (dcerpc_uuid_value *)value;
906 if (strcmp(v->name, "(none)"))
907 populate->add_to_list("DCE-RPC", v->name, key, populate->ui_element);
911 dcerpc_populate_list(const gchar *table_name _U_, decode_as_add_to_list_func add_to_list, gpointer ui_element)
913 struct dcerpc_decode_as_populate populate;
915 populate.add_to_list = add_to_list;
916 populate.ui_element = ui_element;
918 g_hash_table_foreach(dcerpc_uuids, decode_dcerpc_add_to_list, &populate);
921 /* compare two bindings (except the interface related things, e.g. uuid) */
923 decode_dcerpc_binding_cmp(gconstpointer a, gconstpointer b)
925 const decode_dcerpc_bind_values_t *binding_a = (const decode_dcerpc_bind_values_t *)a;
926 const decode_dcerpc_bind_values_t *binding_b = (const decode_dcerpc_bind_values_t *)b;
929 /* don't compare uuid and ver! */
931 addresses_equal(&binding_a->addr_a, &binding_b->addr_a) &&
932 addresses_equal(&binding_a->addr_b, &binding_b->addr_b) &&
933 binding_a->ptype == binding_b->ptype &&
934 binding_a->port_a == binding_b->port_a &&
935 binding_a->port_b == binding_b->port_b &&
936 binding_a->ctx_id == binding_b->ctx_id &&
937 binding_a->transport_salt == binding_b->transport_salt)
947 /* remove a binding (looking the same way as the given one) */
949 decode_dcerpc_binding_reset(const char *name _U_, gconstpointer pattern)
951 const decode_dcerpc_bind_values_t *binding = (const decode_dcerpc_bind_values_t *)pattern;
953 decode_dcerpc_bind_values_t *old_binding;
955 /* find the old binding (if it exists) */
956 le = g_slist_find_custom(decode_dcerpc_bindings,
958 decode_dcerpc_binding_cmp);
962 old_binding = (decode_dcerpc_bind_values_t *)le->data;
964 decode_dcerpc_bindings = g_slist_remove(decode_dcerpc_bindings, le->data);
966 free_address(&old_binding->addr_a);
967 free_address(&old_binding->addr_b);
968 g_string_free(old_binding->ifname, TRUE);
974 dcerpc_decode_as_change(const char *name, gconstpointer pattern, gpointer handle, gchar* list_name)
976 decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t*)pattern;
977 decode_dcerpc_bind_values_t *stored_binding;
978 guid_key *key = *((guid_key**)handle);
981 binding->ifname = g_string_new(list_name);
982 binding->uuid = key->guid;
983 binding->ver = key->ver;
985 /* remove a probably existing old binding */
986 decode_dcerpc_binding_reset(name, binding);
988 /* clone the new binding and append it to the list */
989 stored_binding = g_new(decode_dcerpc_bind_values_t,1);
990 *stored_binding = *binding;
991 copy_address(&stored_binding->addr_a, &binding->addr_a);
992 copy_address(&stored_binding->addr_b, &binding->addr_b);
993 stored_binding->ifname = g_string_new(binding->ifname->str);
995 decode_dcerpc_bindings = g_slist_append (decode_dcerpc_bindings, stored_binding);
1000 static const fragment_items dcerpc_frag_items = {
1001 &ett_dcerpc_fragments,
1002 &ett_dcerpc_fragment,
1004 &hf_dcerpc_fragments,
1005 &hf_dcerpc_fragment,
1006 &hf_dcerpc_fragment_overlap,
1007 &hf_dcerpc_fragment_overlap_conflict,
1008 &hf_dcerpc_fragment_multiple_tails,
1009 &hf_dcerpc_fragment_too_long_fragment,
1010 &hf_dcerpc_fragment_error,
1011 &hf_dcerpc_fragment_count,
1013 &hf_dcerpc_reassembled_length,
1014 /* Reassembled data field */
1019 /* list of hooks to be called when init_protocols is done */
1020 GHookList dcerpc_hooks_init_protos;
1022 /* try to desegment big DCE/RPC packets over TCP? */
1023 static gboolean dcerpc_cn_desegment = TRUE;
1025 /* reassemble DCE/RPC fragments */
1026 /* reassembly of cl dcerpc fragments will not work for the case where ONE frame
1027 might contain multiple dcerpc fragments for different PDUs.
1028 this case would be so unusual/weird so if you got captures like that:
1031 reassembly of co dcerpc fragments will not work for the case where TCP/SMB frames
1032 are coming in out of sequence, but that will hurt in a lot of other places as well.
1034 static gboolean dcerpc_reassemble = TRUE;
1035 static reassembly_table dcerpc_co_reassembly_table;
1036 static reassembly_table dcerpc_cl_reassembly_table;
1038 typedef struct _dcerpc_fragment_key {
1043 } dcerpc_fragment_key;
1046 dcerpc_fragment_hash(gconstpointer k)
1048 const dcerpc_fragment_key* key = (const dcerpc_fragment_key*) k;
1053 hash_val += key->id;
1054 hash_val += key->act_id.data1;
1055 hash_val += key->act_id.data2 << 16;
1056 hash_val += key->act_id.data3;
1062 dcerpc_fragment_equal(gconstpointer k1, gconstpointer k2)
1064 const dcerpc_fragment_key* key1 = (const dcerpc_fragment_key*) k1;
1065 const dcerpc_fragment_key* key2 = (const dcerpc_fragment_key*) k2;
1067 /*key.id is the first item to compare since item is most
1068 likely to differ between sessions, thus shortcircuiting
1069 the comparison of addresses.
1071 return (((key1->id == key2->id)
1072 && (addresses_equal(&key1->src, &key2->src))
1073 && (addresses_equal(&key1->dst, &key2->dst))
1074 && (memcmp (&key1->act_id, &key2->act_id, sizeof (e_guid_t)) == 0))
1078 /* allocate a persistent dcerpc fragment key to insert in the hash */
1080 dcerpc_fragment_temporary_key(const packet_info *pinfo, const guint32 id,
1083 dcerpc_fragment_key *key = g_slice_new(dcerpc_fragment_key);
1084 const e_dce_dg_common_hdr_t *hdr = (const e_dce_dg_common_hdr_t *)data;
1086 copy_address_shallow(&key->src, &pinfo->src);
1087 copy_address_shallow(&key->dst, &pinfo->dst);
1089 key->act_id = hdr->act_id;
1094 /* allocate a persistent dcerpc fragment key to insert in the hash */
1096 dcerpc_fragment_persistent_key(const packet_info *pinfo, const guint32 id,
1099 dcerpc_fragment_key *key = g_slice_new(dcerpc_fragment_key);
1100 const e_dce_dg_common_hdr_t *hdr = (const e_dce_dg_common_hdr_t *)data;
1102 copy_address(&key->src, &pinfo->src);
1103 copy_address(&key->dst, &pinfo->dst);
1105 key->act_id = hdr->act_id;
1111 dcerpc_fragment_free_temporary_key(gpointer ptr)
1113 dcerpc_fragment_key *key = (dcerpc_fragment_key *)ptr;
1116 g_slice_free(dcerpc_fragment_key, key);
1120 dcerpc_fragment_free_persistent_key(gpointer ptr)
1122 dcerpc_fragment_key *key = (dcerpc_fragment_key *)ptr;
1126 * Free up the copies of the addresses from the old key.
1128 free_address(&key->src);
1129 free_address(&key->dst);
1131 g_slice_free(dcerpc_fragment_key, key);
1135 static const reassembly_table_functions dcerpc_cl_reassembly_table_functions = {
1136 dcerpc_fragment_hash,
1137 dcerpc_fragment_equal,
1138 dcerpc_fragment_temporary_key,
1139 dcerpc_fragment_persistent_key,
1140 dcerpc_fragment_free_temporary_key,
1141 dcerpc_fragment_free_persistent_key
1145 dcerpc_reassemble_init(void)
1148 * XXX - addresses_ports_reassembly_table_functions?
1149 * Or can a single connection-oriented DCE RPC session persist
1150 * over multiple transport layer connections?
1152 reassembly_table_init(&dcerpc_co_reassembly_table,
1153 &addresses_reassembly_table_functions);
1154 reassembly_table_init(&dcerpc_cl_reassembly_table,
1155 &dcerpc_cl_reassembly_table_functions);
1159 * Authentication subdissectors. Used to dissect authentication blobs in
1160 * DCERPC binds, requests and responses.
1163 typedef struct _dcerpc_auth_subdissector {
1166 dcerpc_auth_subdissector_fns auth_fns;
1167 } dcerpc_auth_subdissector;
1169 static GSList *dcerpc_auth_subdissector_list;
1171 static dcerpc_auth_subdissector_fns *get_auth_subdissector_fns(
1172 guint8 auth_level, guint8 auth_type)
1177 for (i = 0; (data = g_slist_nth_data(dcerpc_auth_subdissector_list, i)); i++) {
1178 dcerpc_auth_subdissector *asd = (dcerpc_auth_subdissector *)data;
1180 if ((asd->auth_level == auth_level) &&
1181 (asd->auth_type == auth_type))
1182 return &asd->auth_fns;
1188 void register_dcerpc_auth_subdissector(guint8 auth_level, guint8 auth_type,
1189 dcerpc_auth_subdissector_fns *fns)
1191 dcerpc_auth_subdissector *d;
1193 if (get_auth_subdissector_fns(auth_level, auth_type))
1196 d = (dcerpc_auth_subdissector *)g_malloc(sizeof(dcerpc_auth_subdissector));
1198 d->auth_level = auth_level;
1199 d->auth_type = auth_type;
1200 memcpy(&d->auth_fns, fns, sizeof(dcerpc_auth_subdissector_fns));
1202 dcerpc_auth_subdissector_list = g_slist_append(dcerpc_auth_subdissector_list, d);
1205 /* Hand off verifier data to a registered dissector */
1207 static void dissect_auth_verf(tvbuff_t *auth_tvb, packet_info *pinfo,
1209 dcerpc_auth_subdissector_fns *auth_fns,
1210 e_dce_cn_common_hdr_t *hdr,
1211 dcerpc_auth_info *auth_info)
1213 dcerpc_dissect_fnct_t *fn = NULL;
1214 /* XXX - "stub" a fake DCERPC INFO STRUCTURE
1215 If a dcerpc_info is really needed, update
1216 the call stacks to include it
1218 FAKE_DCERPC_INFO_STRUCTURE
1220 switch (hdr->ptype) {
1223 fn = auth_fns->bind_fn;
1227 fn = auth_fns->bind_ack_fn;
1230 fn = auth_fns->auth3_fn;
1233 fn = auth_fns->req_verf_fn;
1236 fn = auth_fns->resp_verf_fn;
1240 /* Don't know how to handle authentication data in this
1242 proto_tree_add_expert_format(tree, pinfo, &ei_dcerpc_invalid_pdu_authentication_attempt,
1244 "Don't know how to dissect authentication data for %s pdu type",
1245 val_to_str(hdr->ptype, pckt_vals, "Unknown (%u)"));
1251 fn(auth_tvb, 0, pinfo, tree, &di, hdr->drep);
1253 proto_tree_add_expert_format(tree, pinfo, &ei_dcerpc_verifier_unavailable,
1254 auth_tvb, 0, hdr->auth_len,
1255 "%s Verifier unavailable",
1256 val_to_str(auth_info->auth_type,
1257 authn_protocol_vals,
1263 proto_tree_add_dcerpc_drep(proto_tree *tree, tvbuff_t *tvb, int offset, guint8 drep[], int drep_len)
1265 const guint8 byteorder = drep[0] >> 4;
1266 const guint8 character = drep[0] & 0x0f;
1267 const guint8 fp = drep[1];
1268 proto_item *ti = proto_tree_add_bytes(tree, hf_dcerpc_drep, tvb, offset, drep_len, drep);
1269 proto_tree *tr = proto_item_add_subtree(ti, ett_dcerpc_drep);
1271 proto_tree_add_uint(tr, hf_dcerpc_drep_byteorder, tvb, offset, 1, byteorder);
1272 proto_tree_add_uint(tr, hf_dcerpc_drep_character, tvb, offset, 1, character);
1273 proto_tree_add_uint(tr, hf_dcerpc_drep_fp, tvb, offset+1, 1, fp);
1275 proto_item_append_text(ti, " (Order: %s, Char: %s, Float: %s)",
1276 val_to_str(byteorder, drep_byteorder_vals, "Unknown (%u)"),
1277 val_to_str(character, drep_character_vals, "Unknown (%u)"),
1278 val_to_str(fp, drep_fp_vals, "Unknown (%u)"));
1282 /* Hand off payload data to a registered dissector */
1284 static tvbuff_t *decode_encrypted_data(tvbuff_t *data_tvb,
1287 dcerpc_auth_subdissector_fns *auth_fns,
1288 gboolean is_request,
1289 dcerpc_auth_info *auth_info)
1291 dcerpc_decode_data_fnct_t *fn;
1294 fn = auth_fns->req_data_fn;
1296 fn = auth_fns->resp_data_fn;
1299 return fn(data_tvb, auth_tvb, 0, pinfo, auth_info);
1304 typedef struct _dcerpc_dissector_data
1306 dcerpc_uuid_value *sub_proto;
1309 dcerpc_auth_info *auth_info;
1311 proto_tree *dcerpc_tree;
1312 } dcerpc_dissector_data_t;
1318 dissector_table_t uuid_dissector_table;
1320 /* the registered subdissectors */
1321 GHashTable *dcerpc_uuids = NULL;
1324 dcerpc_uuid_equal(gconstpointer k1, gconstpointer k2)
1326 const guid_key *key1 = (const guid_key *)k1;
1327 const guid_key *key2 = (const guid_key *)k2;
1328 return ((memcmp(&key1->guid, &key2->guid, sizeof (e_guid_t)) == 0)
1329 && (key1->ver == key2->ver));
1333 dcerpc_uuid_hash(gconstpointer k)
1335 const guid_key *key = (const guid_key *)k;
1336 /* This isn't perfect, but the Data1 part of these is almost always
1338 return key->guid.data1;
1343 dissect_verification_trailer(packet_info *pinfo, tvbuff_t *tvb, int stub_offset,
1344 proto_tree *parent_tree, int *signature_offset);
1347 show_stub_data(packet_info *pinfo, tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
1348 dcerpc_auth_info *auth_info, gboolean is_encrypted)
1350 int length, plain_length, auth_pad_len;
1351 guint auth_pad_offset;
1354 * We don't show stub data unless we have some in the tvbuff;
1355 * however, in the protocol tree, we show, as the number of
1356 * bytes, the reported number of bytes, not the number of bytes
1357 * that happen to be in the tvbuff.
1359 if (tvb_reported_length_remaining(tvb, offset) > 0) {
1360 auth_pad_len = auth_info?auth_info->auth_pad_len:0;
1361 length = tvb_reported_length_remaining(tvb, offset);
1363 /* if auth_pad_len is larger than length then we ignore auth_pad_len totally */
1364 plain_length = length - auth_pad_len;
1365 if (plain_length < 1) {
1366 plain_length = length;
1369 auth_pad_offset = offset + plain_length;
1371 if ((auth_info != NULL) &&
1372 (auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)) {
1374 proto_tree_add_item(dcerpc_tree, hf_dcerpc_encrypted_stub_data, tvb, offset, length, ENC_NA);
1375 /* is the padding is still inside the encrypted blob, don't display it explicit */
1378 proto_tree_add_item(dcerpc_tree, hf_dcerpc_decrypted_stub_data, tvb, offset, plain_length, ENC_NA);
1379 dissect_verification_trailer(pinfo, tvb, offset, dcerpc_tree, NULL);
1382 proto_tree_add_item(dcerpc_tree, hf_dcerpc_stub_data, tvb, offset, plain_length, ENC_NA);
1383 dissect_verification_trailer(pinfo, tvb, offset, dcerpc_tree, NULL);
1385 /* If there is auth padding at the end of the stub, display it */
1386 if (auth_pad_len != 0) {
1387 proto_tree_add_item(dcerpc_tree, hf_dcerpc_auth_padding, tvb, auth_pad_offset, auth_pad_len, ENC_NA);
1393 dissect_dcerpc_guid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1395 dcerpc_dissector_data_t* dissector_data = (dcerpc_dissector_data_t*)data;
1396 const gchar *name = NULL;
1397 dcerpc_sub_dissector *proc;
1398 int (*volatile sub_dissect)(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) = NULL;
1399 proto_item *pi, *sub_item;
1400 proto_tree *sub_tree;
1401 volatile guint length;
1402 guint reported_length;
1403 volatile gint offset = 0;
1404 tvbuff_t *volatile stub_tvb;
1405 tvbuff_t *volatile payload_tvb = NULL;
1406 volatile guint auth_pad_len;
1407 volatile int auth_pad_offset;
1408 const char *volatile saved_proto;
1410 for (proc = dissector_data->sub_proto->procs; proc->name; proc++) {
1411 if (proc->num == dissector_data->info->call_data->opnum) {
1417 col_set_str(pinfo->cinfo, COL_PROTOCOL, dissector_data->sub_proto->name);
1420 col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown operation %u %s",
1421 dissector_data->info->call_data->opnum,
1422 (dissector_data->info->ptype == PDU_REQ) ? "request" : "response");
1424 col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
1425 name, (dissector_data->info->ptype == PDU_REQ) ? "request" : "response");
1427 sub_dissect = (dissector_data->info->ptype == PDU_REQ) ?
1428 proc->dissect_rqst : proc->dissect_resp;
1430 sub_item = proto_tree_add_item(tree, dissector_data->sub_proto->proto_id,
1431 tvb,//(decrypted_tvb != NULL)?decrypted_tvb:tvb,
1433 sub_tree = proto_item_add_subtree(sub_item, dissector_data->sub_proto->ett);
1435 proto_item_append_text(sub_item, ", unknown operation %u",
1436 dissector_data->info->call_data->opnum);
1438 proto_item_append_text(sub_item, ", %s", name);
1442 * Put the operation number into the tree along with
1443 * the operation's name.
1445 if (dissector_data->sub_proto->opnum_hf != -1)
1446 proto_tree_add_uint_format(sub_tree, dissector_data->sub_proto->opnum_hf,
1447 tvb, 0, 0, dissector_data->info->call_data->opnum,
1448 "Operation: %s (%u)",
1449 name ? name : "Unknown operation",
1450 dissector_data->info->call_data->opnum);
1452 proto_tree_add_uint_format_value(sub_tree, hf_dcerpc_op, tvb,
1453 0, 0, dissector_data->info->call_data->opnum,
1455 name ? name : "Unknown operation",
1456 dissector_data->info->call_data->opnum);
1458 if ((dissector_data->info->ptype == PDU_REQ) && (dissector_data->info->call_data->rep_frame != 0)) {
1459 pi = proto_tree_add_uint(sub_tree, hf_dcerpc_response_in,
1460 tvb, 0, 0, dissector_data->info->call_data->rep_frame);
1461 PROTO_ITEM_SET_GENERATED(pi);
1463 if ((dissector_data->info->ptype == PDU_RESP) && (dissector_data->info->call_data->req_frame != 0)) {
1464 pi = proto_tree_add_uint(sub_tree, hf_dcerpc_request_in,
1465 tvb, 0, 0, dissector_data->info->call_data->req_frame);
1466 PROTO_ITEM_SET_GENERATED(pi);
1470 if (!dissector_data->decrypted || (sub_dissect == NULL))
1472 show_stub_data(pinfo, tvb, 0, sub_tree, dissector_data->auth_info, !dissector_data->decrypted);
1473 return tvb_captured_length(tvb);
1476 /* Either there was no encryption or we successfully decrypted
1477 the encrypted payload. */
1479 /* We have a subdissector - call it. */
1480 saved_proto = pinfo->current_proto;
1481 pinfo->current_proto = dissector_data->sub_proto->name;
1483 init_ndr_pointer_list(dissector_data->info);
1485 length = tvb_captured_length(tvb);
1486 reported_length = tvb_reported_length(tvb);
1489 * Remove the authentication padding from the stub data.
1491 if ((dissector_data->auth_info != NULL) && (dissector_data->auth_info->auth_pad_len != 0)) {
1492 if (reported_length >= dissector_data->auth_info->auth_pad_len) {
1494 * OK, the padding length isn't so big that it
1495 * exceeds the stub length. Trim the reported
1496 * length of the tvbuff.
1498 reported_length -= dissector_data->auth_info->auth_pad_len;
1501 * If that exceeds the actual amount of data in
1502 * the tvbuff (which means we have at least one
1503 * byte of authentication padding in the tvbuff),
1504 * trim the actual amount.
1506 if (length > reported_length)
1507 length = reported_length;
1509 stub_tvb = tvb_new_subset(tvb, 0, length, reported_length);
1510 auth_pad_len = dissector_data->auth_info->auth_pad_len;
1511 auth_pad_offset = reported_length;
1514 * The padding length exceeds the stub length.
1515 * Don't bother dissecting the stub, trim the padding
1516 * length to what's in the stub data, and show the
1517 * entire stub as authentication padding.
1520 auth_pad_len = reported_length;
1521 auth_pad_offset = 0;
1526 * No authentication padding.
1530 auth_pad_offset = 0;
1534 proto_item_set_len(sub_item, length);
1537 if (stub_tvb != NULL) {
1539 * Catch all exceptions other than BoundsError, so that even
1540 * if the stub data is bad, we still show the authentication
1543 * If we get BoundsError, it means the frame was cut short
1544 * by a snapshot length, so there's nothing more to
1545 * dissect; just re-throw that exception.
1548 proto_tree *stub_tree = NULL;
1550 int trailer_start_offset = -1;
1551 int trailer_end_offset = -1;
1553 stub_tree = proto_tree_add_subtree_format(dissector_data->dcerpc_tree,
1554 stub_tvb, 0, length,
1555 ett_dcerpc_complete_stub_data, NULL,
1556 "Complete stub data (%d byte%s)", length,
1557 plurality(length, "", "s"));
1558 trailer_end_offset = dissect_verification_trailer(pinfo,
1561 &trailer_start_offset);
1563 if (trailer_end_offset != -1) {
1564 remaining = tvb_captured_length_remaining(stub_tvb,
1565 trailer_start_offset);
1566 length -= remaining;
1569 proto_item_set_len(sub_item, length);
1572 proto_item *payload_item;
1574 payload_item = proto_tree_add_item(stub_tree,
1575 hf_dcerpc_payload_stub_data,
1576 stub_tvb, 0, length, ENC_NA);
1577 proto_item_append_text(payload_item, " (%d byte%s)",
1578 length, plurality(length, "", "s"));
1581 payload_tvb = tvb_new_subset(stub_tvb, 0, length, length);
1582 offset = sub_dissect(payload_tvb, 0, pinfo, sub_tree,
1583 dissector_data->info, dissector_data->drep);
1585 /* If we have a subdissector and it didn't dissect all
1586 data in the tvb, make a note of it. */
1587 remaining = tvb_reported_length_remaining(stub_tvb, offset);
1589 if (trailer_end_offset != -1) {
1590 if (offset > trailer_start_offset) {
1591 remaining = offset - trailer_start_offset;
1592 proto_tree_add_item(sub_tree, hf_dcerpc_stub_data_with_sec_vt,
1593 stub_tvb, trailer_start_offset, remaining, ENC_NA);
1594 col_append_fstr(pinfo->cinfo, COL_INFO,
1595 "[Payload with Verification Trailer (%d byte%s)]",
1597 plurality(remaining, "", "s"));
1600 remaining = trailer_start_offset - offset;
1604 if (remaining > 0) {
1605 proto_tree_add_expert(sub_tree, pinfo, &ei_dcerpc_long_frame, stub_tvb, offset, remaining);
1606 col_append_fstr(pinfo->cinfo, COL_INFO,
1607 "[Long frame (%d byte%s)]",
1609 plurality(remaining, "", "s"));
1611 } CATCH_NONFATAL_ERRORS {
1613 * Somebody threw an exception that means that there
1614 * was a problem dissecting the payload; that means
1615 * that a dissector was found, so we don't need to
1616 * dissect the payload as data or update the protocol
1619 * Just show the exception and then drive on to show
1620 * the authentication padding.
1622 show_exception(stub_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
1626 /* If there is auth padding at the end of the stub, display it */
1627 if (auth_pad_len != 0) {
1628 proto_tree_add_item(sub_tree, hf_dcerpc_auth_padding, tvb, auth_pad_offset, auth_pad_len, ENC_NA);
1631 pinfo->current_proto = saved_proto;
1633 return tvb_captured_length(tvb);
1637 dcerpc_init_uuid(int proto, int ett, e_guid_t *uuid, guint16 ver,
1638 dcerpc_sub_dissector *procs, int opnum_hf)
1640 guid_key *key = (guid_key *)g_malloc(sizeof (*key));
1641 dcerpc_uuid_value *value = (dcerpc_uuid_value *)g_malloc(sizeof (*value));
1642 header_field_info *hf_info;
1643 module_t *samr_module;
1644 const char *filter_name = proto_get_protocol_filter_name(proto);
1645 dissector_handle_t guid_handle;
1650 value->proto = find_protocol_by_id(proto);
1651 value->proto_id = proto;
1653 value->name = proto_get_protocol_short_name(value->proto);
1654 value->procs = procs;
1655 value->opnum_hf = opnum_hf;
1657 g_hash_table_insert(dcerpc_uuids, key, value);
1659 hf_info = proto_registrar_get_nth(opnum_hf);
1660 hf_info->strings = value_string_from_subdissectors(procs);
1662 /* Register the GUID with the dissector table */
1663 guid_handle = create_dissector_handle( dissect_dcerpc_guid, proto);
1664 dissector_add_guid( "dcerpc.uuid", key, guid_handle );
1666 /* add this GUID to the global name resolving */
1667 guids_add_uuid(uuid, proto_get_protocol_short_name(value->proto));
1669 /* Register the samr.nt_password preference as obsolete */
1670 /* This should be in packet-dcerpc-samr.c */
1671 if (strcmp(filter_name, "samr") == 0) {
1672 samr_module = prefs_register_protocol(proto, NULL);
1673 prefs_register_obsolete_preference(samr_module, "nt_password");
1677 /* Function to find the name of a registered protocol
1678 * or NULL if the protocol/version is not known to wireshark.
1681 dcerpc_get_proto_name(e_guid_t *uuid, guint16 ver)
1683 dissector_handle_t handle;
1689 handle = dissector_get_guid_handle(uuid_dissector_table, &key);
1690 if (handle == NULL) {
1694 return dissector_handle_get_short_name(handle);
1697 /* Function to find the opnum hf-field of a registered protocol
1698 * or -1 if the protocol/version is not known to wireshark.
1701 dcerpc_get_proto_hf_opnum(e_guid_t *uuid, guint16 ver)
1704 dcerpc_uuid_value *sub_proto;
1708 if (!(sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key))) {
1711 return sub_proto->opnum_hf;
1714 /* Create a value_string consisting of DCERPC opnum and name from a
1715 subdissector array. */
1717 value_string *value_string_from_subdissectors(dcerpc_sub_dissector *sd)
1719 value_string *vs = NULL;
1724 for (i = 0; sd[i].name; i++) {
1726 vs[i].value = sd[i].num;
1727 vs[i].strptr = sd[i].name;
1733 vs = (value_string *)wmem_alloc(wmem_epan_scope(), (num_sd + 1) * sizeof(value_string));
1737 vs[num_sd].value = 0;
1738 vs[num_sd].strptr = NULL;
1743 /* Function to find the subdissector table of a registered protocol
1744 * or NULL if the protocol/version is not known to wireshark.
1746 dcerpc_sub_dissector *
1747 dcerpc_get_proto_sub_dissector(e_guid_t *uuid, guint16 ver)
1750 dcerpc_uuid_value *sub_proto;
1754 if (!(sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key))) {
1757 return sub_proto->procs;
1763 dcerpc_bind_equal(gconstpointer k1, gconstpointer k2)
1765 const dcerpc_bind_key *key1 = (const dcerpc_bind_key *)k1;
1766 const dcerpc_bind_key *key2 = (const dcerpc_bind_key *)k2;
1767 return ((key1->conv == key2->conv)
1768 && (key1->ctx_id == key2->ctx_id)
1769 && (key1->transport_salt == key2->transport_salt));
1773 dcerpc_bind_hash(gconstpointer k)
1775 const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
1778 hash = GPOINTER_TO_UINT(key->conv);
1779 hash += key->ctx_id;
1780 /* sizeof(guint) might be smaller than sizeof(guint64) */
1781 hash += (guint)key->transport_salt;
1782 hash += (guint)(key->transport_salt << sizeof(guint));
1788 * To keep track of callid mappings. Should really use some generic
1789 * conversation support instead.
1791 static GHashTable *dcerpc_cn_calls = NULL;
1792 static GHashTable *dcerpc_dg_calls = NULL;
1794 typedef struct _dcerpc_cn_call_key {
1795 conversation_t *conv;
1797 guint64 transport_salt;
1798 } dcerpc_cn_call_key;
1800 typedef struct _dcerpc_dg_call_key {
1801 conversation_t *conv;
1804 } dcerpc_dg_call_key;
1808 dcerpc_cn_call_equal(gconstpointer k1, gconstpointer k2)
1810 const dcerpc_cn_call_key *key1 = (const dcerpc_cn_call_key *)k1;
1811 const dcerpc_cn_call_key *key2 = (const dcerpc_cn_call_key *)k2;
1812 return ((key1->conv == key2->conv)
1813 && (key1->call_id == key2->call_id)
1814 && (key1->transport_salt == key2->transport_salt));
1818 dcerpc_dg_call_equal(gconstpointer k1, gconstpointer k2)
1820 const dcerpc_dg_call_key *key1 = (const dcerpc_dg_call_key *)k1;
1821 const dcerpc_dg_call_key *key2 = (const dcerpc_dg_call_key *)k2;
1822 return ((key1->conv == key2->conv)
1823 && (key1->seqnum == key2->seqnum)
1824 && ((memcmp(&key1->act_id, &key2->act_id, sizeof (e_guid_t)) == 0)));
1828 dcerpc_cn_call_hash(gconstpointer k)
1830 const dcerpc_cn_call_key *key = (const dcerpc_cn_call_key *)k;
1833 hash = GPOINTER_TO_UINT(key->conv);
1834 hash += key->call_id;
1835 /* sizeof(guint) might be smaller than sizeof(guint64) */
1836 hash += (guint)key->transport_salt;
1837 hash += (guint)(key->transport_salt << sizeof(guint));
1843 dcerpc_dg_call_hash(gconstpointer k)
1845 const dcerpc_dg_call_key *key = (const dcerpc_dg_call_key *)k;
1846 return (GPOINTER_TO_UINT(key->conv) + key->seqnum + key->act_id.data1
1847 + (key->act_id.data2 << 16) + key->act_id.data3
1848 + (key->act_id.data4[0] << 24) + (key->act_id.data4[1] << 16)
1849 + (key->act_id.data4[2] << 8) + (key->act_id.data4[3] << 0)
1850 + (key->act_id.data4[4] << 24) + (key->act_id.data4[5] << 16)
1851 + (key->act_id.data4[6] << 8) + (key->act_id.data4[7] << 0));
1854 /* to keep track of matched calls/responses
1855 this one uses the same value struct as calls, but the key is the frame id
1856 and call id; there can be more than one call in a frame.
1858 XXX - why not just use the same keys as are used for calls?
1861 static GHashTable *dcerpc_matched = NULL;
1863 typedef struct _dcerpc_matched_key {
1866 } dcerpc_matched_key;
1869 dcerpc_matched_equal(gconstpointer k1, gconstpointer k2)
1871 const dcerpc_matched_key *key1 = (const dcerpc_matched_key *)k1;
1872 const dcerpc_matched_key *key2 = (const dcerpc_matched_key *)k2;
1873 return ((key1->frame == key2->frame)
1874 && (key1->call_id == key2->call_id));
1878 dcerpc_matched_hash(gconstpointer k)
1880 const dcerpc_matched_key *key = (const dcerpc_matched_key *)k;
1885 uuid_equal(e_guid_t *uuid1, e_guid_t *uuid2)
1887 if( (uuid1->data1 != uuid2->data1)
1888 ||(uuid1->data2 != uuid2->data2)
1889 ||(uuid1->data3 != uuid2->data3)
1890 ||(uuid1->data4[0] != uuid2->data4[0])
1891 ||(uuid1->data4[1] != uuid2->data4[1])
1892 ||(uuid1->data4[2] != uuid2->data4[2])
1893 ||(uuid1->data4[3] != uuid2->data4[3])
1894 ||(uuid1->data4[4] != uuid2->data4[4])
1895 ||(uuid1->data4[5] != uuid2->data4[5])
1896 ||(uuid1->data4[6] != uuid2->data4[6])
1897 ||(uuid1->data4[7] != uuid2->data4[7]) ){
1904 dcerpcstat_init(struct register_srt* srt, GArray* srt_array, srt_gui_init_cb gui_callback, void* gui_data)
1906 dcerpcstat_tap_data_t* tap_data = (dcerpcstat_tap_data_t*)get_srt_table_param_data(srt);
1907 srt_stat_table *dcerpc_srt_table;
1909 dcerpc_sub_dissector *procs;
1911 DISSECTOR_ASSERT(tap_data);
1913 hf_opnum = dcerpc_get_proto_hf_opnum(&tap_data->uuid, tap_data->ver);
1914 procs = dcerpc_get_proto_sub_dissector(&tap_data->uuid, tap_data->ver);
1917 dcerpc_srt_table = init_srt_table(tap_data->prog, NULL, srt_array, tap_data->num_procedures, NULL, proto_registrar_get_nth(hf_opnum)->abbrev, gui_callback, gui_data, tap_data);
1919 dcerpc_srt_table = init_srt_table(tap_data->prog, NULL, srt_array, tap_data->num_procedures, NULL, NULL, gui_callback, gui_data, tap_data);
1922 for(i=0;i<tap_data->num_procedures;i++){
1924 const char *proc_name;
1926 proc_name = "unknown";
1927 for(j=0;procs[j].name;j++)
1929 if (procs[j].num == i)
1931 proc_name = procs[j].name;
1935 init_srt_table_row(dcerpc_srt_table, i, proc_name);
1940 dcerpcstat_packet(void *pss, packet_info *pinfo, epan_dissect_t *edt _U_, const void *prv)
1943 srt_stat_table *dcerpc_srt_table;
1944 srt_data_t *data = (srt_data_t *)pss;
1945 const dcerpc_info *ri = (const dcerpc_info *)prv;
1946 dcerpcstat_tap_data_t* tap_data;
1948 dcerpc_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
1949 tap_data = (dcerpcstat_tap_data_t*)dcerpc_srt_table->table_specific_data;
1954 if(!ri->call_data->req_frame){
1955 /* we have not seen the request so we don't know the delta*/
1958 if(ri->call_data->opnum >= tap_data->num_procedures){
1959 /* don't handle this since it's outside of known table */
1963 /* we are only interested in reply packets */
1964 if(ri->ptype != PDU_RESP){
1968 /* we are only interested in certain program/versions */
1969 if( (!uuid_equal( (&ri->call_data->uuid), (&tap_data->uuid)))
1970 ||(ri->call_data->ver != tap_data->ver)){
1974 add_srt_table_data(dcerpc_srt_table, ri->call_data->opnum, &ri->call_data->req_time, pinfo);
1980 dcerpcstat_param(register_srt_t* srt, const char* opt_arg, char** err)
1983 guint32 i, max_procs;
1984 dcerpcstat_tap_data_t* tap_data;
1985 guint d1,d2,d3,d40,d41,d42,d43,d44,d45,d46,d47;
1988 dcerpc_sub_dissector *procs;
1990 if (sscanf(opt_arg, ",%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x,%d.%d%n",
1991 &d1,&d2,&d3,&d40,&d41,&d42,&d43,&d44,&d45,&d46,&d47,&major,&minor,&pos) == 13)
1993 if ((major < 0) || (major > 65535)) {
1994 *err = g_strdup_printf("dcerpcstat_init() Major version number %d is invalid - must be positive and <= 65535", major);
1997 if ((minor < 0) || (minor > 65535)) {
1998 *err = g_strdup_printf("dcerpcstat_init() Minor version number %d is invalid - must be positive and <= 65535", minor);
2003 tap_data = g_new0(dcerpcstat_tap_data_t, 1);
2005 tap_data->uuid.data1 = d1;
2006 tap_data->uuid.data2 = d2;
2007 tap_data->uuid.data3 = d3;
2008 tap_data->uuid.data4[0] = d40;
2009 tap_data->uuid.data4[1] = d41;
2010 tap_data->uuid.data4[2] = d42;
2011 tap_data->uuid.data4[3] = d43;
2012 tap_data->uuid.data4[4] = d44;
2013 tap_data->uuid.data4[5] = d45;
2014 tap_data->uuid.data4[6] = d46;
2015 tap_data->uuid.data4[7] = d47;
2017 procs = dcerpc_get_proto_sub_dissector(&tap_data->uuid, ver);
2018 tap_data->prog = dcerpc_get_proto_name(&tap_data->uuid, ver);
2019 tap_data->ver = ver;
2021 for(i=0,max_procs=0;procs[i].name;i++)
2023 if(procs[i].num>max_procs)
2025 max_procs = procs[i].num;
2028 tap_data->num_procedures = max_procs+1;
2030 set_srt_table_param_data(srt, tap_data);
2034 *err = g_strdup_printf("<uuid>,<major version>.<minor version>[,<filter>]");
2042 * Utility functions. Modeled after packet-rpc.c
2046 dissect_dcerpc_char(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
2047 proto_tree *tree, guint8 *drep,
2048 int hfindex, guint8 *pdata)
2053 * XXX - fix to handle EBCDIC if we ever support EBCDIC FT_CHAR.
2055 data = tvb_get_guint8(tvb, offset);
2056 if (hfindex != -1) {
2057 proto_tree_add_item(tree, hfindex, tvb, offset, 1, ENC_ASCII|DREP_ENC_INTEGER(drep));
2061 tvb_ensure_bytes_exist(tvb, offset, 1);
2066 dissect_dcerpc_uint8(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
2067 proto_tree *tree, guint8 *drep,
2068 int hfindex, guint8 *pdata)
2072 data = tvb_get_guint8(tvb, offset);
2073 if (hfindex != -1) {
2074 proto_tree_add_item(tree, hfindex, tvb, offset, 1, DREP_ENC_INTEGER(drep));
2078 tvb_ensure_bytes_exist(tvb, offset, 1);
2083 dissect_dcerpc_uint16(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
2084 proto_tree *tree, guint8 *drep,
2085 int hfindex, guint16 *pdata)
2089 data = ((drep[0] & DREP_LITTLE_ENDIAN)
2090 ? tvb_get_letohs(tvb, offset)
2091 : tvb_get_ntohs(tvb, offset));
2093 if (hfindex != -1) {
2094 proto_tree_add_item(tree, hfindex, tvb, offset, 2, DREP_ENC_INTEGER(drep));
2098 tvb_ensure_bytes_exist(tvb, offset, 2);
2103 dissect_dcerpc_uint32(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
2104 proto_tree *tree, guint8 *drep,
2105 int hfindex, guint32 *pdata)
2109 data = ((drep[0] & DREP_LITTLE_ENDIAN)
2110 ? tvb_get_letohl(tvb, offset)
2111 : tvb_get_ntohl(tvb, offset));
2113 if (hfindex != -1) {
2114 proto_tree_add_item(tree, hfindex, tvb, offset, 4, DREP_ENC_INTEGER(drep));
2118 tvb_ensure_bytes_exist(tvb, offset, 4);
2122 /* handles 32 bit unix time_t */
2124 dissect_dcerpc_time_t(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
2125 proto_tree *tree, guint8 *drep,
2126 int hfindex, guint32 *pdata)
2131 data = ((drep[0] & DREP_LITTLE_ENDIAN)
2132 ? tvb_get_letohl(tvb, offset)
2133 : tvb_get_ntohl(tvb, offset));
2137 if (hfindex != -1) {
2138 if (data == 0xffffffff) {
2139 /* special case, no time specified */
2140 proto_tree_add_time_format_value(tree, hfindex, tvb, offset, 4, &tv, "No time specified");
2142 proto_tree_add_time(tree, hfindex, tvb, offset, 4, &tv);
2148 tvb_ensure_bytes_exist(tvb, offset, 4);
2153 dissect_dcerpc_uint64(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
2154 proto_tree *tree, dcerpc_info *di, guint8 *drep,
2155 int hfindex, guint64 *pdata)
2159 data = ((drep[0] & DREP_LITTLE_ENDIAN)
2160 ? tvb_get_letoh64(tvb, offset)
2161 : tvb_get_ntoh64(tvb, offset));
2163 if (hfindex != -1) {
2164 header_field_info *hfinfo;
2166 /* This might be a field that is either 32bit, in NDR or
2167 64 bits in NDR64. So we must be careful and call the right
2170 hfinfo = proto_registrar_get_nth(hfindex);
2172 switch (hfinfo->type) {
2174 proto_tree_add_uint64(tree, hfindex, tvb, offset, 8, data);
2177 proto_tree_add_int64(tree, hfindex, tvb, offset, 8, data);
2180 /* The value is truncated to 32bits. 64bit values have only been
2181 seen on fuzz-tested files */
2182 DISSECTOR_ASSERT((di->call_data->flags & DCERPC_IS_NDR64) || (data <= G_MAXUINT32));
2183 proto_tree_add_uint(tree, hfindex, tvb, offset, 8, (guint32)data);
2188 tvb_ensure_bytes_exist(tvb, offset, 8);
2194 dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
2195 proto_tree *tree, guint8 *drep,
2196 int hfindex, gfloat *pdata)
2202 case(DCE_RPC_DREP_FP_IEEE):
2203 data = ((drep[0] & DREP_LITTLE_ENDIAN)
2204 ? tvb_get_letohieee_float(tvb, offset)
2205 : tvb_get_ntohieee_float(tvb, offset));
2206 if (tree && hfindex != -1) {
2207 proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
2210 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
2211 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
2212 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
2214 /* ToBeDone: non IEEE floating formats */
2215 /* Set data to a negative infinity value */
2217 if (tree && hfindex != -1) {
2218 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep[1]);
2223 tvb_ensure_bytes_exist(tvb, offset, 4);
2229 dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
2230 proto_tree *tree, guint8 *drep,
2231 int hfindex, gdouble *pdata)
2237 case(DCE_RPC_DREP_FP_IEEE):
2238 data = ((drep[0] & DREP_LITTLE_ENDIAN)
2239 ? tvb_get_letohieee_double(tvb, offset)
2240 : tvb_get_ntohieee_double(tvb, offset));
2241 if (tree && hfindex != -1) {
2242 proto_tree_add_double(tree, hfindex, tvb, offset, 8, data);
2245 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
2246 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
2247 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
2249 /* ToBeDone: non IEEE double formats */
2250 /* Set data to a negative infinity value */
2251 data = -G_MAXDOUBLE;
2252 if (tree && hfindex != -1) {
2253 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep[1]);
2258 tvb_ensure_bytes_exist(tvb, offset, 8);
2264 dissect_dcerpc_uuid_t(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
2265 proto_tree *tree, guint8 *drep,
2266 int hfindex, e_guid_t *pdata)
2271 if (drep[0] & DREP_LITTLE_ENDIAN) {
2272 tvb_get_letohguid(tvb, offset, (e_guid_t *) &uuid);
2274 tvb_get_ntohguid(tvb, offset, (e_guid_t *) &uuid);
2276 if (tree && hfindex != -1) {
2277 proto_tree_add_guid(tree, hfindex, tvb, offset, 16, (e_guid_t *) &uuid);
2287 * a couple simpler things
2290 dcerpc_tvb_get_ntohs(tvbuff_t *tvb, gint offset, guint8 *drep)
2292 if (drep[0] & DREP_LITTLE_ENDIAN) {
2293 return tvb_get_letohs(tvb, offset);
2295 return tvb_get_ntohs(tvb, offset);
2300 dcerpc_tvb_get_ntohl(tvbuff_t *tvb, gint offset, guint8 *drep)
2302 if (drep[0] & DREP_LITTLE_ENDIAN) {
2303 return tvb_get_letohl(tvb, offset);
2305 return tvb_get_ntohl(tvb, offset);
2310 dcerpc_tvb_get_uuid(tvbuff_t *tvb, gint offset, guint8 *drep, e_guid_t *uuid)
2312 if (drep[0] & DREP_LITTLE_ENDIAN) {
2313 tvb_get_letohguid(tvb, offset, (e_guid_t *) uuid);
2315 tvb_get_ntohguid(tvb, offset, (e_guid_t *) uuid);
2321 /* function to dissect a unidimensional conformant array */
2323 dissect_ndr_ucarray_core(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2324 proto_tree *tree, dcerpc_info *di, guint8 *drep,
2325 dcerpc_dissect_fnct_t *fnct_bytes,
2326 dcerpc_dissect_fnct_blk_t *fnct_block)
2330 int conformance_size = 4;
2332 /* ensure that just one pointer is set in the call */
2333 DISSECTOR_ASSERT((fnct_bytes && !fnct_block) || (!fnct_bytes && fnct_block));
2335 if (di->call_data->flags & DCERPC_IS_NDR64) {
2336 conformance_size = 8;
2339 if (di->conformant_run) {
2342 /* conformant run, just dissect the max_count header */
2343 old_offset = offset;
2344 di->conformant_run = 0;
2345 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
2346 hf_dcerpc_array_max_count, &val);
2347 di->array_max_count = (gint32)val;
2348 di->array_max_count_offset = offset-conformance_size;
2349 di->conformant_run = 1;
2350 di->conformant_eaten = offset-old_offset;
2352 /* we don't remember where in the bytestream this field was */
2353 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, conformance_size, di->array_max_count);
2355 /* real run, dissect the elements */
2357 offset = (*fnct_block)(tvb, offset, di->array_max_count,
2358 pinfo, tree, di, drep);
2360 for (i=0 ;i<di->array_max_count; i++) {
2361 offset = (*fnct_bytes)(tvb, offset, pinfo, tree, di, drep);
2370 dissect_ndr_ucarray_block(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2371 proto_tree *tree, dcerpc_info *di, guint8 *drep,
2372 dcerpc_dissect_fnct_blk_t *fnct)
2374 return dissect_ndr_ucarray_core(tvb, offset, pinfo, tree, di, drep, NULL, fnct);
2378 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2379 proto_tree *tree, dcerpc_info *di, guint8 *drep,
2380 dcerpc_dissect_fnct_t *fnct)
2382 return dissect_ndr_ucarray_core(tvb, offset, pinfo, tree, di, drep, fnct, NULL);
2385 /* function to dissect a unidimensional conformant and varying array
2386 * depending on the dissection function passed as a parameter,
2387 * content of the array will be dissected as a block or byte by byte
2390 dissect_ndr_ucvarray_core(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2391 proto_tree *tree, dcerpc_info *di, guint8 *drep,
2392 dcerpc_dissect_fnct_t *fnct_bytes,
2393 dcerpc_dissect_fnct_blk_t *fnct_block)
2397 int conformance_size = 4;
2399 if (di->call_data->flags & DCERPC_IS_NDR64) {
2400 conformance_size = 8;
2403 if (di->conformant_run) {
2406 /* conformant run, just dissect the max_count header */
2407 old_offset = offset;
2408 di->conformant_run = 0;
2409 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
2410 hf_dcerpc_array_max_count, &val);
2411 DISSECTOR_ASSERT(val <= G_MAXUINT32);
2412 di->array_max_count = (guint32)val;
2413 di->array_max_count_offset = offset-conformance_size;
2414 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
2415 hf_dcerpc_array_offset, &val);
2416 DISSECTOR_ASSERT(val <= G_MAXUINT32);
2417 di->array_offset = (guint32)val;
2418 di->array_offset_offset = offset-conformance_size;
2419 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
2420 hf_dcerpc_array_actual_count, &val);
2421 DISSECTOR_ASSERT(val <= G_MAXUINT32);
2422 di->array_actual_count = (guint32)val;
2423 di->array_actual_count_offset = offset-conformance_size;
2424 di->conformant_run = 1;
2425 di->conformant_eaten = offset-old_offset;
2427 /* we don't remember where in the bytestream these fields were */
2428 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, conformance_size, di->array_max_count);
2429 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, conformance_size, di->array_offset);
2430 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, conformance_size, di->array_actual_count);
2432 /* real run, dissect the elements */
2434 offset = (*fnct_block)(tvb, offset, di->array_actual_count,
2435 pinfo, tree, di, drep);
2436 } else if (fnct_bytes) {
2437 for (i=0 ;i<di->array_actual_count; i++) {
2438 old_offset = offset;
2439 offset = (*fnct_bytes)(tvb, offset, pinfo, tree, di, drep);
2440 /* Make sure we're moving forward */
2441 if (old_offset >= offset)
2451 dissect_ndr_ucvarray_block(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2452 proto_tree *tree, dcerpc_info *di, guint8 *drep,
2453 dcerpc_dissect_fnct_blk_t *fnct)
2455 return dissect_ndr_ucvarray_core(tvb, offset, pinfo, tree, di, drep, NULL, fnct);
2459 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2460 proto_tree *tree, dcerpc_info *di, guint8 *drep,
2461 dcerpc_dissect_fnct_t *fnct)
2463 return dissect_ndr_ucvarray_core(tvb, offset, pinfo, tree, di, drep, fnct, NULL);
2465 /* function to dissect a unidimensional varying array */
2467 dissect_ndr_uvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2468 proto_tree *tree, dcerpc_info *di, guint8 *drep,
2469 dcerpc_dissect_fnct_t *fnct)
2473 int conformance_size = 4;
2475 if (di->call_data->flags & DCERPC_IS_NDR64) {
2476 conformance_size = 8;
2479 if (di->conformant_run) {
2482 /* conformant run, just dissect the max_count header */
2483 old_offset = offset;
2484 di->conformant_run = 0;
2485 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
2486 hf_dcerpc_array_offset, &val);
2487 DISSECTOR_ASSERT(val <= G_MAXUINT32);
2488 di->array_offset = (guint32)val;
2489 di->array_offset_offset = offset-conformance_size;
2490 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
2491 hf_dcerpc_array_actual_count, &val);
2492 DISSECTOR_ASSERT(val <= G_MAXUINT32);
2493 di->array_actual_count = (guint32)val;
2494 di->array_actual_count_offset = offset-conformance_size;
2495 di->conformant_run = 1;
2496 di->conformant_eaten = offset-old_offset;
2498 /* we don't remember where in the bytestream these fields were */
2499 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, conformance_size, di->array_offset);
2500 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, conformance_size, di->array_actual_count);
2502 /* real run, dissect the elements */
2503 for (i=0; i<di->array_actual_count; i++) {
2504 offset = (*fnct)(tvb, offset, pinfo, tree, di, drep);
2511 /* Dissect an string of bytes. This corresponds to
2512 IDL of the form '[string] byte *foo'.
2514 It can also be used for a conformant varying array of bytes if
2515 the contents of the array should be shown as a big blob, rather
2516 than showing each byte as an individual element.
2518 XXX - which of those is really the IDL type for, for example,
2519 the encrypted data in some MAPI packets? (Microsoft hasn't
2522 XXX - does this need to do all the conformant array stuff that
2523 "dissect_ndr_ucvarray()" does? These are presumably for strings
2524 that are conformant and varying - they're stored like conformant
2525 varying arrays of bytes. */
2527 dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo,
2528 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2532 if (di->conformant_run) {
2533 /* just a run to handle conformant arrays, no scalars to dissect */
2537 /* NDR array header */
2539 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
2540 hf_dcerpc_array_max_count, NULL);
2542 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
2543 hf_dcerpc_array_offset, NULL);
2545 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
2546 hf_dcerpc_array_actual_count, &len);
2548 DISSECTOR_ASSERT(len <= G_MAXUINT32);
2550 proto_tree_add_item(tree, di->hf_index, tvb, offset, (guint32)len,
2554 offset += (guint32)len;
2559 /* For dissecting arrays that are to be interpreted as strings. */
2561 /* Dissect an NDR conformant varying string of elements.
2562 The length of each element is given by the 'size_is' parameter;
2563 the elements are assumed to be characters or wide characters.
2565 XXX - does this need to do all the conformant array stuff that
2566 "dissect_ndr_ucvarray()" does? */
2568 dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2569 proto_tree *tree, dcerpc_info *di, guint8 *drep, int size_is,
2570 int hfindex, gboolean add_subtree, char **data)
2572 header_field_info *hfinfo;
2573 proto_item *string_item;
2574 proto_tree *string_tree;
2579 /* Make sure this really is a string field. */
2580 hfinfo = proto_registrar_get_nth(hfindex);
2581 DISSECTOR_ASSERT(hfinfo->type == FT_STRING);
2583 if (di->conformant_run) {
2584 /* just a run to handle conformant arrays, no scalars to dissect */
2589 string_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_dcerpc_string, &string_item,
2590 proto_registrar_get_name(hfindex));
2596 /* NDR array header */
2598 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
2599 hf_dcerpc_array_max_count, NULL);
2601 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
2602 hf_dcerpc_array_offset, NULL);
2604 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
2605 hf_dcerpc_array_actual_count, &len);
2607 /* The value is truncated to 32bits. 64bit values have only been
2608 seen on fuzztested files */
2609 buffer_len = size_is * (guint32)len;
2612 if (!di->no_align && (offset % size_is))
2613 offset += size_is - (offset % size_is);
2616 * "tvb_get_string_enc()" throws an exception if the entire string
2617 * isn't in the tvbuff. If the length is bogus, this should
2618 * keep us from trying to allocate an immensely large buffer.
2619 * (It won't help if the length is *valid* but immensely large,
2620 * but that's another matter; in any case, that would happen only
2621 * if we had an immensely large tvbuff....)
2623 * XXX - so why are we doing tvb_ensure_bytes_exist()?
2625 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
2626 if (size_is == sizeof(guint16)) {
2628 * Assume little-endian UTF-16.
2630 * XXX - is this always little-endian?
2632 s = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, buffer_len,
2633 ENC_UTF_16|ENC_LITTLE_ENDIAN);
2636 * XXX - what if size_is is neither 1 nor 2?
2638 s = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, buffer_len,
2639 DREP_ENC_CHAR(drep));
2641 if (tree && buffer_len)
2642 proto_tree_add_string(string_tree, hfindex, tvb, offset,
2645 if (string_item != NULL)
2646 proto_item_append_text(string_item, ": %s", s);
2651 offset += buffer_len;
2653 proto_item_set_end(string_item, tvb, offset);
2659 dissect_ndr_cstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2660 proto_tree *tree, dcerpc_info *di, guint8 *drep, int size_is,
2661 int hfindex, gboolean add_subtree, char **data)
2663 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep, size_is, hfindex, add_subtree, data);
2666 /* Dissect an conformant varying string of chars.
2667 This corresponds to IDL of the form '[string] char *foo'.
2669 XXX - at least according to the DCE RPC 1.1 spec, a string has
2670 a null terminator, which isn't necessary as a terminator for
2671 the transfer language (as there's a length), but is presumably
2672 there for the benefit of null-terminated-string languages
2673 such as C. Is this ever used for purely counted strings?
2674 (Not that it matters if it is.) */
2676 dissect_ndr_char_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2677 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2679 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep,
2680 sizeof(guint8), di->hf_index,
2684 /* Dissect a conformant varying string of wchars (wide characters).
2685 This corresponds to IDL of the form '[string] wchar *foo'
2687 XXX - at least according to the DCE RPC 1.1 spec, a string has
2688 a null terminator, which isn't necessary as a terminator for
2689 the transfer language (as there's a length), but is presumably
2690 there for the benefit of null-terminated-string languages
2691 such as C. Is this ever used for purely counted strings?
2692 (Not that it matters if it is.) */
2694 dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2695 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2697 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep,
2698 sizeof(guint16), di->hf_index,
2702 /* This function is aimed for PIDL usage and dissects a UNIQUE pointer to
2706 PIDL_dissect_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep, int chsize, int hfindex, guint32 param)
2709 gint levels = CB_STR_ITEM_LEVELS(param);
2711 offset = dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep,
2715 if (!di->conformant_run) {
2716 /* Append string to COL_INFO */
2717 if (param & PIDL_SET_COL_INFO) {
2718 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", s);
2720 /* Save string to dcv->private_data */
2721 if ((param & PIDL_STR_SAVE)
2722 && (!pinfo->fd->flags.visited)) {
2723 dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2724 dcv->private_data = wmem_strdup(wmem_file_scope(), s);
2726 /* Append string to upper-level proto_items */
2727 if ((levels > 0) && tree && s && s[0]) {
2728 proto_item_append_text(tree, ": %s", s);
2729 tree = tree->parent;
2732 proto_item_append_text(tree, ": %s", s);
2733 tree = tree->parent;
2735 while (levels > 0) {
2736 proto_item_append_text(tree, " %s", s);
2737 tree = tree->parent;
2748 /* Dissect an NDR varying string of elements.
2749 The length of each element is given by the 'size_is' parameter;
2750 the elements are assumed to be characters or wide characters.
2753 dissect_ndr_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2754 proto_tree *tree, dcerpc_info *di, guint8 *drep, int size_is,
2755 int hfindex, gboolean add_subtree, char **data)
2757 header_field_info *hfinfo;
2758 proto_item *string_item;
2759 proto_tree *string_tree;
2764 /* Make sure this really is a string field. */
2765 hfinfo = proto_registrar_get_nth(hfindex);
2766 DISSECTOR_ASSERT(hfinfo->type == FT_STRING);
2768 if (di->conformant_run) {
2769 /* just a run to handle conformant arrays, no scalars to dissect */
2774 string_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_dcerpc_string, &string_item,
2775 proto_registrar_get_name(hfindex));
2781 /* NDR array header */
2782 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
2783 hf_dcerpc_array_offset, NULL);
2785 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
2786 hf_dcerpc_array_actual_count, &len);
2788 DISSECTOR_ASSERT(len <= G_MAXUINT32);
2789 buffer_len = size_is * (guint32)len;
2792 if (!di->no_align && (offset % size_is))
2793 offset += size_is - (offset % size_is);
2796 * "tvb_get_string_enc()" throws an exception if the entire string
2797 * isn't in the tvbuff. If the length is bogus, this should
2798 * keep us from trying to allocate an immensely large buffer.
2799 * (It won't help if the length is *valid* but immensely large,
2800 * but that's another matter; in any case, that would happen only
2801 * if we had an immensely large tvbuff....)
2803 * XXX - so why are we doing tvb_ensure_bytes_exist()?
2805 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
2806 if (size_is == sizeof(guint16)) {
2808 * Assume little-endian UTF-16.
2810 * XXX - is this always little-endian?
2812 s = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, buffer_len,
2813 ENC_UTF_16|ENC_LITTLE_ENDIAN);
2816 * XXX - what if size_is is neither 1 nor 2?
2818 s = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, buffer_len,
2819 DREP_ENC_CHAR(drep));
2821 if (tree && buffer_len)
2822 proto_tree_add_string(string_tree, hfindex, tvb, offset,
2825 if (string_item != NULL)
2826 proto_item_append_text(string_item, ": %s", s);
2831 offset += buffer_len;
2833 proto_item_set_end(string_item, tvb, offset);
2838 /* Dissect an varying string of chars.
2839 This corresponds to IDL of the form '[string] char *foo'.
2841 XXX - at least according to the DCE RPC 1.1 spec, a string has
2842 a null terminator, which isn't necessary as a terminator for
2843 the transfer language (as there's a length), but is presumably
2844 there for the benefit of null-terminated-string languages
2845 such as C. Is this ever used for purely counted strings?
2846 (Not that it matters if it is.) */
2848 dissect_ndr_char_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2849 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2851 return dissect_ndr_vstring(tvb, offset, pinfo, tree, di, drep,
2852 sizeof(guint8), di->hf_index,
2856 /* Dissect a varying string of wchars (wide characters).
2857 This corresponds to IDL of the form '[string] wchar *foo'
2859 XXX - at least according to the DCE RPC 1.1 spec, a string has
2860 a null terminator, which isn't necessary as a terminator for
2861 the transfer language (as there's a length), but is presumably
2862 there for the benefit of null-terminated-string languages
2863 such as C. Is this ever used for purely counted strings?
2864 (Not that it matters if it is.) */
2866 dissect_ndr_wchar_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2867 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2869 return dissect_ndr_vstring(tvb, offset, pinfo, tree, di, drep,
2870 sizeof(guint16), di->hf_index,
2875 /* ndr pointer handling */
2876 /* list of pointers encountered so far */
2877 static GSList *ndr_pointer_list = NULL;
2879 /* position where in the list to insert newly encountered pointers */
2880 static int ndr_pointer_list_pos = 0;
2882 /* Boolean controlling whether pointers are top-level or embedded */
2883 static gboolean pointers_are_top_level = TRUE;
2885 /* as a kludge, we represent all embedded reference pointers as id == -1
2886 hoping that his will not collide with any non-ref pointers */
2887 typedef struct ndr_pointer_data {
2889 proto_item *item; /* proto_item for pointer */
2890 proto_tree *tree; /* subtree of above item */
2891 dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
2893 dcerpc_callback_fnct_t *callback;
2894 void *callback_args;
2895 } ndr_pointer_data_t;
2898 init_ndr_pointer_list(dcerpc_info *di)
2900 di->conformant_run = 0;
2902 while (ndr_pointer_list) {
2903 ndr_pointer_data_t *npd = (ndr_pointer_data_t *)g_slist_nth_data(ndr_pointer_list, 0);
2904 ndr_pointer_list = g_slist_remove(ndr_pointer_list, npd);
2908 ndr_pointer_list = NULL;
2909 ndr_pointer_list_pos = 0;
2910 pointers_are_top_level = TRUE;
2914 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, dcerpc_info *di, guint8 *drep)
2916 int found_new_pointer;
2925 found_new_pointer = 0;
2926 len = g_slist_length(ndr_pointer_list);
2927 for (i=next_pointer; i<len; i++) {
2928 ndr_pointer_data_t *tnpd = (ndr_pointer_data_t *)g_slist_nth_data(ndr_pointer_list, i);
2930 dcerpc_dissect_fnct_t *fnct;
2933 found_new_pointer = 1;
2936 ndr_pointer_list_pos = i+1;
2937 di->hf_index = tnpd->hf_index;
2938 /* first a run to handle any conformant
2940 di->conformant_run = 1;
2941 di->conformant_eaten = 0;
2942 old_offset = offset;
2943 offset = (*(fnct))(tvb, offset, pinfo, NULL, di, drep);
2945 DISSECTOR_ASSERT((offset-old_offset) == di->conformant_eaten);
2946 /* This is to check for any bugs in the dissectors.
2948 * Basically, the NDR representation will store all
2949 * arrays in two blocks, one block with the dimension
2950 * description, like size, number of elements and such,
2951 * and another block that contains the actual data stored
2953 * If the array is embedded directly inside another,
2954 * encapsulating aggregate type, like a union or struct,
2955 * then these two blocks will be stored at different places
2956 * in the bytestream, with other data between the blocks.
2958 * For this reason, all pointers to types (both aggregate
2959 * and scalar, for simplicity no distinction is made)
2960 * will have its dissector called twice.
2961 * The dissector will first be called with conformant_run == 1
2962 * in which mode the dissector MUST NOT consume any data from
2963 * the tvbuff (i.e. may not dissect anything) except the
2964 * initial control block for arrays.
2965 * The second time the dissector is called, with
2966 * conformant_run == 0, all other data for the type will be
2969 * All dissect_ndr_<type> dissectors are already prepared
2970 * for this and knows when it should eat data from the tvb
2971 * and when not to, so implementors of dissectors will
2972 * normally not need to worry about this or even know about
2973 * it. However, if a dissector for an aggregate type calls
2974 * a subdissector from outside packet-dcerpc.c, such as
2975 * the dissector in packet-smb.c for NT Security Descriptors
2976 * as an example, then it is VERY important to encapsulate
2977 * this call to an external subdissector with the appropriate
2978 * test for conformant_run, i.e. it will need something like
2980 * dcerpc_info *di (received as function parameter)
2982 * if (di->conformant_run) {
2986 * to make sure it makes the right thing.
2987 * This assert will signal when someone has forgotten to
2988 * make the dissector aware of this requirement.
2991 /* now we dissect the actual pointer */
2992 di->conformant_run = 0;
2993 old_offset = offset;
2994 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, di, drep);
2996 tnpd->callback(pinfo, tnpd->tree, tnpd->item, di, tvb, old_offset, offset, tnpd->callback_args);
2997 proto_item_set_len(tnpd->item, offset - old_offset);
3001 } while (found_new_pointer);
3008 add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
3009 dcerpc_info *di, dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index,
3010 dcerpc_callback_fnct_t *callback, void *callback_args)
3012 ndr_pointer_data_t *npd;
3014 /* check if this pointer is valid */
3015 if (id != 0xffffffff) {
3016 dcerpc_call_value *value;
3018 value = di->call_data;
3020 if (di->ptype == PDU_REQ) {
3021 if (!(pinfo->fd->flags.visited)) {
3022 if (id > value->max_ptr) {
3023 value->max_ptr = id;
3027 /* if we haven't seen the request bail out since we can't
3028 know whether this is the first non-NULL instance
3030 if (value->req_frame == 0) {
3031 /* XXX THROW EXCEPTION */
3034 /* We saw this one in the request frame, nothing to
3036 if (id <= value->max_ptr) {
3042 npd = (ndr_pointer_data_t *)g_malloc(sizeof(ndr_pointer_data_t));
3047 npd->hf_index = hf_index;
3048 npd->callback = callback;
3049 npd->callback_args = callback_args;
3050 ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
3051 ndr_pointer_list_pos);
3052 ndr_pointer_list_pos++;
3057 find_pointer_index(guint32 id)
3059 ndr_pointer_data_t *npd;
3062 len = g_slist_length(ndr_pointer_list);
3063 for (i=0; i<len; i++) {
3064 npd = (ndr_pointer_data_t *)g_slist_nth_data(ndr_pointer_list, i);
3066 if (npd->id == id) {
3075 /* This function dissects an NDR pointer and stores the callback for later
3076 * deferred dissection.
3078 * fnct is the callback function for when we have reached this object in
3081 * type is what type of pointer.
3083 * this is text is what text we should put in any created tree node.
3085 * hf_index is what hf value we want to pass to the callback function when
3086 * it is called, the callback can later pick this one up from di->hf_index.
3088 * callback is executed after the pointer has been dereferenced.
3090 * callback_args is passed as an argument to the callback function
3092 * See packet-dcerpc-samr.c for examples
3095 dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3096 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
3097 int type, const char *text, int hf_index,
3098 dcerpc_callback_fnct_t *callback, void *callback_args)
3100 proto_tree *tr = NULL;
3101 gint start_offset = offset;
3102 int pointer_size = 4;
3104 if (di->conformant_run) {
3105 /* this call was only for dissecting the header for any
3106 embedded conformant array. we will not parse any
3107 pointers in this mode.
3111 if (di->call_data->flags & DCERPC_IS_NDR64) {
3116 /*TOP LEVEL REFERENCE POINTER*/
3117 if ( pointers_are_top_level
3118 && (type == NDR_POINTER_REF) ) {
3121 /* we must find out a nice way to do the length here */
3122 tr = proto_tree_add_subtree(tree, tvb, offset, 0,
3123 ett_dcerpc_pointer_data, &item, text);
3125 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
3126 hf_index, callback, callback_args);
3130 /*TOP LEVEL FULL POINTER*/
3131 if ( pointers_are_top_level
3132 && (type == NDR_POINTER_PTR) ) {
3137 /* get the referent id */
3138 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
3140 /* we got a NULL pointer */
3142 proto_tree_add_bytes_format_value(tree, hf_dcerpc_null_pointer, tvb, offset-pointer_size,
3143 pointer_size, NULL, "%s", text);
3147 /* see if we have seen this pointer before
3148 The value is truncated to 32bits. 64bit values have only been
3149 seen on fuzz-tested files */
3150 idx = find_pointer_index((guint32)id);
3152 /* we have seen this pointer before */
3154 proto_tree_add_string(tree, hf_dcerpc_duplicate_ptr, tvb, offset-pointer_size, pointer_size, text);
3159 tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
3160 pointer_size, ett_dcerpc_pointer_data, &item, text);
3161 if (di->call_data->flags & DCERPC_IS_NDR64) {
3162 proto_tree_add_uint64(tr, hf_dcerpc_referent_id64, tvb,
3163 offset-pointer_size, pointer_size, id);
3165 proto_tree_add_uint(tr, hf_dcerpc_referent_id32, tvb,
3166 offset-pointer_size, pointer_size, (guint32)id);
3168 add_pointer_to_list(pinfo, tr, item, di, fnct, (guint32)id, hf_index,
3169 callback, callback_args);
3172 /*TOP LEVEL UNIQUE POINTER*/
3173 if ( pointers_are_top_level
3174 && (type == NDR_POINTER_UNIQUE) ) {
3178 /* get the referent id */
3179 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
3181 /* we got a NULL pointer */
3183 proto_tree_add_bytes_format_value(tree, hf_dcerpc_null_pointer, tvb, offset-pointer_size,
3184 pointer_size, NULL, "%s",text);
3189 tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
3191 ett_dcerpc_pointer_data, &item, text);
3192 if (di->call_data->flags & DCERPC_IS_NDR64) {
3193 proto_tree_add_uint64(tr, hf_dcerpc_referent_id64, tvb,
3194 offset-pointer_size, pointer_size, id);
3196 proto_tree_add_uint(tr, hf_dcerpc_referent_id32, tvb,
3197 offset-pointer_size, pointer_size, (guint32)id);
3199 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
3200 hf_index, callback, callback_args);
3204 /*EMBEDDED REFERENCE POINTER*/
3205 if ( (!pointers_are_top_level)
3206 && (type == NDR_POINTER_REF) ) {
3210 /* get the referent id */
3211 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
3214 tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
3216 ett_dcerpc_pointer_data,&item,text);
3217 if (di->call_data->flags & DCERPC_IS_NDR64) {
3218 proto_tree_add_uint64(tr, hf_dcerpc_referent_id64, tvb,
3219 offset-pointer_size, pointer_size, id);
3221 proto_tree_add_uint(tr, hf_dcerpc_referent_id32, tvb,
3222 offset-pointer_size, pointer_size, (guint32)id);
3224 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
3225 hf_index, callback, callback_args);
3229 /*EMBEDDED UNIQUE POINTER*/
3230 if ( (!pointers_are_top_level)
3231 && (type == NDR_POINTER_UNIQUE) ) {
3235 /* get the referent id */
3236 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
3238 /* we got a NULL pointer */
3240 proto_tree_add_bytes_format_value(tree, hf_dcerpc_null_pointer, tvb, offset-pointer_size,
3241 pointer_size, NULL, "%s",text);
3246 tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
3248 ett_dcerpc_pointer_data,&item,text);
3249 if (di->call_data->flags & DCERPC_IS_NDR64) {
3250 proto_tree_add_uint64(tr, hf_dcerpc_referent_id64, tvb,
3251 offset-pointer_size, pointer_size, id);
3253 proto_tree_add_uint(tr, hf_dcerpc_referent_id32, tvb,
3254 offset-pointer_size, pointer_size, (guint32)id);
3256 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
3257 hf_index, callback, callback_args);
3261 /*EMBEDDED FULL POINTER*/
3262 if ( (!pointers_are_top_level)
3263 && (type == NDR_POINTER_PTR) ) {
3268 /* get the referent id */
3269 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
3271 /* we got a NULL pointer */
3273 proto_tree_add_bytes_format_value(tree, hf_dcerpc_null_pointer, tvb, offset-pointer_size,
3274 pointer_size, NULL, "%s",text);
3278 /* see if we have seen this pointer before
3279 The value is truncated to 32bits. 64bit values have only been
3280 seen on fuzztested files */
3281 idx = find_pointer_index((guint32)id);
3283 /* we have seen this pointer before */
3285 proto_tree_add_string(tree, hf_dcerpc_duplicate_ptr, tvb, offset-pointer_size, pointer_size, text);
3290 tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
3292 ett_dcerpc_pointer_data, &item, text);
3293 if (di->call_data->flags & DCERPC_IS_NDR64) {
3294 proto_tree_add_uint64(tr, hf_dcerpc_referent_id64, tvb,
3295 offset-pointer_size, pointer_size, id);
3297 proto_tree_add_uint(tr, hf_dcerpc_referent_id32, tvb,
3298 offset-pointer_size, pointer_size, (guint32)id);
3300 add_pointer_to_list(pinfo, tr, item, di, fnct, (guint32)id, hf_index,
3301 callback, callback_args);
3307 /* After each top level pointer we have dissected we have to
3308 dissect all deferrals before we move on to the next top level
3310 if (pointers_are_top_level == TRUE) {
3311 pointers_are_top_level = FALSE;
3312 offset = dissect_deferred_pointers(pinfo, tvb, offset, di, drep);
3313 pointers_are_top_level = TRUE;
3316 /* Set the length for the new subtree */
3318 proto_item_set_len(tr, offset-start_offset);
3324 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3325 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
3326 int type, const char *text, int hf_index)
3328 return dissect_ndr_pointer_cb(
3329 tvb, offset, pinfo, tree, di, drep, fnct, type, text, hf_index,
3333 dissect_ndr_toplevel_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3334 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
3335 int type, const char *text, int hf_index)
3339 pointers_are_top_level = TRUE;
3340 ret = dissect_ndr_pointer_cb(
3341 tvb, offset, pinfo, tree, di, drep, fnct, type, text, hf_index,
3346 dissect_ndr_embedded_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3347 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
3348 int type, const char *text, int hf_index)
3352 pointers_are_top_level = FALSE;
3353 ret = dissect_ndr_pointer_cb(
3354 tvb, offset, pinfo, tree, di, drep, fnct, type, text, hf_index,
3360 dissect_sec_vt_bitmask(proto_tree *tree, tvbuff_t *tvb)
3362 proto_tree_add_bitmask(tree, tvb, 0,
3363 hf_dcerpc_sec_vt_bitmask,
3364 ett_dcerpc_sec_vt_bitmask,
3365 sec_vt_bitmask_fields,
3370 dissect_sec_vt_pcontext(proto_tree *tree, tvbuff_t *tvb)
3373 proto_item *ti = NULL;
3374 proto_tree *tr = proto_tree_add_subtree(tree, tvb, offset, -1,
3375 ett_dcerpc_sec_vt_pcontext,
3378 const char *uuid_name;
3380 tvb_get_letohguid(tvb, offset, &uuid);
3381 uuid_name = guids_get_uuid_name(&uuid);
3383 uuid_name = guid_to_str(wmem_packet_scope(), &uuid);
3386 proto_tree_add_guid_format(tr, hf_dcerpc_sec_vt_pcontext_uuid, tvb,
3387 offset, 16, &uuid, "Abstract Syntax: %s", uuid_name);
3390 proto_tree_add_item(tr, hf_dcerpc_sec_vt_pcontext_ver,
3391 tvb, offset, 4, ENC_LITTLE_ENDIAN);
3394 tvb_get_letohguid(tvb, offset, &uuid);
3395 uuid_name = guids_get_uuid_name(&uuid);
3397 uuid_name = guid_to_str(wmem_packet_scope(), &uuid);
3400 proto_tree_add_guid_format(tr, hf_dcerpc_sec_vt_pcontext_uuid, tvb,
3401 offset, 16, &uuid, "Transfer Syntax: %s", uuid_name);
3404 proto_tree_add_item(tr, hf_dcerpc_sec_vt_pcontext_ver,
3405 tvb, offset, 4, ENC_LITTLE_ENDIAN);
3408 proto_item_set_len(ti, offset);
3412 dissect_sec_vt_header(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb)
3415 proto_item *ti = NULL;
3416 proto_tree *tr = proto_tree_add_subtree(tree, tvb, offset, -1,
3417 ett_dcerpc_sec_vt_header,
3420 guint8 ptype = tvb_get_guint8(tvb, offset);
3422 proto_tree_add_uint(tr, hf_dcerpc_packet_type, tvb, offset, 1, ptype);
3425 proto_tree_add_item(tr, hf_dcerpc_reserved, tvb, offset, 1, ENC_NA);
3428 proto_tree_add_item(tr, hf_dcerpc_reserved, tvb, offset, 2, ENC_NA);
3431 tvb_memcpy(tvb, drep, offset, 4);
3432 proto_tree_add_dcerpc_drep(tr, tvb, offset, drep, 4);
3435 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tr, drep,
3436 hf_dcerpc_cn_call_id, NULL);
3438 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tr, drep,
3439 hf_dcerpc_cn_ctx_id, NULL);
3441 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tr, drep,
3442 hf_dcerpc_opnum, NULL);
3444 proto_item_set_len(ti, offset);
3448 dissect_verification_trailer_impl(packet_info *pinfo, tvbuff_t *tvb, int stub_offset,
3449 proto_tree *parent_tree, int *signature_offset)
3451 int remaining = tvb_captured_length_remaining(tvb, stub_offset);
3453 gint signature_start;
3454 gint payload_length;
3456 SEC_VT_COMMAND_BITMASK_1 = 0x0001,
3457 SEC_VT_COMMAND_PCONTEXT = 0x0002,
3458 SEC_VT_COMMAND_HEADER2 = 0x0003,
3459 SEC_VT_COMMAND_END = 0x4000,
3460 SEC_VT_MUST_PROCESS_COMMAND = 0x8000,
3461 SEC_VT_COMMAND_MASK = 0x3fff,
3463 proto_item *payload_item;
3467 if (signature_offset != NULL) {
3468 *signature_offset = -1;
3471 /* We need at least signature + the header of one command */
3472 if (remaining < (int)(sizeof(TRAILER_SIGNATURE) + 4)) {
3476 /* We only scan the last 512 bytes for a possible trailer */
3477 if (remaining > 512) {
3478 offset = remaining - 512;
3483 offset += stub_offset;
3485 signature_start = tvb_find_tvb(tvb, tvb_trailer_signature, offset);
3486 if (signature_start == -1) {
3489 payload_length = signature_start - stub_offset;
3490 payload_item = proto_tree_add_item(parent_tree,
3491 hf_dcerpc_payload_stub_data,
3492 tvb, stub_offset, payload_length, ENC_NA);
3493 proto_item_append_text(payload_item, " (%d byte%s)",
3494 payload_length, plurality(payload_length, "", "s"));
3496 if (signature_offset != NULL) {
3497 *signature_offset = signature_start;
3499 remaining -= (signature_start - offset);
3500 offset = signature_start;
3502 tree = proto_tree_add_subtree(parent_tree, tvb, offset, -1,
3503 ett_dcerpc_verification_trailer,
3504 &item, "Verification Trailer");
3506 proto_tree_add_item(tree, hf_dcerpc_sec_vt_signature,
3507 tvb, offset, sizeof(TRAILER_SIGNATURE), ENC_NA);
3508 offset += (int)sizeof(TRAILER_SIGNATURE);
3509 remaining -= (int)sizeof(TRAILER_SIGNATURE);
3511 while (remaining >= 4) {
3513 guint16 len, len_missalign;
3514 gboolean cmd_end, cmd_must;
3517 tvbuff_t *cmd_tvb = NULL;
3519 cmd = (sec_vt_command)tvb_get_letohs(tvb, offset);
3520 len = tvb_get_letohs(tvb, offset + 2);
3521 cmd_end = cmd & SEC_VT_COMMAND_END;
3522 cmd_must = cmd & SEC_VT_MUST_PROCESS_COMMAND;
3523 cmd = (sec_vt_command)(cmd & SEC_VT_COMMAND_MASK);
3525 tr = proto_tree_add_subtree_format(tree, tvb, offset, 4 + len,
3526 ett_dcerpc_sec_vt_pcontext,
3528 val_to_str(cmd, sec_vt_command_cmd_vals,
3529 "Unknown (0x%04x)"));
3532 proto_item_append_text(ti, "!!!");
3535 proto_item_append_text(ti, ", END");
3538 proto_tree_add_bitmask(tr, tvb, offset,
3539 hf_dcerpc_sec_vt_command,
3540 ett_dcerpc_sec_vt_command,
3541 sec_vt_command_fields,
3545 proto_tree_add_item(tr, hf_dcerpc_sec_vt_command_length, tvb,
3546 offset, 2, ENC_LITTLE_ENDIAN);
3549 cmd_tvb = tvb_new_subset_length(tvb, offset, len);
3551 case SEC_VT_COMMAND_BITMASK_1:
3552 dissect_sec_vt_bitmask(tr, cmd_tvb);
3554 case SEC_VT_COMMAND_PCONTEXT:
3555 dissect_sec_vt_pcontext(tr, cmd_tvb);
3557 case SEC_VT_COMMAND_HEADER2:
3558 dissect_sec_vt_header(pinfo, tr, cmd_tvb);
3561 proto_tree_add_item(tr, hf_dcerpc_unknown, cmd_tvb, 0, len, ENC_NA);
3566 remaining -= (4 + len);
3568 len_missalign = len & 1;
3570 if (len_missalign) {
3571 int l = 2-len_missalign;
3572 proto_tree_add_item(tr, hf_dcerpc_missalign, tvb, offset, l, ENC_NA);
3582 proto_item_set_end(item, tvb, offset);
3587 dissect_verification_trailer(packet_info *pinfo, tvbuff_t *tvb, int stub_offset,
3588 proto_tree *parent_tree, int *signature_offset)
3590 volatile int ret = -1;
3593 * Even if we found a signature we can't be sure to have a
3594 * valid verification trailer, we're only relatively sure
3595 * if we manage to dissect it completely, otherwise it
3596 * may be part of the real payload. That's why we have
3597 * a try/catch block here.
3599 ret = dissect_verification_trailer_impl(pinfo, tvb, stub_offset, parent_tree, signature_offset);
3600 } CATCH_NONFATAL_ERRORS {
3606 dcerpc_try_handoff(packet_info *pinfo, proto_tree *tree,
3607 proto_tree *dcerpc_tree,
3608 tvbuff_t *volatile tvb, gboolean decrypted,
3609 guint8 *drep, dcerpc_info *info,
3610 dcerpc_auth_info *auth_info)
3612 volatile gint offset = 0;
3614 dcerpc_dissector_data_t dissector_data;
3615 proto_item *hidden_item;
3617 /* GUID and UUID are same size, but compiler complains about structure "name" differences */
3618 memcpy(&key.guid, &info->call_data->uuid, sizeof(key.guid));
3619 key.ver = info->call_data->ver;
3621 dissector_data.sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key);
3622 dissector_data.info = info;
3623 dissector_data.decrypted = decrypted;
3624 dissector_data.auth_info = auth_info;
3625 dissector_data.drep = drep;
3626 dissector_data.dcerpc_tree = dcerpc_tree;
3628 /* Check the dissector table before the hash table. Hopefully the hash table entries can
3629 all be converted to use dissector table */
3630 if ((dissector_data.sub_proto == NULL) ||
3631 (!dissector_try_guid_new(uuid_dissector_table, &key, tvb, pinfo, tree, FALSE, &dissector_data))) {
3633 * We don't have a dissector for this UUID, or the protocol
3634 * for that UUID is disabled.
3637 hidden_item = proto_tree_add_boolean(dcerpc_tree, hf_dcerpc_unknown_if_id,
3638 tvb, offset, 0, TRUE);
3639 PROTO_ITEM_SET_HIDDEN(hidden_item);
3640 col_append_fstr(pinfo->cinfo, COL_INFO, " %s V%u",
3641 guids_resolve_guid_to_str(&info->call_data->uuid), info->call_data->ver);
3643 show_stub_data(pinfo, tvb, 0, dcerpc_tree, auth_info, !decrypted);
3647 tap_queue_packet(dcerpc_tap, pinfo, info);
3652 dissect_dcerpc_verifier(tvbuff_t *tvb, packet_info *pinfo,
3653 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
3654 dcerpc_auth_info *auth_info)
3658 auth_info->auth_data = NULL;
3660 if (auth_info->auth_size != 0) {
3661 dcerpc_auth_subdissector_fns *auth_fns;
3664 auth_offset = hdr->frag_len - hdr->auth_len;
3666 auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
3669 auth_info->auth_data = auth_tvb;
3671 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
3672 auth_info->auth_type))) {
3674 * Catch all bounds-error exceptions, so that even if the
3675 * verifier is bad or we don't have all of it, we still
3676 * show the stub data.
3679 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
3681 } CATCH_BOUNDS_ERRORS {
3682 show_exception(auth_tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
3685 proto_tree_add_item(dcerpc_tree, hf_dcerpc_auth_verifier, auth_tvb, 0, hdr->auth_len, ENC_NA);
3689 return hdr->auth_len;
3693 dissect_dcerpc_cn_auth(tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
3694 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
3695 gboolean are_credentials, dcerpc_auth_info *auth_info)
3697 volatile int offset;
3700 * Initially set auth_level and auth_type to zero to indicate that we
3701 * haven't yet seen any authentication level information.
3703 auth_info->auth_level = 0;
3704 auth_info->auth_type = 0;
3705 auth_info->auth_size = 0;
3706 auth_info->auth_pad_len = 0;
3709 * The authentication information is at the *end* of the PDU; in
3710 * request and response PDUs, the request and response stub data
3713 * Is there any authentication data (i.e., is the authentication length
3714 * non-zero), and is the authentication length valid (i.e., is it, plus
3715 * 8 bytes for the type/level/pad length/reserved/context id, less than
3716 * or equal to the fragment length minus the starting offset of the
3721 && ((hdr->auth_len + 8) <= (hdr->frag_len - stub_offset))) {
3724 * Yes, there is authentication data, and the length is valid.
3725 * Do we have all the bytes of stub data?
3726 * (If not, we'd throw an exception dissecting *that*, so don't
3727 * bother trying to dissect the authentication information and
3728 * throwing another exception there.)
3730 offset = hdr->frag_len - (hdr->auth_len + 8);
3731 if (offset == 0 || tvb_offset_exists(tvb, offset - 1)) {
3733 * Either there's no stub data, or the last byte of the stub
3734 * data is present in the captured data, so we shouldn't
3735 * get a BoundsError dissecting the stub data.
3737 * Try dissecting the authentication data.
3738 * Catch all exceptions, so that even if the auth info is bad
3739 * or we don't have all of it, we still show the stuff we
3740 * dissect after this, such as stub data.
3743 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3744 hf_dcerpc_auth_type,
3745 &auth_info->auth_type);
3746 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3747 hf_dcerpc_auth_level,
3748 &auth_info->auth_level);
3750 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3751 hf_dcerpc_auth_pad_len,
3752 &auth_info->auth_pad_len);
3753 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3754 hf_dcerpc_auth_rsrvd, NULL);
3755 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3756 hf_dcerpc_auth_ctx_id, NULL);
3759 * Dissect the authentication data.
3761 if (are_credentials) {
3763 dcerpc_auth_subdissector_fns *auth_fns;
3765 auth_tvb = tvb_new_subset(tvb, offset,
3766 MIN(hdr->auth_len,tvb_reported_length_remaining(tvb, offset)),
3769 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
3770 auth_info->auth_type)))
3771 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
3774 proto_tree_add_item(dcerpc_tree, hf_dcerpc_auth_credentials, tvb, offset, hdr->auth_len, ENC_NA);
3777 /* Compute the size of the auth block. Note that this should not
3778 include auth padding, since when NTLMSSP encryption is used, the
3779 padding is actually inside the encrypted stub */
3780 auth_info->auth_size = hdr->auth_len + 8;
3781 } CATCH_BOUNDS_ERRORS {
3782 show_exception(tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
3789 /* We need to hash in the SMB fid number to generate a unique hash table
3790 * key as DCERPC over SMB allows several pipes over the same TCP/IP
3792 * We pass this function the transport type here to make sure we only look
3793 * at this function if it came across an SMB pipe.
3794 * Other transports might need to mix in their own extra multiplexing data
3795 * as well in the future.
3799 dcerpc_get_transport_salt(packet_info *pinfo)
3801 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
3803 switch (decode_data->dcetransporttype) {
3804 case DCE_CN_TRANSPORT_SMBPIPE:
3805 /* DCERPC over smb */
3806 return decode_data->dcetransportsalt;
3809 /* Some other transport... */
3814 dcerpc_set_transport_salt(guint64 dcetransportsalt, packet_info *pinfo)
3816 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
3818 decode_data->dcetransportsalt = dcetransportsalt;
3822 * Connection oriented packet types
3826 dissect_dcerpc_cn_bind(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3827 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
3829 conversation_t *conv = find_or_create_conversation(pinfo);
3830 guint8 num_ctx_items = 0;
3833 guint8 num_trans_items;
3838 guint16 if_ver, if_ver_minor;
3839 dcerpc_auth_info auth_info;
3841 const char *uuid_name = NULL;
3842 proto_item *iface_item = NULL;
3843 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
3845 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3846 hf_dcerpc_cn_max_xmit, NULL);
3848 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3849 hf_dcerpc_cn_max_recv, NULL);
3851 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3852 hf_dcerpc_cn_assoc_group, NULL);
3854 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3855 hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
3860 col_append_fstr(pinfo->cinfo, COL_INFO, ", %u context items:", num_ctx_items);
3862 for (i = 0; i < num_ctx_items; i++) {
3863 proto_item *ctx_item = NULL;
3864 proto_tree *ctx_tree = NULL, *iface_tree = NULL;
3865 gint ctx_offset = offset;
3867 dissect_dcerpc_uint16(tvb, offset, pinfo, NULL, hdr->drep,
3868 hf_dcerpc_cn_ctx_id, &ctx_id);
3870 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3871 /* (if we have multiple contexts, this might cause "decode as"
3872 * to behave unpredictably) */
3873 decode_data->dcectxid = ctx_id;
3876 ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_item,
3879 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
3882 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree, hdr->drep,
3883 hf_dcerpc_cn_ctx_id, &ctx_id);
3884 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, ctx_tree, hdr->drep,
3885 hf_dcerpc_cn_num_trans_items, &num_trans_items);
3888 proto_item_append_text(ctx_item, "[%u]: Context ID:%u", i+1, ctx_id);
3894 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &if_id);
3897 iface_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_abstract_syntax, tvb, offset, 0, ENC_NA);
3898 iface_tree = proto_item_add_subtree(iface_item, ett_dcerpc_cn_iface);
3900 uuid_str = guid_to_str(wmem_packet_scope(), (e_guid_t*)&if_id);
3901 uuid_name = guids_get_uuid_name(&if_id);
3903 proto_tree_add_guid_format(iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
3904 offset, 16, (e_guid_t *) &if_id, "Interface: %s UUID: %s", uuid_name, uuid_str);
3905 proto_item_append_text(iface_item, ": %s", uuid_name);
3906 proto_item_append_text(ctx_item, ", %s", uuid_name);
3908 proto_tree_add_guid_format(iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
3909 offset, 16, (e_guid_t *) &if_id, "Interface UUID: %s", uuid_str);
3910 proto_item_append_text(iface_item, ": %s", uuid_str);
3911 proto_item_append_text(ctx_item, ", %s", uuid_str);
3916 if (hdr->drep[0] & DREP_LITTLE_ENDIAN) {
3917 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
3918 hf_dcerpc_cn_bind_if_ver, &if_ver);
3919 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
3920 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
3922 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
3923 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
3924 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
3925 hf_dcerpc_cn_bind_if_ver, &if_ver);
3929 proto_item_append_text(iface_item, " V%u.%u", if_ver, if_ver_minor);
3930 proto_item_set_len(iface_item, 20);
3933 memset(&trans_id, 0, sizeof(trans_id));
3934 for (j = 0; j < num_trans_items; j++) {
3935 proto_tree *trans_tree = NULL;
3936 proto_item *trans_item = NULL;
3938 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &trans_id);
3941 trans_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_trans_syntax, tvb, offset, 0, ENC_NA);
3942 trans_tree = proto_item_add_subtree(trans_item, ett_dcerpc_cn_trans_syntax);
3944 uuid_str = guid_to_str(wmem_packet_scope(), (e_guid_t *) &trans_id);
3945 uuid_name = guids_get_uuid_name(&trans_id);
3947 /* check for [MS-RPCE] 3.3.1.5.3 Bind Time Feature Negotiation */
3948 if (trans_id.data1 == 0x6cb71c2c && trans_id.data2 == 0x9812 && trans_id.data3 == 0x4540) {
3949 proto_tree_add_guid_format(trans_tree, hf_dcerpc_cn_bind_trans_id,
3950 tvb, offset, 16, (e_guid_t *) &trans_id,
3951 "Transfer Syntax: Bind Time Feature Negotiation UUID:%s",
3953 proto_tree_add_bitmask(trans_tree, tvb, offset + 8,
3954 hf_dcerpc_cn_bind_trans_btfn,
3955 ett_dcerpc_cn_bind_trans_btfn,
3956 dcerpc_cn_bind_trans_btfn_fields,
3958 proto_item_append_text(trans_item, "[%u]: Bind Time Feature Negotiation", j+1);
3959 proto_item_append_text(ctx_item, ", Bind Time Feature Negotiation");
3960 } else if (uuid_name) {
3961 proto_tree_add_guid_format(trans_tree, hf_dcerpc_cn_bind_trans_id,
3962 tvb, offset, 16, (e_guid_t *) &trans_id,
3963 "Transfer Syntax: %s UUID:%s", uuid_name, uuid_str);
3964 proto_item_append_text(trans_item, "[%u]: %s", j+1, uuid_name);
3965 proto_item_append_text(ctx_item, ", %s", uuid_name);
3967 proto_tree_add_guid_format(trans_tree, hf_dcerpc_cn_bind_trans_id,
3968 tvb, offset, 16, (e_guid_t *) &trans_id,
3969 "Transfer Syntax: %s", uuid_str);
3970 proto_item_append_text(trans_item, "[%u]: %s", j+1, uuid_str);
3971 proto_item_append_text(ctx_item, ", %s", uuid_str);
3977 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, trans_tree, hdr->drep,
3978 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
3980 proto_item_set_len(trans_item, 20);
3981 proto_item_append_text(trans_item, " V%u", trans_ver);
3985 /* if this is the first time we've seen this packet, we need to
3986 update the dcerpc_binds table so that any later calls can
3987 match to the interface.
3988 XXX We assume that BINDs will NEVER be fragmented.
3990 if (!(pinfo->fd->flags.visited)) {
3991 dcerpc_bind_key *key;
3992 dcerpc_bind_value *value;
3994 key = (dcerpc_bind_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_key));
3996 key->ctx_id = ctx_id;
3997 key->transport_salt = dcerpc_get_transport_salt(pinfo);
3999 value = (dcerpc_bind_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_value));
4000 value->uuid = if_id;
4001 value->ver = if_ver;
4002 value->transport = trans_id;
4004 /* add this entry to the bind table */
4005 g_hash_table_insert(dcerpc_binds, key, value);
4009 col_append_fstr(pinfo->cinfo, COL_INFO, ",");
4010 col_append_fstr(pinfo->cinfo, COL_INFO, " %s V%u.%u (%s)",
4011 guids_resolve_guid_to_str(&if_id), if_ver, if_ver_minor,
4012 guids_resolve_guid_to_str(&trans_id));
4015 proto_item_set_len(ctx_item, offset - ctx_offset);
4020 * XXX - we should save the authentication type *if* we have
4021 * an authentication header, and associate it with an authentication
4022 * context, so subsequent PDUs can use that context.
4024 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
4028 dissect_dcerpc_cn_bind_ack(tvbuff_t *tvb, gint offset, packet_info *pinfo,
4029 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
4031 guint16 max_xmit, max_recv;
4032 guint16 sec_addr_len;
4039 dcerpc_auth_info auth_info;
4040 const char *uuid_name = NULL;
4041 const char *result_str = NULL;
4043 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4044 hf_dcerpc_cn_max_xmit, &max_xmit);
4046 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4047 hf_dcerpc_cn_max_recv, &max_recv);
4049 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4050 hf_dcerpc_cn_assoc_group, NULL);
4052 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4053 hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
4054 if (sec_addr_len != 0) {
4055 proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
4056 sec_addr_len, ENC_ASCII|ENC_NA);
4057 offset += sec_addr_len;
4061 offset += 4 - offset % 4;
4064 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4065 hf_dcerpc_cn_num_results, &num_results);
4070 col_append_fstr(pinfo->cinfo, COL_INFO, ", max_xmit: %u max_recv: %u, %u results:",
4071 max_xmit, max_recv, num_results);
4073 for (i = 0; i < num_results; i++) {
4074 proto_tree *ctx_tree = NULL;
4075 proto_item *ctx_item = NULL;
4078 ctx_tree = proto_tree_add_subtree_format(dcerpc_tree, tvb, offset, 24, ett_dcerpc_cn_ctx, &ctx_item, "Ctx Item[%u]:", i+1);
4081 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree,
4082 hdr->drep, hf_dcerpc_cn_ack_result,
4085 /* [MS-RPCE] 3.3.1.5.3 check if this Ctx Item is the response to a Bind Time Feature Negotiation request */
4087 proto_tree_add_bitmask(ctx_tree, tvb, offset,
4088 hf_dcerpc_cn_bind_trans_btfn,
4089 ett_dcerpc_cn_bind_trans_btfn,
4090 dcerpc_cn_bind_trans_btfn_fields,
4093 } else if (result != 0) {
4094 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree,
4095 hdr->drep, hf_dcerpc_cn_ack_reason,
4099 * The reason for rejection isn't meaningful, and often isn't
4100 * set, when the syntax was accepted.
4105 result_str = val_to_str(result, p_cont_result_vals, "Unknown result (%u)");
4108 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &trans_id);
4109 uuid_name = guids_get_uuid_name(&trans_id);
4111 uuid_name = guid_to_str(wmem_packet_scope(), (e_guid_t *) &trans_id);
4113 proto_tree_add_guid_format(ctx_tree, hf_dcerpc_cn_ack_trans_id, tvb,
4114 offset, 16, (e_guid_t *) &trans_id, "Transfer Syntax: %s",
4116 proto_item_append_text(ctx_item, " %s, %s", result_str, uuid_name);
4120 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, ctx_tree, hdr->drep,
4121 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
4124 col_append_fstr(pinfo->cinfo, COL_INFO, ",");
4125 col_append_fstr(pinfo->cinfo, COL_INFO, " %s", result_str);
4129 * XXX - do we need to do anything with the authentication level
4130 * we get back from this?
4132 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
4136 dissect_dcerpc_cn_bind_nak(tvbuff_t *tvb, gint offset, packet_info *pinfo,
4137 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
4140 guint8 num_protocols;
4143 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
4144 hdr->drep, hf_dcerpc_cn_reject_reason,
4147 col_append_fstr(pinfo->cinfo, COL_INFO, " reason: %s",
4148 val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
4150 if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
4151 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4152 hf_dcerpc_cn_num_protocols,
4155 for (i = 0; i < num_protocols; i++) {
4156 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
4157 hdr->drep, hf_dcerpc_cn_protocol_ver_major,
4159 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
4160 hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
4166 /* Return a string describing a DCE/RPC fragment as first, middle, or end
4169 #define PFC_FRAG_MASK 0x03
4172 fragment_type(guint8 flags)
4174 static const char* t[4] = {
4180 return t[flags & PFC_FRAG_MASK];
4183 /* Dissect stub data (payload) of a DCERPC packet. */
4186 dissect_dcerpc_cn_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
4187 proto_tree *dcerpc_tree, proto_tree *tree,
4188 e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
4189 dcerpc_auth_info *auth_info, guint32 alloc_hint _U_,
4192 gint length, reported_length;
4193 gboolean save_fragmented;
4194 fragment_head *fd_head = NULL;
4196 tvbuff_t *auth_tvb, *payload_tvb, *decrypted_tvb = NULL;
4198 proto_item *parent_pi;
4199 proto_item *dcerpc_tree_item;
4201 save_fragmented = pinfo->fragmented;
4203 length = tvb_reported_length_remaining(tvb, offset);
4204 reported_length = tvb_reported_length_remaining(tvb, offset);
4205 if (reported_length < 0 ||
4206 (guint32)reported_length < auth_info->auth_size) {
4207 /* We don't even have enough bytes for the authentication
4211 reported_length -= auth_info->auth_size;
4212 if (length > reported_length)
4213 length = reported_length;
4214 payload_tvb = tvb_new_subset(tvb, offset, length, reported_length);
4217 /*don't bother if we don't have the entire tvb */
4218 /*XXX we should really make sure we calculate auth_info->auth_data
4219 and use that one instead of this auth_tvb hack
4221 if (tvb_captured_length(tvb) == tvb_reported_length(tvb)) {
4222 if (tvb_reported_length_remaining(tvb, offset+length) > 8) {
4223 auth_tvb = tvb_new_subset_remaining(tvb, offset+length+8);
4227 /* Decrypt the PDU if it is encrypted */
4229 if (auth_info->auth_type &&
4230 (auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)) {
4232 * We know the authentication type, and the authentication
4233 * level is "Packet privacy", meaning the payload is
4234 * encrypted; attempt to decrypt it.
4236 dcerpc_auth_subdissector_fns *auth_fns;
4238 /* Start out assuming we won't succeed in decrypting. */
4240 /* Schannel needs information into the footer (verifier) in order to setup decryption keys
4241 * so we call it in order to have a chance to decipher the data
4243 if (DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN == auth_info->auth_type) {
4244 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, auth_info);
4247 if ((auth_fns = get_auth_subdissector_fns(
4248 auth_info->auth_level, auth_info->auth_type))) {
4251 result = decode_encrypted_data(
4252 payload_tvb, auth_tvb, pinfo, auth_fns,
4253 hdr->ptype == PDU_REQ, auth_info);
4256 proto_tree_add_item(dcerpc_tree, hf_dcerpc_encrypted_stub_data, payload_tvb, 0, -1, ENC_NA);
4258 add_new_data_source(
4259 pinfo, result, "Decrypted stub data");
4262 decrypted_tvb = result;
4266 decrypted_tvb = payload_tvb;
4268 /* if this packet is not fragmented, just dissect it and exit */
4269 if (PFC_NOT_FRAGMENTED(hdr)) {
4270 pinfo->fragmented = FALSE;
4272 dcerpc_try_handoff(pinfo, tree, dcerpc_tree,
4273 ((decrypted_tvb != NULL) ? decrypted_tvb : payload_tvb),
4274 ((decrypted_tvb != NULL) ? TRUE : FALSE),
4275 hdr->drep, di, auth_info);
4277 pinfo->fragmented = save_fragmented;
4281 /* The packet is fragmented. */
4282 pinfo->fragmented = TRUE;
4284 /* debug output of essential fragment data. */
4285 /* leave it here for future debugging sessions */
4286 /*printf("DCE num:%u offset:%u frag_len:%u tvb_len:%u\n",
4287 pinfo->num, offset, hdr->frag_len, tvb_reported_length(decrypted_tvb));*/
4289 /* if we are not doing reassembly and this is the first fragment
4290 then just dissect it and exit
4291 XXX - if we're not doing reassembly, can we decrypt an
4294 if ( (!dcerpc_reassemble) && (hdr->flags & PFC_FIRST_FRAG) ) {
4296 dcerpc_try_handoff(pinfo, tree, dcerpc_tree,
4297 ((decrypted_tvb != NULL) ? decrypted_tvb : payload_tvb),
4298 ((decrypted_tvb != NULL) ? TRUE : FALSE),
4299 hdr->drep, di, auth_info);
4301 expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment, "%s fragment", fragment_type(hdr->flags));
4303 pinfo->fragmented = save_fragmented;
4307 /* if we have already seen this packet, see if it was reassembled
4308 and if so dissect the full pdu.
4311 if (pinfo->fd->flags.visited) {
4312 fd_head = fragment_get_reassembled(&dcerpc_co_reassembly_table, frame);
4316 /* if we are not doing reassembly and it was neither a complete PDU
4317 nor the first fragment then there is nothing more we can do
4318 so we just have to exit
4320 if ( !dcerpc_reassemble || (tvb_captured_length(tvb) != tvb_reported_length(tvb)) )
4323 /* if we didn't get 'frame' we don't know where the PDU started and thus
4324 it is pointless to continue
4329 /* from now on we must attempt to reassemble the PDU
4332 /* if we get here we know it is the first time we see the packet
4333 and we also know it is only a fragment and not a full PDU,
4334 thus we must reassemble it.
4337 /* Do we have any non-encrypted data to reassemble? */
4338 if (decrypted_tvb == NULL) {
4339 /* No. We can't even try to reassemble. */
4343 /* defragmentation is a bit tricky, as there's no offset of the fragment
4344 * in the protocol data.
4346 * just use fragment_add_seq_next() and hope that TCP/SMB segments coming
4347 * in with the correct sequence.
4349 fd_head = fragment_add_seq_next(&dcerpc_co_reassembly_table,
4350 decrypted_tvb, 0, pinfo, frame, NULL,
4351 tvb_reported_length(decrypted_tvb),
4352 hdr->flags&PFC_LAST_FRAG ? FALSE : TRUE /* more_frags */);
4356 /* if reassembly is complete and this is the last fragment
4357 * (multiple fragments in one PDU are possible!)
4358 * dissect the full PDU
4360 if (fd_head && (fd_head->flags & FD_DEFRAGMENTED) ) {
4362 if ((pinfo->num == fd_head->reassembled_in) && (hdr->flags & PFC_LAST_FRAG) ) {
4364 proto_item *frag_tree_item;
4366 next_tvb = tvb_new_chain((decrypted_tvb)?decrypted_tvb:payload_tvb,
4369 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
4370 show_fragment_tree(fd_head, &dcerpc_frag_items,
4371 tree, pinfo, next_tvb, &frag_tree_item);
4372 /* the toplevel fragment subtree is now behind all desegmented data,
4373 * move it right behind the DCE/RPC tree */
4374 dcerpc_tree_item = proto_tree_get_parent(dcerpc_tree);
4375 if (frag_tree_item && dcerpc_tree_item) {
4376 proto_tree_move_item(tree, dcerpc_tree_item, frag_tree_item);
4379 pinfo->fragmented = FALSE;
4381 expert_add_info_format(pinfo, frag_tree_item, &ei_dcerpc_fragment_reassembled, "%s fragment, reassembled", fragment_type(hdr->flags));
4383 dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb, TRUE, hdr->drep, di, auth_info);
4386 if (decrypted_tvb) {
4387 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
4388 decrypted_tvb, 0, 0, fd_head->reassembled_in);
4390 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
4391 payload_tvb, 0, 0, fd_head->reassembled_in);
4393 PROTO_ITEM_SET_GENERATED(pi);
4394 parent_pi = proto_tree_get_parent(dcerpc_tree);
4395 if (parent_pi != NULL) {
4396 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
4398 col_append_fstr(pinfo->cinfo, COL_INFO,
4399 " [DCE/RPC %s fragment, reas: #%u]", fragment_type(hdr->flags), fd_head->reassembled_in);
4400 expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment_reassembled, "%s fragment, reassembled in #%u", fragment_type(hdr->flags), fd_head->reassembled_in);
4403 /* Reassembly not complete - some fragments
4404 are missing. Just show the stub data. */
4405 expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment, "%s fragment", fragment_type(hdr->flags));
4407 if (decrypted_tvb) {
4408 show_stub_data(pinfo, decrypted_tvb, 0, tree, auth_info, FALSE);
4410 show_stub_data(pinfo, payload_tvb, 0, tree, auth_info, TRUE);
4414 pinfo->fragmented = save_fragmented;
4418 dissect_dcerpc_cn_rqst(tvbuff_t *tvb, gint offset, packet_info *pinfo,
4419 proto_tree *dcerpc_tree, proto_tree *tree,
4420 e_dce_cn_common_hdr_t *hdr)
4422 conversation_t *conv;
4425 e_guid_t obj_id = DCERPC_UUID_NULL;
4426 dcerpc_auth_info auth_info;
4429 proto_item *parent_pi;
4430 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
4432 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4433 hf_dcerpc_cn_alloc_hint, &alloc_hint);
4435 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4436 hf_dcerpc_cn_ctx_id, &ctx_id);
4437 parent_pi = proto_tree_get_parent(dcerpc_tree);
4438 if (parent_pi != NULL) {
4439 proto_item_append_text(parent_pi, ", Ctx: %u", ctx_id);
4442 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4443 hf_dcerpc_opnum, &opnum);
4445 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
4446 decode_data->dcectxid = ctx_id;
4448 col_append_fstr(pinfo->cinfo, COL_INFO, ", opnum: %u, Ctx: %u",
4451 if (hdr->flags & PFC_OBJECT_UUID) {
4452 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &obj_id);
4454 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
4455 offset, 16, (e_guid_t *) &obj_id, "Object UUID: %s",
4456 guid_to_str(wmem_packet_scope(), (e_guid_t *) &obj_id));
4462 * XXX - what if this was set when the connection was set up,
4463 * and we just have a security context?
4465 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
4467 conv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
4468 pinfo->srcport, pinfo->destport, 0);
4470 show_stub_data(pinfo, tvb, offset, dcerpc_tree, &auth_info, TRUE);
4472 dcerpc_matched_key matched_key, *new_matched_key;
4473 dcerpc_call_value *value;
4475 /* !!! we can NOT check flags.visited here since this will interact
4476 badly with when SMB handles (i.e. calls the subdissector)
4477 and desegmented pdu's .
4478 Instead we check if this pdu is already in the matched table or not
4480 matched_key.frame = pinfo->num;
4481 matched_key.call_id = hdr->call_id;
4482 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
4484 dcerpc_bind_key bind_key;
4485 dcerpc_bind_value *bind_value;
4487 bind_key.conv = conv;
4488 bind_key.ctx_id = ctx_id;
4489 bind_key.transport_salt = dcerpc_get_transport_salt(pinfo);
4491 if ((bind_value = (dcerpc_bind_value *)g_hash_table_lookup(dcerpc_binds, &bind_key)) ) {
4492 if (!(hdr->flags&PFC_FIRST_FRAG)) {
4493 dcerpc_cn_call_key call_key;
4494 dcerpc_call_value *call_value;
4496 call_key.conv = conv;
4497 call_key.call_id = hdr->call_id;
4498 call_key.transport_salt = dcerpc_get_transport_salt(pinfo);
4499 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_cn_calls, &call_key))) {
4500 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
4501 *new_matched_key = matched_key;
4502 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
4506 dcerpc_cn_call_key *call_key;
4507 dcerpc_call_value *call_value;
4509 /* We found the binding and it is the first fragment
4510 (or a complete PDU) of a dcerpc pdu so just add
4511 the call to both the call table and the
4514 call_key = (dcerpc_cn_call_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_cn_call_key));
4515 call_key->conv = conv;
4516 call_key->call_id = hdr->call_id;
4517 call_key->transport_salt = dcerpc_get_transport_salt(pinfo);
4519 /* if there is already a matching call in the table
4520 remove it so it is replaced with the new one */
4521 if (g_hash_table_lookup(dcerpc_cn_calls, call_key)) {
4522 g_hash_table_remove(dcerpc_cn_calls, call_key);
4525 call_value = (dcerpc_call_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_call_value));
4526 call_value->uuid = bind_value->uuid;
4527 call_value->ver = bind_value->ver;
4528 call_value->object_uuid = obj_id;
4529 call_value->opnum = opnum;
4530 call_value->req_frame = pinfo->num;
4531 call_value->req_time = pinfo->abs_ts;
4532 call_value->rep_frame = 0;
4533 call_value->max_ptr = 0;
4534 call_value->se_data = NULL;
4535 call_value->private_data = NULL;
4536 call_value->pol = NULL;
4537 call_value->flags = 0;
4538 if (!memcmp(&bind_value->transport, &uuid_ndr64, sizeof(uuid_ndr64))) {
4539 call_value->flags |= DCERPC_IS_NDR64;
4542 g_hash_table_insert(dcerpc_cn_calls, call_key, call_value);
4544 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
4545 *new_matched_key = matched_key;
4546 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
4555 di = wmem_new0(wmem_packet_scope(), dcerpc_info);
4556 /* handoff this call */
4557 di->dcerpc_procedure_name = "";
4559 di->call_id = hdr->call_id;
4560 di->transport_salt = dcerpc_get_transport_salt(pinfo);
4561 di->ptype = PDU_REQ;
4562 di->call_data = value;
4565 if (value->rep_frame != 0) {
4566 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
4567 tvb, 0, 0, value->rep_frame);
4568 PROTO_ITEM_SET_GENERATED(pi);
4569 if (parent_pi != NULL) {
4570 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
4574 dissect_dcerpc_cn_stub(tvb, offset, pinfo, dcerpc_tree, tree,
4575 hdr, di, &auth_info, alloc_hint,
4578 /* no bind information, simply show stub data */
4579 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);
4580 show_stub_data(pinfo, tvb, offset, dcerpc_tree, &auth_info, TRUE);
4584 /* Dissect the verifier */
4585 dissect_dcerpc_verifier(tvb, pinfo, dcerpc_tree, hdr, &auth_info);
4590 dissect_dcerpc_cn_resp(tvbuff_t *tvb, gint offset, packet_info *pinfo,
4591 proto_tree *dcerpc_tree, proto_tree *tree,
4592 e_dce_cn_common_hdr_t *hdr)
4594 dcerpc_call_value *value = NULL;
4595 conversation_t *conv;
4597 dcerpc_auth_info auth_info;
4600 proto_item *parent_pi;
4601 e_guid_t obj_id_null = DCERPC_UUID_NULL;
4602 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
4604 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4605 hf_dcerpc_cn_alloc_hint, &alloc_hint);
4607 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4608 hf_dcerpc_cn_ctx_id, &ctx_id);
4609 parent_pi = proto_tree_get_parent(dcerpc_tree);
4610 if (parent_pi != NULL) {
4611 proto_item_append_text(parent_pi, ", Ctx: %u", ctx_id);
4614 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
4615 decode_data->dcectxid = ctx_id;
4617 col_append_fstr(pinfo->cinfo, COL_INFO, ", Ctx: %u", ctx_id);
4619 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4620 hf_dcerpc_cn_cancel_count, NULL);
4625 * XXX - what if this was set when the connection was set up,
4626 * and we just have a security context?
4628 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
4630 conv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
4631 pinfo->srcport, pinfo->destport, 0);
4634 /* no point in creating one here, really */
4635 show_stub_data(pinfo, tvb, offset, dcerpc_tree, &auth_info, TRUE);
4637 dcerpc_matched_key matched_key, *new_matched_key;
4639 /* !!! we can NOT check flags.visited here since this will interact
4640 badly with when SMB handles (i.e. calls the subdissector)
4641 and desegmented pdu's .
4642 Instead we check if this pdu is already in the matched table or not
4644 matched_key.frame = pinfo->num;
4645 matched_key.call_id = hdr->call_id;
4646 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
4648 dcerpc_cn_call_key call_key;
4649 dcerpc_call_value *call_value;
4651 call_key.conv = conv;
4652 call_key.call_id = hdr->call_id;
4653 call_key.transport_salt = dcerpc_get_transport_salt(pinfo);
4655 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_cn_calls, &call_key))) {
4656 /* extra sanity check, only match them if the reply
4657 came after the request */
4658 if (call_value->req_frame<pinfo->num) {
4659 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
4660 *new_matched_key = matched_key;
4661 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
4663 if (call_value->rep_frame == 0) {
4664 call_value->rep_frame = pinfo->num;
4673 di = wmem_new0(wmem_packet_scope(), dcerpc_info);
4674 /* handoff this call */
4675 di->dcerpc_procedure_name = "";
4677 di->call_id = hdr->call_id;
4678 di->transport_salt = dcerpc_get_transport_salt(pinfo);
4679 di->ptype = PDU_RESP;
4680 di->call_data = value;
4682 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
4684 /* (optional) "Object UUID" from request */
4685 if (dcerpc_tree && (memcmp(&value->object_uuid, &obj_id_null, sizeof(obj_id_null)) != 0)) {
4686 pi = proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
4687 offset, 0, (e_guid_t *) &value->object_uuid, "Object UUID: %s",
4688 guid_to_str(wmem_packet_scope(), (e_guid_t *) &value->object_uuid));
4689 PROTO_ITEM_SET_GENERATED(pi);
4693 if (value->req_frame != 0) {
4695 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4696 tvb, 0, 0, value->req_frame);
4697 PROTO_ITEM_SET_GENERATED(pi);
4698 if (parent_pi != NULL) {
4699 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
4701 nstime_delta(&delta_ts, &pinfo->abs_ts, &value->req_time);
4702 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
4703 PROTO_ITEM_SET_GENERATED(pi);
4705 proto_tree_add_expert(dcerpc_tree, pinfo, &ei_dcerpc_no_request_found, tvb, 0, 0);
4708 dissect_dcerpc_cn_stub(tvb, offset, pinfo, dcerpc_tree, tree,
4709 hdr, di, &auth_info, alloc_hint,
4712 /* no bind information, simply show stub data */
4713 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);
4714 show_stub_data(pinfo, tvb, offset, dcerpc_tree, &auth_info, TRUE);
4718 /* Dissect the verifier */
4719 dissect_dcerpc_verifier(tvb, pinfo, dcerpc_tree, hdr, &auth_info);
4723 dissect_dcerpc_cn_fault(tvbuff_t *tvb, gint offset, packet_info *pinfo,
4724 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
4726 dcerpc_call_value *value = NULL;
4727 conversation_t *conv;
4731 dcerpc_auth_info auth_info;
4732 proto_item *pi = NULL;
4733 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
4735 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4736 hf_dcerpc_cn_alloc_hint, &alloc_hint);
4738 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4739 hf_dcerpc_cn_ctx_id, &ctx_id);
4741 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4742 hf_dcerpc_cn_cancel_count, NULL);
4747 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4748 hf_dcerpc_cn_status, &status);
4750 status = ((hdr->drep[0] & DREP_LITTLE_ENDIAN)
4751 ? tvb_get_letohl(tvb, offset)
4752 : tvb_get_ntohl(tvb, offset));
4754 pi = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_status, tvb, offset, 4, DREP_ENC_INTEGER(hdr->drep));
4757 expert_add_info_format(pinfo, pi, &ei_dcerpc_cn_status, "Fault: %s", val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
4759 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
4760 decode_data->dcectxid = ctx_id;
4762 col_append_fstr(pinfo->cinfo, COL_INFO,
4763 ", Ctx: %u, status: %s", ctx_id,
4764 val_to_str(status, reject_status_vals,
4765 "Unknown (0x%08x)"));
4771 * XXX - what if this was set when the connection was set up,
4772 * and we just have a security context?
4774 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
4776 conv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
4777 pinfo->srcport, pinfo->destport, 0);
4779 /* no point in creating one here, really */
4781 dcerpc_matched_key matched_key, *new_matched_key;
4783 /* !!! we can NOT check flags.visited here since this will interact
4784 badly with when SMB handles (i.e. calls the subdissector)
4785 and desegmented pdu's .
4786 Instead we check if this pdu is already in the matched table or not
4788 matched_key.frame = pinfo->num;
4789 matched_key.call_id = hdr->call_id;
4790 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
4792 dcerpc_cn_call_key call_key;
4793 dcerpc_call_value *call_value;
4795 call_key.conv = conv;
4796 call_key.call_id = hdr->call_id;
4797 call_key.transport_salt = dcerpc_get_transport_salt(pinfo);
4799 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_cn_calls, &call_key))) {
4800 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
4801 *new_matched_key = matched_key;
4802 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
4805 if (call_value->rep_frame == 0) {
4806 call_value->rep_frame = pinfo->num;
4813 int length, stub_length;
4815 proto_item *parent_pi;
4817 di = wmem_new0(wmem_packet_scope(), dcerpc_info);
4818 /* handoff this call */
4819 di->dcerpc_procedure_name = "";
4821 di->call_id = hdr->call_id;
4822 di->transport_salt = dcerpc_get_transport_salt(pinfo);
4823 di->ptype = PDU_FAULT;
4824 di->call_data = value;
4826 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
4827 if (value->req_frame != 0) {
4829 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4830 tvb, 0, 0, value->req_frame);
4831 PROTO_ITEM_SET_GENERATED(pi);
4832 parent_pi = proto_tree_get_parent(dcerpc_tree);
4833 if (parent_pi != NULL) {
4834 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
4836 nstime_delta(&delta_ts, &pinfo->abs_ts, &value->req_time);
4837 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
4838 PROTO_ITEM_SET_GENERATED(pi);
4840 proto_tree_add_expert(dcerpc_tree, pinfo, &ei_dcerpc_no_request_found, tvb, 0, 0);
4843 length = tvb_reported_length_remaining(tvb, offset);
4844 /* as we now create a tvb in dissect_dcerpc_cn() containing only the
4845 * stub_data, the following calculation is no longer valid:
4846 * stub_length = hdr->frag_len - offset - auth_info.auth_size;
4847 * simply use the remaining length of the tvb instead.
4848 * XXX - or better use the reported_length?!?
4850 stub_length = length;
4851 if (length > stub_length)
4852 length = stub_length;
4854 /* If we don't have reassembly enabled, or this packet contains
4855 the entire PDU, or if we don't have all the data in this
4856 fragment, just call the handoff directly if this is the
4857 first fragment or the PDU isn't fragmented. */
4858 if ( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
4859 !tvb_bytes_exist(tvb, offset, stub_length) ) {
4860 if (hdr->flags&PFC_FIRST_FRAG) {
4861 /* First fragment, possibly the only fragment */
4863 * XXX - should there be a third routine for each
4864 * function in an RPC subdissector, to handle
4865 * fault responses? The DCE RPC 1.1 spec says
4866 * three's "stub data" here, which I infer means
4867 * that it's protocol-specific and call-specific.
4869 * It should probably get passed the status code
4870 * as well, as that might be protocol-specific.
4872 if (stub_length > 0) {
4873 proto_tree_add_item(dcerpc_tree, hf_dcerpc_fault_stub_data, tvb, offset, stub_length, ENC_NA);
4876 /* PDU is fragmented and this isn't the first fragment */
4877 if (stub_length > 0) {
4878 proto_tree_add_item(dcerpc_tree, hf_dcerpc_fragment_data, tvb, offset, stub_length, ENC_NA);
4882 /* Reassembly is enabled, the PDU is fragmented, and
4883 we have all the data in the fragment; the first two
4884 of those mean we should attempt reassembly, and the
4885 third means we can attempt reassembly. */
4888 proto_tree_add_item(dcerpc_tree, hf_dcerpc_fragment_data, tvb, offset, stub_length, ENC_NA);
4891 if (hdr->flags&PFC_FIRST_FRAG) { /* FIRST fragment */
4892 if ( (!pinfo->fd->flags.visited) && value->rep_frame ) {
4893 fragment_add_seq_next(&dcerpc_co_reassembly_table,
4895 pinfo, value->rep_frame, NULL,
4899 } else if (hdr->flags&PFC_LAST_FRAG) { /* LAST fragment */
4900 if ( value->rep_frame ) {
4901 fragment_head *fd_head;
4903 fd_head = fragment_add_seq_next(&dcerpc_co_reassembly_table,
4905 pinfo, value->rep_frame, NULL,
4910 /* We completed reassembly */
4912 proto_item *frag_tree_item;
4914 next_tvb = tvb_new_chain(tvb, fd_head->tvb_data);
4915 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
4916 show_fragment_tree(fd_head, &dcerpc_frag_items,
4917 dcerpc_tree, pinfo, next_tvb, &frag_tree_item);
4920 * XXX - should there be a third routine for each
4921 * function in an RPC subdissector, to handle
4922 * fault responses? The DCE RPC 1.1 spec says
4923 * three's "stub data" here, which I infer means
4924 * that it's protocol-specific and call-specific.
4926 * It should probably get passed the status code
4927 * as well, as that might be protocol-specific.
4931 proto_tree_add_item(dcerpc_tree, hf_dcerpc_stub_data, tvb, offset, stub_length, ENC_NA);
4936 } else { /* MIDDLE fragment(s) */
4937 if ( (!pinfo->fd->flags.visited) && value->rep_frame ) {
4938 fragment_add_seq_next(&dcerpc_co_reassembly_table,
4940 pinfo, value->rep_frame, NULL,
4951 dissect_dcerpc_cn_rts(tvbuff_t *tvb, gint offset, packet_info *pinfo,
4952 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
4954 proto_item *tf = NULL;
4955 proto_item *parent_pi = NULL;
4956 proto_tree *cn_rts_pdu_tree = NULL;
4958 guint16 commands_nb = 0;
4961 const char *info_str = NULL;
4962 static const int * flags[] = {
4963 &hf_dcerpc_cn_rts_flags_none,
4964 &hf_dcerpc_cn_rts_flags_ping,
4965 &hf_dcerpc_cn_rts_flags_other_cmd,
4966 &hf_dcerpc_cn_rts_flags_recycle_channel,
4967 &hf_dcerpc_cn_rts_flags_in_channel,
4968 &hf_dcerpc_cn_rts_flags_out_channel,
4969 &hf_dcerpc_cn_rts_flags_eof,
4973 /* Dissect specific RTS header */
4974 rts_flags = dcerpc_tvb_get_ntohs(tvb, offset, hdr->drep);
4975 proto_tree_add_bitmask_value_with_flags(dcerpc_tree, tvb, offset, hf_dcerpc_cn_rts_flags,
4976 ett_dcerpc_cn_rts_flags, flags, rts_flags, BMT_NO_APPEND);
4979 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4980 hf_dcerpc_cn_rts_commands_nb, &commands_nb);
4982 /* Create the RTS PDU tree - we do not yet know its name */
4983 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);
4985 cmd = (guint32 *)wmem_alloc(wmem_packet_scope(), sizeof (guint32) * (commands_nb + 1));
4987 /* Dissect commands */
4988 for (i = 0; i < commands_nb; ++i) {
4989 proto_tree *cn_rts_command_tree = NULL;
4990 const guint32 command = dcerpc_tvb_get_ntohl(tvb, offset, hdr->drep);
4992 tf = proto_tree_add_uint(cn_rts_pdu_tree, hf_dcerpc_cn_rts_command, tvb, offset, 4, command);
4993 cn_rts_command_tree = proto_item_add_subtree(tf, ett_dcerpc_cn_rts_command);
4996 case RTS_CMD_RECEIVEWINDOWSIZE:
4997 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_receivewindowsize, NULL);
4999 case RTS_CMD_FLOWCONTROLACK:
5000 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_fack_bytesreceived, NULL);
5001 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_fack_availablewindow, NULL);
5002 offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_fack_channelcookie, NULL);
5004 case RTS_CMD_CONNECTIONTIMEOUT:
5005 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_connectiontimeout, NULL);
5007 case RTS_CMD_COOKIE:
5008 offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_cookie, NULL);
5010 case RTS_CMD_CHANNELLIFETIME:
5011 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_channellifetime, NULL);
5013 case RTS_CMD_CLIENTKEEPALIVE:
5014 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_clientkeepalive, NULL);
5016 case RTS_CMD_VERSION:
5017 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_version, NULL);
5021 case RTS_CMD_PADDING: {
5023 const guint32 conformance_count = dcerpc_tvb_get_ntohl(tvb, offset, hdr->drep);
5024 proto_tree_add_uint(cn_rts_command_tree, hf_dcerpc_cn_rts_command_conformancecount, tvb, offset, 4, conformance_count);
5026 padding = (guint8 *)tvb_memdup(wmem_packet_scope(), tvb, offset, conformance_count);
5027 proto_tree_add_bytes(cn_rts_command_tree, hf_dcerpc_cn_rts_command_padding, tvb, offset, conformance_count, padding);
5028 offset += conformance_count;
5030 case RTS_CMD_NEGATIVEANCE:
5034 case RTS_CMD_CLIENTADDRESS: {
5036 const guint32 addrtype = dcerpc_tvb_get_ntohl(tvb, offset, hdr->drep);
5037 proto_tree_add_uint(cn_rts_command_tree, hf_dcerpc_cn_rts_command_addrtype, tvb, offset, 4, addrtype);
5041 const guint32 addr4 = tvb_get_ipv4(tvb, offset);
5042 proto_tree_add_ipv4_format_value(cn_rts_command_tree, hf_dcerpc_cmd_client_ipv4, tvb, offset, 4, addr4, "%s", get_hostname(addr4));
5046 struct e_in6_addr addr6;
5047 tvb_get_ipv6(tvb, offset, &addr6);
5048 proto_tree_add_ipv6_format_value(cn_rts_command_tree, hf_dcerpc_cmd_client_ipv6, tvb, offset, 16, &addr6, "%s", get_hostname6(&addr6));
5052 padding = (guint8 *)tvb_memdup(wmem_packet_scope(), tvb, offset, 12);
5053 proto_tree_add_bytes(cn_rts_command_tree, hf_dcerpc_cn_rts_command_padding, tvb, offset, 12, padding);
5056 case RTS_CMD_ASSOCIATIONGROUPID:
5057 offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_associationgroupid, NULL);
5059 case RTS_CMD_DESTINATION:
5060 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_forwarddestination, NULL);
5062 case RTS_CMD_PINGTRAFFICSENTNOTIFY:
5063 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_pingtrafficsentnotify, NULL);
5066 expert_add_info(pinfo, tf, &ei_dcerpc_cn_rts_command);
5071 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RPCH");
5073 /* Define which PDU Body we are dealing with */
5074 info_str = "unknown RTS PDU";
5076 switch (rts_flags) {
5078 switch (commands_nb) {
5080 if (cmd[0] == 0x2) {
5081 info_str = "CONN/A3";
5082 } else if (cmd[0] == 0x3) {
5083 info_str = "IN_R1/A5,IN_R1/A6,IN_R2/A2,IN_R2/A5,OUT_R2/A4";
5084 } else if (cmd[0] == 0x7) {
5085 info_str = "IN_R1/B1";
5086 } else if (cmd[0] == 0x0) {
5087 info_str = "IN_R1/B2";
5088 } else if (cmd[0] == 0xD) {
5089 info_str = "IN_R2/A3,IN_R2/A4";
5090 } else if (cmd[0] == 0xA) {
5091 info_str = "OUT_R1/A9,OUT_R1/A10,OUT_R1/A11,OUT_R2/B1,OUT_R2/B2";
5095 if ((cmd[0] == 0x0) && (cmd[1] == 0x6)) {
5096 info_str = "CONN/B3";
5097 } else if ((cmd[0] == 0xD) && (cmd[1] == 0xA)) {
5098 info_str = "OUT_R2/A5,OUT_R2/A6";
5102 if ((cmd[0] == 0x6) && (cmd[1] == 0x0) && (cmd[2] == 0x2)) {
5103 info_str = "CONN/C1,CONN/C2";
5107 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x0)) {
5108 info_str = "CONN/A1";
5109 } else if ((cmd[0] == 0xD) && (cmd[1] == 0x6) && (cmd[2] == 0x0) && (cmd[3] == 0x2)) {
5110 info_str = "IN_R1/A3,IN_R1/A4";
5114 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x4) && (cmd[4] == 0x5) && (cmd[5] == 0xC)) {
5115 info_str = "CONN/B1";
5123 switch (commands_nb) {
5128 if ((cmd[0] == 0x7) || (cmd[0] == 0x8)) {
5129 info_str = "OUT_R2/C1";
5136 case RTS_FLAG_OTHER_CMD:
5137 switch (commands_nb) {
5139 if (cmd[0] == 0x5) {
5140 info_str = "Keep-Alive";
5141 } else if (cmd[0] == 0xE) {
5142 info_str = "PingTrafficSentNotify";
5143 } else if (cmd[0] == 0x1) {
5144 info_str = "FlowControlAck";
5148 if ((cmd[0] == 0xD) && (cmd[1] == 0x1)) {
5149 info_str = "FlowControlAckWithDestination";
5156 case RTS_FLAG_RECYCLE_CHANNEL:
5157 switch (commands_nb) {
5159 if (cmd[0] == 0xD) {
5160 info_str = "OUT_R1/A1,OUT_R1/A2,OUT_R2/A1,OUT_R2/A2";
5164 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3)) {
5165 info_str = "IN_R1/A1,IN_R2/A1";
5169 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3) && (cmd[4] == 0x0)) {
5170 info_str = "OUT_R1/A3,OUT_R2/A3";
5177 case RTS_FLAG_IN_CHANNEL|RTS_FLAG_RECYCLE_CHANNEL:
5178 switch (commands_nb) {
5180 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3) && (cmd[4] == 0x0) && (cmd[5] == 0x2)) {
5181 info_str = "IN_R1/A2";
5188 case RTS_FLAG_IN_CHANNEL:
5189 switch (commands_nb) {
5191 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x0) && (cmd[4] == 0x2) && (cmd[5] == 0xC) && (cmd[6] == 0xB)) {
5192 info_str = "CONN/B2";
5199 case RTS_FLAG_OUT_CHANNEL|RTS_FLAG_RECYCLE_CHANNEL:
5200 switch (commands_nb) {
5202 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3) && (cmd[4] == 0x4) && (cmd[5] == 0) && (cmd[6] == 0x2)) {
5203 info_str = "OUT_R1/A4";
5210 case RTS_FLAG_OUT_CHANNEL:
5211 switch (commands_nb) {
5213 if ((cmd[0] == 0xD) && (cmd[1] == 0x3)) {
5214 info_str = "OUT_R1/A7,OUT_R1/A8,OUT_R2/A8";
5218 if ((cmd[0] == 0xD) && (cmd[1] == 0x6) && (cmd[2] == 0x2)) {
5219 info_str = "OUT_R1/A5,OUT_R1/A6";
5220 } else if ((cmd[0] == 0xD) && (cmd[1] == 0x3) && (cmd[2] == 0x6)) {
5221 info_str = "OUT_R2/A7";
5225 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x4) && (cmd[4] == 0x0)) {
5226 info_str = "CONN/A2";
5234 switch (commands_nb) {
5236 if (cmd[0] == 0xA) {
5237 info_str = "OUT_R2/B3";
5245 switch (commands_nb) {
5257 col_add_fstr(pinfo->cinfo, COL_INFO, "%s, ", info_str);
5258 col_set_fence(pinfo->cinfo,COL_INFO);
5260 parent_pi = proto_tree_get_parent(dcerpc_tree);
5261 if (parent_pi != NULL) {
5262 proto_item_append_text(parent_pi, ", %s", info_str);
5267 is_dcerpc(tvbuff_t *tvb, int offset, packet_info *pinfo _U_)
5270 guint8 rpc_ver_minor;
5273 if (!tvb_bytes_exist(tvb, offset, sizeof(e_dce_cn_common_hdr_t)))
5274 return FALSE; /* not enough information to check */
5276 rpc_ver = tvb_get_guint8(tvb, offset++);
5279 rpc_ver_minor = tvb_get_guint8(tvb, offset++);
5280 if ((rpc_ver_minor != 0) && (rpc_ver_minor != 1))
5282 ptype = tvb_get_guint8(tvb, offset++);
5283 if (ptype > PDU_RTS)
5290 * DCERPC dissector for connection oriented calls.
5293 dissect_dcerpc_cn(tvbuff_t *tvb, int offset, packet_info *pinfo,
5294 proto_tree *tree, gboolean can_desegment, int *pkt_len)
5296 static const guint8 nulls[4] = { 0 };
5300 proto_item *ti = NULL;
5301 proto_item *tf = NULL;
5302 proto_tree *dcerpc_tree = NULL;
5303 e_dce_cn_common_hdr_t hdr;
5304 dcerpc_auth_info auth_info;
5305 tvbuff_t *fragment_tvb;
5306 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
5307 static const int * hdr_flags[] = {
5308 &hf_dcerpc_cn_flags_object,
5309 &hf_dcerpc_cn_flags_maybe,
5310 &hf_dcerpc_cn_flags_dne,
5311 &hf_dcerpc_cn_flags_mpx,
5312 &hf_dcerpc_cn_flags_reserved,
5313 &hf_dcerpc_cn_flags_cancel_pending,
5314 &hf_dcerpc_cn_flags_last_frag,
5315 &hf_dcerpc_cn_flags_first_frag,
5320 * when done over nbt, dcerpc requests are padded with 4 bytes of null
5321 * data for some reason.
5323 * XXX - if that's always the case, the right way to do this would
5324 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
5325 * the 4 bytes of null padding, and make that the dissector
5326 * used for "netbios".
5328 if (tvb_memeql(tvb, offset, nulls, 4) == 0) {
5337 * Check if this looks like a C/O DCERPC call
5339 if (!is_dcerpc(tvb, offset, pinfo))
5342 start_offset = offset;
5343 hdr.rpc_ver = tvb_get_guint8(tvb, offset++);
5344 hdr.rpc_ver_minor = tvb_get_guint8(tvb, offset++);
5345 hdr.ptype = tvb_get_guint8(tvb, offset++);
5347 hdr.flags = tvb_get_guint8(tvb, offset++);
5348 tvb_memcpy(tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
5349 offset += (int)sizeof (hdr.drep);
5351 hdr.frag_len = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5353 hdr.auth_len = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5355 hdr.call_id = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
5358 if (decode_data->dcectxid == 0) {
5359 col_append_fstr(pinfo->cinfo, COL_DCE_CALL, "%u", hdr.call_id);
5361 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
5362 * prepend a delimiter */
5363 col_append_fstr(pinfo->cinfo, COL_DCE_CALL, "#%u", hdr.call_id);
5366 if (can_desegment && pinfo->can_desegment
5367 && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
5368 pinfo->desegment_offset = start_offset;
5369 pinfo->desegment_len = hdr.frag_len - tvb_reported_length_remaining(tvb, start_offset);
5370 *pkt_len = 0; /* desegmentation required */
5374 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCERPC");
5376 if (decode_data->dcectxid != 0) {
5377 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
5378 * append a delimiter and set a column fence */
5379 col_append_str(pinfo->cinfo, COL_INFO, " # ");
5380 col_set_fence(pinfo->cinfo,COL_INFO);
5382 col_add_fstr(pinfo->cinfo, COL_INFO, "%s: call_id: %u",
5383 pckt_vals[hdr.ptype].strptr, hdr.call_id);
5385 if (decode_data->dcectxid != 0) {
5386 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU */
5387 expert_add_info(pinfo, NULL, &ei_dcerpc_fragment_multiple);
5390 offset = start_offset;
5391 tvb_ensure_bytes_exist(tvb, offset, 16);
5393 ti = proto_tree_add_item(tree, proto_dcerpc, tvb, offset, hdr.frag_len, ENC_NA);
5394 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
5397 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
5400 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset, 1, hdr.rpc_ver_minor);
5403 tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
5406 #if 0 /* XXX - too much "output noise", removed for now */
5407 if (hdr.ptype == PDU_BIND || hdr.ptype == PDU_ALTER ||
5408 hdr.ptype == PDU_BIND_ACK || hdr.ptype == PDU_ALTER_ACK)
5409 expert_add_info_format(pinfo, tf, &ei_dcerpc_context_change, "Context change: %s", val_to_str(hdr.ptype, pckt_vals, "(0x%x)"));
5411 if (hdr.ptype == PDU_BIND_NAK)
5412 expert_add_info(pinfo, tf, &ei_dcerpc_bind_not_acknowledged);
5415 proto_item_append_text(ti, " %s, Fragment: %s",
5416 val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"),
5417 fragment_type(hdr.flags));
5420 proto_tree_add_bitmask_value_with_flags(dcerpc_tree, tvb, offset, hf_dcerpc_cn_flags,
5421 ett_dcerpc_cn_flags, hdr_flags, hdr.flags, BMT_NO_APPEND);
5424 col_append_fstr(pinfo->cinfo, COL_INFO, ", Fragment: %s", fragment_type(hdr.flags));
5426 proto_tree_add_dcerpc_drep(dcerpc_tree, tvb, offset, hdr.drep, (int)sizeof (hdr.drep));
5427 offset += (int)sizeof (hdr.drep);
5429 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
5432 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
5435 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
5439 proto_item_append_text(ti, ", FragLen: %u, Call: %u", hdr.frag_len, hdr.call_id);
5443 * None of the stuff done above should throw an exception, because
5444 * we would have rejected this as "not DCE RPC" if we didn't have all
5445 * of it. (XXX - perhaps we should request reassembly if we have
5446 * enough of the header to consider it DCE RPC but not enough to
5447 * get the fragment length; in that case the stuff still wouldn't
5448 * throw an exception.)
5450 * The rest of the stuff might, so return the PDU length to our caller.
5451 * XXX - should we construct a tvbuff containing only the PDU and
5452 * use that? Or should we have separate "is this a DCE RPC PDU",
5453 * "how long is it", and "dissect it" routines - which might let us
5454 * do most of the work in "tcp_dissect_pdus()"?
5456 if (pkt_len != NULL)
5457 *pkt_len = hdr.frag_len + padding;
5459 /* The remaining bytes in the current tvb might contain multiple
5460 * DCE/RPC fragments, so create a new tvb subset for this fragment.
5461 * Only limit the end of the fragment, but not the offset start,
5462 * as the authentication function dissect_dcerpc_cn_auth() will fail
5463 * (and other functions might fail as well) computing the right start
5466 subtvb_len = MIN(hdr.frag_len, tvb_reported_length(tvb));
5467 fragment_tvb = tvb_new_subset(tvb, start_offset,
5468 subtvb_len /* length */,
5469 hdr.frag_len /* reported_length */);
5472 * Packet type specific stuff is next.
5474 switch (hdr.ptype) {
5477 dissect_dcerpc_cn_bind(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
5482 dissect_dcerpc_cn_bind_ack(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
5487 * Nothing after the common header other than credentials.
5489 dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr, TRUE,
5494 dissect_dcerpc_cn_rqst(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, tree, &hdr);
5498 dissect_dcerpc_cn_resp(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, tree, &hdr);
5502 dissect_dcerpc_cn_fault(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
5506 dissect_dcerpc_cn_bind_nak(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
5512 * Nothing after the common header other than an authentication
5515 dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr, FALSE,
5521 * Nothing after the common header, not even an authentication
5526 dissect_dcerpc_cn_rts(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
5530 /* might as well dissect the auth info */
5531 dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr, FALSE,
5539 * DCERPC dissector for connection oriented calls over packet-oriented
5543 dissect_dcerpc_cn_pk(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5545 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
5548 * Only one PDU per transport packet, and only one transport
5551 decode_data->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
5552 if (!dissect_dcerpc_cn(tvb, 0, pinfo, tree, FALSE, NULL)) {
5554 * It wasn't a DCERPC PDU.
5566 * DCERPC dissector for connection oriented calls over byte-stream
5568 * we need to distinguish here between SMB and non-TCP (more in the future?)
5569 * to be able to know what kind of private_data structure to expect.
5572 dissect_dcerpc_cn_bs_body(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
5574 volatile int offset = 0;
5576 volatile int dcerpc_pdus = 0;
5577 volatile gboolean ret = FALSE;
5580 * There may be multiple PDUs per transport packet; keep
5583 while (tvb_reported_length_remaining(tvb, offset) != 0) {
5586 if (dissect_dcerpc_cn(tvb, offset, pinfo, tree,
5587 dcerpc_cn_desegment, &pdu_len)) {
5590 } CATCH_NONFATAL_ERRORS {
5592 * Somebody threw an exception that means that there
5593 * was a problem dissecting the payload; that means
5594 * that a dissector was found, so we don't need to
5595 * dissect the payload as data or update the protocol
5598 * Just show the exception and then continue dissecting
5601 show_exception(tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
5603 * Presumably it looked enough like a DCE RPC PDU that we
5604 * dissected enough of it to throw an exception.
5609 if (dcerpc_pdus == 0) {
5610 gboolean try_desegment = FALSE;
5611 if (dcerpc_cn_desegment && pinfo->can_desegment &&
5612 !tvb_bytes_exist(tvb, offset, sizeof(e_dce_cn_common_hdr_t))) {
5613 /* look for a previous occurrence of the DCE-RPC protocol */
5614 wmem_list_frame_t *cur;
5615 cur = wmem_list_frame_prev(wmem_list_tail(pinfo->layers));
5616 while (cur != NULL) {
5617 if (proto_dcerpc == (gint)GPOINTER_TO_UINT(wmem_list_frame_data(cur))) {
5618 try_desegment = TRUE;
5621 cur = wmem_list_frame_prev(cur);
5625 if (try_desegment) {
5626 /* It didn't look like DCE-RPC but we already had one DCE-RPC
5627 * layer in this packet and what we have is short. Assume that
5628 * it was just too short to tell and ask the TCP layer for more
5630 pinfo->desegment_offset = offset;
5631 pinfo->desegment_len = (guint32)(sizeof(e_dce_cn_common_hdr_t) - tvb_reported_length_remaining(tvb, offset));
5633 /* Really not DCE-RPC */
5639 * Well, we've seen at least one DCERPC PDU.
5643 /* if we had more than one Req/Resp in this PDU change the protocol column */
5644 /* this will formerly contain the last interface name, which may not be the same for all Req/Resp */
5645 if (dcerpc_pdus >= 2)
5646 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "%u*DCERPC", dcerpc_pdus);
5650 * Desegmentation required - bail now, but give the user a hint that desegmentation might be done later.
5652 proto_tree_add_uint_format(tree, hf_dcerpc_cn_deseg_req, tvb, offset,
5654 tvb_reported_length_remaining(tvb, offset),
5655 "[DCE RPC: %u byte%s left, desegmentation might follow]",
5656 tvb_reported_length_remaining(tvb, offset),
5657 plurality(tvb_reported_length_remaining(tvb, offset), "", "s"));
5662 * Step to the next PDU.
5670 dissect_dcerpc_cn_bs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5672 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
5674 decode_data->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
5675 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
5679 get_dcerpc_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb,
5680 int offset _U_, void *data _U_)
5685 /* XXX: why does htis not take offset into account? */
5686 tvb_memcpy(tvb, (guint8 *)drep, 4, sizeof(drep));
5687 frag_len = dcerpc_tvb_get_ntohs(tvb, 8, drep);
5693 dissect_dcerpc_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
5696 dissect_dcerpc_cn(tvb, 0, pinfo, tree,
5697 /* Desegment is already handled by TCP, don't confuse it */
5704 dissect_dcerpc_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
5706 dcerpc_decode_as_data* decode_data;
5708 if (!is_dcerpc(tvb, 0, pinfo))
5711 decode_data = dcerpc_get_decode_data(pinfo);
5712 decode_data->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
5714 tcp_dissect_pdus(tvb, pinfo, tree, dcerpc_cn_desegment, 10, get_dcerpc_pdu_len, dissect_dcerpc_pdu, data);
5719 dissect_dcerpc_cn_smbpipe(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5721 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
5723 decode_data->dcetransporttype = DCE_CN_TRANSPORT_SMBPIPE;
5724 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
5728 dissect_dcerpc_cn_smb2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5730 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
5732 decode_data->dcetransporttype = DCE_CN_TRANSPORT_SMBPIPE;
5733 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
5739 dissect_dcerpc_dg_auth(tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
5740 e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
5742 proto_tree *auth_tree = NULL;
5743 guint8 protection_level;
5746 * Initially set "*auth_level_p" to -1 to indicate that we haven't
5747 * yet seen any authentication level information.
5749 if (auth_level_p != NULL)
5753 * The authentication information is at the *end* of the PDU; in
5754 * request and response PDUs, the request and response stub data
5757 * If the full packet is here, and there's data past the end of the
5758 * packet body, then dissect the auth info.
5760 offset += hdr->frag_len;
5761 if (tvb_reported_length_remaining(tvb, offset) > 0) {
5762 switch (hdr->auth_proto) {
5764 case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
5765 auth_tree = proto_tree_add_subtree(dcerpc_tree, tvb, offset, -1, ett_dcerpc_krb5_auth_verf, NULL, "Kerberos authentication verifier");
5766 protection_level = tvb_get_guint8(tvb, offset);
5767 if (auth_level_p != NULL)
5768 *auth_level_p = protection_level;
5769 proto_tree_add_uint(auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
5771 proto_tree_add_item(auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, ENC_BIG_ENDIAN);
5773 if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
5774 offset += 6; /* 6 bytes of padding */
5776 offset += 2; /* 2 bytes of padding */
5777 proto_tree_add_item(auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, ENC_NA);
5782 proto_tree_add_item(dcerpc_tree, hf_dcerpc_authentication_verifier, tvb, offset, -1, ENC_NA);
5789 dissect_dcerpc_dg_cancel_ack(tvbuff_t *tvb, int offset, packet_info *pinfo,
5790 proto_tree *dcerpc_tree,
5791 e_dce_dg_common_hdr_t *hdr)
5795 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5796 hdr->drep, hf_dcerpc_dg_cancel_vers,
5802 /* The only version we know about */
5803 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5804 hdr->drep, hf_dcerpc_dg_cancel_id,
5806 /*offset = */dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
5807 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
5814 dissect_dcerpc_dg_cancel(tvbuff_t *tvb, int offset, packet_info *pinfo,
5815 proto_tree *dcerpc_tree,
5816 e_dce_dg_common_hdr_t *hdr)
5820 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5821 hdr->drep, hf_dcerpc_dg_cancel_vers,
5827 /* The only version we know about */
5828 /*offset = */dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5829 hdr->drep, hf_dcerpc_dg_cancel_id,
5831 /* XXX - are NDR Booleans 32 bits? */
5833 /* XXX - the RPC reference in chapter: "the cancel PDU" doesn't mention
5834 the accepting_cancels field (it's only in the cancel_ack PDU)! */
5835 /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
5836 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
5843 dissect_dcerpc_dg_fack(tvbuff_t *tvb, int offset, packet_info *pinfo,
5844 proto_tree *dcerpc_tree,
5845 e_dce_dg_common_hdr_t *hdr)
5852 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
5853 hdr->drep, hf_dcerpc_dg_fack_vers,
5860 case 0: /* The only version documented in the DCE RPC 1.1 spec */
5861 case 1: /* This appears to be the same */
5862 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
5863 hdr->drep, hf_dcerpc_dg_fack_window_size,
5865 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5866 hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
5868 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5869 hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
5871 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
5872 hdr->drep, hf_dcerpc_dg_fack_serial_num,
5874 col_append_fstr(pinfo->cinfo, COL_INFO, " serial: %u",
5876 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
5877 hdr->drep, hf_dcerpc_dg_fack_selack_len,
5879 for (i = 0; i < selack_len; i++) {
5880 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5881 hdr->drep, hf_dcerpc_dg_fack_selack,
5890 dissect_dcerpc_dg_reject_fault(tvbuff_t *tvb, int offset, packet_info *pinfo,
5891 proto_tree *dcerpc_tree,
5892 e_dce_dg_common_hdr_t *hdr)
5896 /*offset = */dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5897 hdr->drep, hf_dcerpc_dg_status,
5900 col_append_fstr (pinfo->cinfo, COL_INFO,
5902 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
5906 dissect_dcerpc_dg_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
5907 proto_tree *dcerpc_tree, proto_tree *tree,
5908 e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
5910 int length, reported_length, stub_length;
5911 gboolean save_fragmented;
5912 fragment_head *fd_head;
5915 proto_item *parent_pi;
5917 col_append_fstr(pinfo->cinfo, COL_INFO, " opnum: %u len: %u",
5918 di->call_data->opnum, hdr->frag_len );
5920 length = tvb_reported_length_remaining(tvb, offset);
5921 reported_length = tvb_reported_length_remaining(tvb, offset);
5922 stub_length = hdr->frag_len;
5923 if (length > stub_length)
5924 length = stub_length;
5925 if (reported_length > stub_length)
5926 reported_length = stub_length;
5928 save_fragmented = pinfo->fragmented;
5930 /* If we don't have reassembly enabled, or this packet contains
5931 the entire PDU, or if this is a short frame (or a frame
5932 not reassembled at a lower layer) that doesn't include all
5933 the data in the fragment, just call the handoff directly if
5934 this is the first fragment or the PDU isn't fragmented. */
5935 if ( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
5936 !tvb_bytes_exist(tvb, offset, stub_length) ) {
5937 if (hdr->frag_num == 0) {
5940 /* First fragment, possibly the only fragment */
5943 * XXX - authentication info?
5945 pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
5946 next_tvb = tvb_new_subset(tvb, offset, length,
5948 dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb, TRUE, hdr->drep, di, NULL);
5950 /* PDU is fragmented and this isn't the first fragment */
5952 proto_tree_add_item(dcerpc_tree, hf_dcerpc_fragment_data, tvb, offset, stub_length, ENC_NA);
5956 /* Reassembly is enabled, the PDU is fragmented, and
5957 we have all the data in the fragment; the first two
5958 of those mean we should attempt reassembly, and the
5959 third means we can attempt reassembly. */
5961 proto_tree_add_item(dcerpc_tree, hf_dcerpc_fragment_data, tvb, offset, stub_length, ENC_NA);
5964 fd_head = fragment_add_seq(&dcerpc_cl_reassembly_table,
5966 pinfo, hdr->seqnum, (void *)hdr,
5967 hdr->frag_num, stub_length,
5968 !(hdr->flags1 & PFCL1_LASTFRAG), 0);
5969 if (fd_head != NULL) {
5970 /* We completed reassembly... */
5971 if (pinfo->num == fd_head->reassembled_in) {
5972 /* ...and this is the reassembled RPC PDU */
5973 next_tvb = tvb_new_chain(tvb, fd_head->tvb_data);
5974 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
5975 show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
5976 tree, pinfo, next_tvb, &pi);
5979 * XXX - authentication info?
5981 pinfo->fragmented = FALSE;
5982 dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb, TRUE, hdr->drep, di, NULL);
5984 /* ...and this isn't the reassembled RPC PDU */
5985 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
5986 tvb, 0, 0, fd_head->reassembled_in);
5987 PROTO_ITEM_SET_GENERATED(pi);
5988 parent_pi = proto_tree_get_parent(dcerpc_tree);
5989 if (parent_pi != NULL) {
5990 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
5992 col_append_fstr(pinfo->cinfo, COL_INFO,
5993 " [DCE/RPC fragment, reas: #%u]", fd_head->reassembled_in);
5997 pinfo->fragmented = save_fragmented;
6001 dissect_dcerpc_dg_rqst(tvbuff_t *tvb, int offset, packet_info *pinfo,
6002 proto_tree *dcerpc_tree, proto_tree *tree,
6003 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
6006 dcerpc_call_value *value;
6007 dcerpc_matched_key matched_key, *new_matched_key;
6009 proto_item *parent_pi;
6011 if (!(pinfo->fd->flags.visited)) {
6012 dcerpc_call_value *call_value;
6013 dcerpc_dg_call_key *call_key;
6015 call_key = (dcerpc_dg_call_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_dg_call_key));
6016 call_key->conv = conv;
6017 call_key->seqnum = hdr->seqnum;
6018 call_key->act_id = hdr->act_id;
6020 call_value = (dcerpc_call_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_call_value));
6021 call_value->uuid = hdr->if_id;
6022 call_value->ver = hdr->if_ver;
6023 call_value->object_uuid = hdr->obj_id;
6024 call_value->opnum = hdr->opnum;
6025 call_value->req_frame = pinfo->num;
6026 call_value->req_time = pinfo->abs_ts;
6027 call_value->rep_frame = 0;
6028 call_value->max_ptr = 0;
6029 call_value->se_data = NULL;
6030 call_value->private_data = NULL;
6031 call_value->pol = NULL;
6032 /* NDR64 is not available on dg transports ?*/
6033 call_value->flags = 0;
6035 g_hash_table_insert(dcerpc_dg_calls, call_key, call_value);
6037 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof(dcerpc_matched_key));
6038 new_matched_key->frame = pinfo->num;
6039 new_matched_key->call_id = hdr->seqnum;
6040 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
6043 matched_key.frame = pinfo->num;
6044 matched_key.call_id = hdr->seqnum;
6045 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
6047 value = wmem_new(wmem_packet_scope(), dcerpc_call_value);
6048 value->uuid = hdr->if_id;
6049 value->ver = hdr->if_ver;
6050 value->object_uuid = hdr->obj_id;
6051 value->opnum = hdr->opnum;
6052 value->req_frame = pinfo->num;
6053 value->rep_frame = 0;
6055 value->se_data = NULL;
6056 value->private_data = NULL;
6059 di = wmem_new0(wmem_packet_scope(), dcerpc_info);
6060 di->dcerpc_procedure_name = "";
6062 di->call_id = hdr->seqnum;
6063 di->transport_salt = -1;
6064 di->ptype = PDU_REQ;
6065 di->call_data = value;
6067 if (value->rep_frame != 0) {
6068 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
6069 tvb, 0, 0, value->rep_frame);
6070 PROTO_ITEM_SET_GENERATED(pi);
6071 parent_pi = proto_tree_get_parent(dcerpc_tree);
6072 if (parent_pi != NULL) {
6073 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
6076 dissect_dcerpc_dg_stub(tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
6080 dissect_dcerpc_dg_resp(tvbuff_t *tvb, int offset, packet_info *pinfo,
6081 proto_tree *dcerpc_tree, proto_tree *tree,
6082 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
6085 dcerpc_call_value *value;
6086 dcerpc_matched_key matched_key, *new_matched_key;
6088 proto_item *parent_pi;
6090 if (!(pinfo->fd->flags.visited)) {
6091 dcerpc_call_value *call_value;
6092 dcerpc_dg_call_key call_key;
6094 call_key.conv = conv;
6095 call_key.seqnum = hdr->seqnum;
6096 call_key.act_id = hdr->act_id;
6098 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_dg_calls, &call_key))) {
6099 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
6100 new_matched_key->frame = pinfo->num;
6101 new_matched_key->call_id = hdr->seqnum;
6102 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
6103 if (call_value->rep_frame == 0) {
6104 call_value->rep_frame = pinfo->num;
6109 matched_key.frame = pinfo->num;
6110 matched_key.call_id = hdr->seqnum;
6111 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
6113 value = wmem_new0(wmem_packet_scope(), dcerpc_call_value);
6114 value->uuid = hdr->if_id;
6115 value->ver = hdr->if_ver;
6116 value->object_uuid = hdr->obj_id;
6117 value->opnum = hdr->opnum;
6118 value->rep_frame = pinfo->num;
6121 di = wmem_new0(wmem_packet_scope(), dcerpc_info);
6122 di->dcerpc_procedure_name = "";
6124 di->transport_salt = -1;
6125 di->ptype = PDU_RESP;
6126 di->call_data = value;
6128 if (value->req_frame != 0) {
6130 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
6131 tvb, 0, 0, value->req_frame);
6132 PROTO_ITEM_SET_GENERATED(pi);
6133 parent_pi = proto_tree_get_parent(dcerpc_tree);
6134 if (parent_pi != NULL) {
6135 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
6137 nstime_delta(&delta_ts, &pinfo->abs_ts, &value->req_time);
6138 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
6139 PROTO_ITEM_SET_GENERATED(pi);
6141 proto_tree_add_expert(dcerpc_tree, pinfo, &ei_dcerpc_no_request_found, tvb, 0, 0);
6143 dissect_dcerpc_dg_stub(tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
6147 dissect_dcerpc_dg_ping_ack(tvbuff_t *tvb, int offset, packet_info *pinfo,
6148 proto_tree *dcerpc_tree,
6149 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
6151 proto_item *parent_pi;
6152 /* if (!(pinfo->fd->flags.visited)) {*/
6153 dcerpc_call_value *call_value;
6154 dcerpc_dg_call_key call_key;
6156 call_key.conv = conv;
6157 call_key.seqnum = hdr->seqnum;
6158 call_key.act_id = hdr->act_id;
6160 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_dg_calls, &call_key))) {
6164 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
6165 tvb, 0, 0, call_value->req_frame);
6166 PROTO_ITEM_SET_GENERATED(pi);
6167 parent_pi = proto_tree_get_parent(dcerpc_tree);
6168 if (parent_pi != NULL) {
6169 proto_item_append_text(parent_pi, ", [Req: #%u]", call_value->req_frame);
6172 col_append_fstr(pinfo->cinfo, COL_INFO, " [req: #%u]", call_value->req_frame);
6174 nstime_delta(&delta_ts, &pinfo->abs_ts, &call_value->req_time);
6175 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
6176 PROTO_ITEM_SET_GENERATED(pi);
6182 * DCERPC dissector for connectionless calls
6185 dissect_dcerpc_dg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
6187 proto_item *ti = NULL;
6188 proto_tree *dcerpc_tree = NULL;
6189 e_dce_dg_common_hdr_t hdr;
6191 conversation_t *conv;
6194 const char *uuid_name = NULL;
6195 static const int * hdr_flags1[] = {
6196 &hf_dcerpc_dg_flags1_rsrvd_80,
6197 &hf_dcerpc_dg_flags1_broadcast,
6198 &hf_dcerpc_dg_flags1_idempotent,
6199 &hf_dcerpc_dg_flags1_maybe,
6200 &hf_dcerpc_dg_flags1_nofack,
6201 &hf_dcerpc_dg_flags1_frag,
6202 &hf_dcerpc_dg_flags1_last_frag,
6203 &hf_dcerpc_dg_flags1_rsrvd_01,
6207 static const int * hdr_flags2[] = {
6208 &hf_dcerpc_dg_flags2_rsrvd_80,
6209 &hf_dcerpc_dg_flags2_rsrvd_40,
6210 &hf_dcerpc_dg_flags2_rsrvd_20,
6211 &hf_dcerpc_dg_flags2_rsrvd_10,
6212 &hf_dcerpc_dg_flags2_rsrvd_08,
6213 &hf_dcerpc_dg_flags2_rsrvd_04,
6214 &hf_dcerpc_dg_flags2_cancel_pending,
6215 &hf_dcerpc_dg_flags2_rsrvd_01,
6220 * Check if this looks like a CL DCERPC call. All dg packets
6221 * have an 80 byte header on them. Which starts with
6222 * version (4), pkt_type.
6224 if (tvb_reported_length(tvb) < sizeof (hdr)) {
6228 /* Version must be 4 */
6229 hdr.rpc_ver = tvb_get_guint8(tvb, offset++);
6230 if (hdr.rpc_ver != 4)
6233 /* Type must be <= 19 or it's not DCE/RPC */
6234 hdr.ptype = tvb_get_guint8(tvb, offset++);
6238 /* flags1 has bit 1 and 8 as reserved so if any of them are set, it is
6239 probably not a DCE/RPC packet
6241 hdr.flags1 = tvb_get_guint8(tvb, offset++);
6242 if (hdr.flags1&0x81)
6245 /* flags2 has all bits except bit 2 as reserved so if any of them are set
6246 it is probably not DCE/RPC.
6248 hdr.flags2 = tvb_get_guint8(tvb, offset++);
6249 if (hdr.flags2&0xfd)
6253 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCERPC");
6254 col_add_str(pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
6256 tvb_memcpy(tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
6257 offset += (int)sizeof (hdr.drep);
6258 hdr.serial_hi = tvb_get_guint8(tvb, offset++);
6259 dcerpc_tvb_get_uuid(tvb, offset, hdr.drep, &hdr.obj_id);
6261 dcerpc_tvb_get_uuid(tvb, offset, hdr.drep, &hdr.if_id);
6263 dcerpc_tvb_get_uuid(tvb, offset, hdr.drep, &hdr.act_id);
6265 hdr.server_boot = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
6267 hdr.if_ver = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
6269 hdr.seqnum = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
6271 hdr.opnum = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
6273 hdr.ihint = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
6275 hdr.ahint = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
6277 hdr.frag_len = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
6279 hdr.frag_num = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
6281 hdr.auth_proto = tvb_get_guint8(tvb, offset++);
6282 hdr.serial_lo = tvb_get_guint8(tvb, offset++);
6285 ti = proto_tree_add_item(tree, proto_dcerpc, tvb, 0, -1, ENC_NA);
6287 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
6288 proto_item_append_text(ti, " %s, Seq: %u, Serial: %u, Frag: %u, FragLen: %u",
6289 val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"),
6290 hdr.seqnum, hdr.serial_hi*256+hdr.serial_lo,
6291 hdr.frag_num, hdr.frag_len);
6296 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
6299 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
6302 proto_tree_add_bitmask_value(dcerpc_tree, tvb, offset, hf_dcerpc_dg_flags1,
6303 ett_dcerpc_dg_flags1, hdr_flags1, hdr.flags1);
6306 proto_tree_add_bitmask_value(dcerpc_tree, tvb, offset, hf_dcerpc_dg_flags2,
6307 ett_dcerpc_dg_flags2, hdr_flags2, hdr.flags2);
6311 proto_tree_add_dcerpc_drep(dcerpc_tree, tvb, offset, hdr.drep, (int)sizeof (hdr.drep));
6313 offset += (int)sizeof (hdr.drep);
6316 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
6320 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
6321 offset, 16, (e_guid_t *) &hdr.obj_id, "Object UUID: %s",
6322 guid_to_str(wmem_packet_scope(), (e_guid_t *) &hdr.obj_id));
6327 uuid_str = guid_to_str(wmem_packet_scope(), (e_guid_t*)&hdr.if_id);
6328 uuid_name = guids_get_uuid_name(&hdr.if_id);
6330 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
6331 offset, 16, (e_guid_t *) &hdr.if_id, "Interface: %s UUID: %s", uuid_name, uuid_str);
6333 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
6334 offset, 16, (e_guid_t *) &hdr.if_id, "Interface UUID: %s", uuid_str);
6340 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
6341 offset, 16, (e_guid_t *) &hdr.act_id, "Activity: %s",
6342 guid_to_str(wmem_packet_scope(), (e_guid_t *) &hdr.act_id));
6347 nstime_t server_boot;
6349 server_boot.secs = hdr.server_boot;
6350 server_boot.nsecs = 0;
6352 if (hdr.server_boot == 0)
6353 proto_tree_add_time_format_value(dcerpc_tree, hf_dcerpc_dg_server_boot,
6354 tvb, offset, 4, &server_boot,
6357 proto_tree_add_time(dcerpc_tree, hf_dcerpc_dg_server_boot,
6358 tvb, offset, 4, &server_boot);
6363 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
6367 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
6368 col_append_fstr(pinfo->cinfo, COL_INFO, ": seq: %u", hdr.seqnum);
6369 col_append_fstr(pinfo->cinfo, COL_DCE_CALL, "%u", hdr.seqnum);
6373 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
6377 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
6381 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
6385 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
6389 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
6390 if (hdr.flags1 & PFCL1_FRAG) {
6391 /* Fragmented - put the fragment number into the Info column */
6392 col_append_fstr(pinfo->cinfo, COL_INFO, " frag: %u",
6398 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
6402 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
6403 if (hdr.flags1 & PFCL1_FRAG) {
6404 /* Fragmented - put the serial number into the Info column */
6405 col_append_fstr(pinfo->cinfo, COL_INFO, " serial: %u",
6406 (hdr.serial_hi << 8) | hdr.serial_lo);
6412 * XXX - for Kerberos, we get a protection level; if it's
6413 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
6416 dissect_dcerpc_dg_auth(tvb, offset, dcerpc_tree, &hdr,
6421 * keeping track of the conversation shouldn't really be necessary
6422 * for connectionless packets, because everything we need to know
6423 * to dissect is in the header for each packet. Unfortunately,
6424 * Microsoft's implementation is buggy and often puts the
6425 * completely wrong if_id in the header. go figure. So, keep
6426 * track of the seqnum and use that if possible. Note: that's not
6427 * completely correct. It should really be done based on both the
6428 * activity_id and seqnum. I haven't seen anywhere that it would
6429 * make a difference, but for future reference...
6431 conv = find_or_create_conversation(pinfo);
6434 * Packet type specific stuff is next.
6437 switch (hdr.ptype) {
6439 case PDU_CANCEL_ACK:
6440 /* Body is optional */
6441 /* XXX - we assume "frag_len" is the length of the body */
6442 if (hdr.frag_len != 0)
6443 dissect_dcerpc_dg_cancel_ack(tvb, offset, pinfo, dcerpc_tree, &hdr);
6448 * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
6449 * but in at least one capture none of the Cl_cancel PDUs had a
6452 /* XXX - we assume "frag_len" is the length of the body */
6453 if (hdr.frag_len != 0)
6454 dissect_dcerpc_dg_cancel(tvb, offset, pinfo, dcerpc_tree, &hdr);
6458 /* Body is optional; if present, it's the same as PDU_FACK */
6459 /* XXX - we assume "frag_len" is the length of the body */
6460 if (hdr.frag_len != 0)
6461 dissect_dcerpc_dg_fack(tvb, offset, pinfo, dcerpc_tree, &hdr);
6465 /* Body is optional */
6466 /* XXX - we assume "frag_len" is the length of the body */
6467 if (hdr.frag_len != 0)
6468 dissect_dcerpc_dg_fack(tvb, offset, pinfo, dcerpc_tree, &hdr);
6473 dissect_dcerpc_dg_reject_fault(tvb, offset, pinfo, dcerpc_tree, &hdr);
6477 dissect_dcerpc_dg_rqst(tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
6481 dissect_dcerpc_dg_resp(tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
6484 /* these requests have no body */
6487 dissect_dcerpc_dg_ping_ack(tvb, offset, pinfo, dcerpc_tree, &hdr, conv);
6498 dcerpc_init_protocol(void)
6500 /* structures and data for BIND */
6501 dcerpc_binds = g_hash_table_new(dcerpc_bind_hash, dcerpc_bind_equal);
6503 /* structures and data for CALL */
6504 dcerpc_cn_calls = g_hash_table_new(dcerpc_cn_call_hash, dcerpc_cn_call_equal);
6505 dcerpc_dg_calls = g_hash_table_new(dcerpc_dg_call_hash, dcerpc_dg_call_equal);
6507 /* structure and data for MATCHED */
6508 dcerpc_matched = g_hash_table_new(dcerpc_matched_hash, dcerpc_matched_equal);
6509 decode_dcerpc_inject_bindings();
6513 dcerpc_cleanup_protocol(void)
6515 g_hash_table_destroy(dcerpc_binds);
6516 g_hash_table_destroy(dcerpc_cn_calls);
6517 g_hash_table_destroy(dcerpc_dg_calls);
6518 g_hash_table_destroy(dcerpc_matched);
6522 proto_register_dcerpc(void)
6524 static hf_register_info hf[] = {
6525 { &hf_dcerpc_request_in,
6526 { "Request in frame", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE,
6527 NULL, 0, "This packet is a response to the packet with this number", HFILL }},
6528 { &hf_dcerpc_response_in,
6529 { "Response in frame", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
6530 NULL, 0, "This packet will be responded in the packet with this number", HFILL }},
6531 { &hf_dcerpc_referent_id32,
6532 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
6533 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
6534 { &hf_dcerpc_referent_id64,
6535 { "Referent ID", "dcerpc.referent_id64", FT_UINT64, BASE_HEX,
6536 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
6538 { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6539 { &hf_dcerpc_ver_minor,
6540 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6541 { &hf_dcerpc_packet_type,
6542 { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS(pckt_vals), 0x0, NULL, HFILL }},
6543 { &hf_dcerpc_cn_flags,
6544 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6545 { &hf_dcerpc_cn_flags_first_frag,
6546 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_FIRST_FRAG, NULL, HFILL }},
6547 { &hf_dcerpc_cn_flags_last_frag,
6548 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_LAST_FRAG, NULL, HFILL }},
6549 { &hf_dcerpc_cn_flags_cancel_pending,
6550 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_PENDING_CANCEL, NULL, HFILL }},
6551 { &hf_dcerpc_cn_flags_reserved,
6552 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_RESERVED_1, NULL, HFILL }},
6553 { &hf_dcerpc_cn_flags_mpx,
6554 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_CONC_MPX, NULL, HFILL }},
6555 { &hf_dcerpc_cn_flags_dne,
6556 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_DID_NOT_EXECUTE, NULL, HFILL }},
6557 { &hf_dcerpc_cn_flags_maybe,
6558 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_MAYBE, NULL, HFILL }},
6559 { &hf_dcerpc_cn_flags_object,
6560 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_OBJECT_UUID, NULL, HFILL }},
6562 { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6563 { &hf_dcerpc_drep_byteorder,
6564 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS(drep_byteorder_vals), 0x0, NULL, HFILL }},
6565 { &hf_dcerpc_ndr_padding,
6566 { "NDR-Padding", "dcerpc.ndr_padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6567 { &hf_dcerpc_drep_character,
6568 { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS(drep_character_vals), 0x0, NULL, HFILL }},
6569 { &hf_dcerpc_drep_fp,
6570 { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS(drep_fp_vals), 0x0, NULL, HFILL }},
6571 { &hf_dcerpc_cn_frag_len,
6572 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6573 { &hf_dcerpc_cn_auth_len,
6574 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6575 { &hf_dcerpc_cn_call_id,
6576 { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6577 { &hf_dcerpc_cn_max_xmit,
6578 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6579 { &hf_dcerpc_cn_max_recv,
6580 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6581 { &hf_dcerpc_cn_assoc_group,
6582 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6583 { &hf_dcerpc_cn_num_ctx_items,
6584 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6585 { &hf_dcerpc_cn_ctx_item,
6586 { "Ctx Item", "dcerpc.cn_ctx_item", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6587 { &hf_dcerpc_cn_ctx_id,
6588 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6589 { &hf_dcerpc_cn_num_trans_items,
6590 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6591 { &hf_dcerpc_cn_bind_abstract_syntax,
6592 { "Abstract Syntax", "dcerpc.cn_bind_abstract_syntax", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6593 { &hf_dcerpc_cn_bind_if_id,
6594 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6595 { &hf_dcerpc_cn_bind_if_ver,
6596 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6597 { &hf_dcerpc_cn_bind_if_ver_minor,
6598 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6599 { &hf_dcerpc_cn_bind_trans_syntax,
6600 { "Transfer Syntax", "dcerpc.cn_bind_trans", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6601 { &hf_dcerpc_cn_bind_trans_id,
6602 { "ID", "dcerpc.cn_bind_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6603 { &hf_dcerpc_cn_bind_trans_ver,
6604 { "ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6605 { &hf_dcerpc_cn_bind_trans_btfn, /* [MS-RPCE] 2.2.2.14 */
6606 {"Bind Time Features", "dcerpc.cn_bind_trans_btfn", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
6607 { &hf_dcerpc_cn_bind_trans_btfn_01,
6608 { "Security Context Multiplexing Supported", "dcerpc.cn_bind_trans_btfn.01", FT_BOOLEAN, 16, NULL, 0x01, NULL, HFILL }},
6609 { &hf_dcerpc_cn_bind_trans_btfn_02,
6610 { "Keep Connection On Orphan Supported", "dcerpc.cn_bind_trans_btfn.02", FT_BOOLEAN, 16, NULL, 0x02, NULL, HFILL }},
6611 { &hf_dcerpc_cn_alloc_hint,
6612 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6613 { &hf_dcerpc_cn_sec_addr_len,
6614 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6615 { &hf_dcerpc_cn_sec_addr,
6616 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6617 { &hf_dcerpc_cn_num_results,
6618 { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6619 { &hf_dcerpc_cn_ack_result,
6620 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, NULL, HFILL }},
6621 { &hf_dcerpc_cn_ack_reason,
6622 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, NULL, HFILL }},
6623 { &hf_dcerpc_cn_ack_trans_id,
6624 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6625 { &hf_dcerpc_cn_ack_trans_ver,
6626 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6627 { &hf_dcerpc_cn_reject_reason,
6628 { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, NULL, HFILL }},
6629 { &hf_dcerpc_cn_num_protocols,
6630 { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6631 { &hf_dcerpc_cn_protocol_ver_major,
6632 { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6633 { &hf_dcerpc_cn_protocol_ver_minor,
6634 { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6635 { &hf_dcerpc_cn_cancel_count,
6636 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6637 { &hf_dcerpc_cn_status,
6638 { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, NULL, HFILL }},
6639 { &hf_dcerpc_cn_deseg_req,
6640 { "Desegmentation Required", "dcerpc.cn_deseg_req", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6641 { &hf_dcerpc_auth_type,
6642 { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS(authn_protocol_vals), 0x0, NULL, HFILL }},
6643 { &hf_dcerpc_auth_level,
6644 { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, NULL, HFILL }},
6645 { &hf_dcerpc_auth_pad_len,
6646 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6647 { &hf_dcerpc_auth_rsrvd,
6648 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6649 { &hf_dcerpc_auth_ctx_id,
6650 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6651 { &hf_dcerpc_dg_flags1,
6652 { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6653 { &hf_dcerpc_dg_flags1_rsrvd_01,
6654 { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_RESERVED_01, NULL, HFILL }},
6655 { &hf_dcerpc_dg_flags1_last_frag,
6656 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_LASTFRAG, NULL, HFILL }},
6657 { &hf_dcerpc_dg_flags1_frag,
6658 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_FRAG, NULL, HFILL }},
6659 { &hf_dcerpc_dg_flags1_nofack,
6660 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_NOFACK, NULL, HFILL }},
6661 { &hf_dcerpc_dg_flags1_maybe,
6662 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_MAYBE, NULL, HFILL }},
6663 { &hf_dcerpc_dg_flags1_idempotent,
6664 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_IDEMPOTENT, NULL, HFILL }},
6665 { &hf_dcerpc_dg_flags1_broadcast,
6666 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_BROADCAST, NULL, HFILL }},
6667 { &hf_dcerpc_dg_flags1_rsrvd_80,
6668 { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_RESERVED_80, NULL, HFILL }},
6669 { &hf_dcerpc_dg_flags2,
6670 { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6671 { &hf_dcerpc_dg_flags2_rsrvd_01,
6672 { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_01, NULL, HFILL }},
6673 { &hf_dcerpc_dg_flags2_cancel_pending,
6674 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_CANCEL_PENDING, NULL, HFILL }},
6675 { &hf_dcerpc_dg_flags2_rsrvd_04,
6676 { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_04, NULL, HFILL }},
6677 { &hf_dcerpc_dg_flags2_rsrvd_08,
6678 { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_08, NULL, HFILL }},
6679 { &hf_dcerpc_dg_flags2_rsrvd_10,
6680 { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_10, NULL, HFILL }},
6681 { &hf_dcerpc_dg_flags2_rsrvd_20,
6682 { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_20, NULL, HFILL }},
6683 { &hf_dcerpc_dg_flags2_rsrvd_40,
6684 { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_40, NULL, HFILL }},
6685 { &hf_dcerpc_dg_flags2_rsrvd_80,
6686 { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_80, NULL, HFILL }},
6687 { &hf_dcerpc_dg_serial_lo,
6688 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6689 { &hf_dcerpc_dg_serial_hi,
6690 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6691 { &hf_dcerpc_dg_ahint,
6692 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6693 { &hf_dcerpc_dg_ihint,
6694 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6695 { &hf_dcerpc_dg_frag_len,
6696 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6697 { &hf_dcerpc_dg_frag_num,
6698 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6699 { &hf_dcerpc_dg_auth_proto,
6700 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS(authn_protocol_vals), 0x0, NULL, HFILL }},
6701 { &hf_dcerpc_dg_seqnum,
6702 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6703 { &hf_dcerpc_dg_server_boot,
6704 { "Server boot time", "dcerpc.dg_server_boot", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0, NULL, HFILL }},
6705 { &hf_dcerpc_dg_if_ver,
6706 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6707 { &hf_dcerpc_krb5_av_prot_level,
6708 { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, NULL, HFILL }},
6709 { &hf_dcerpc_krb5_av_key_vers_num,
6710 { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6711 { &hf_dcerpc_krb5_av_key_auth_verifier,
6712 { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6713 { &hf_dcerpc_obj_id,
6714 { "Object", "dcerpc.obj_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6715 { &hf_dcerpc_dg_if_id,
6716 { "Interface", "dcerpc.dg_if_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6717 { &hf_dcerpc_dg_act_id,
6718 { "Activity", "dcerpc.dg_act_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6720 { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6722 { &hf_dcerpc_dg_cancel_vers,
6723 { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6725 { &hf_dcerpc_dg_cancel_id,
6726 { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6728 { &hf_dcerpc_dg_server_accepting_cancels,
6729 { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6731 { &hf_dcerpc_dg_fack_vers,
6732 { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6734 { &hf_dcerpc_dg_fack_window_size,
6735 { "Window Size", "dcerpc.fack_window_size", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6737 { &hf_dcerpc_dg_fack_max_tsdu,
6738 { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6740 { &hf_dcerpc_dg_fack_max_frag_size,
6741 { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6743 { &hf_dcerpc_dg_fack_serial_num,
6744 { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6746 { &hf_dcerpc_dg_fack_selack_len,
6747 { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6749 { &hf_dcerpc_dg_fack_selack,
6750 { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6752 { &hf_dcerpc_dg_status,
6753 { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, NULL, HFILL }},
6755 { &hf_dcerpc_array_max_count,
6756 { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
6758 { &hf_dcerpc_array_offset,
6759 { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
6761 { &hf_dcerpc_array_actual_count,
6762 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
6765 { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6767 { &hf_dcerpc_null_pointer,
6768 { "NULL Pointer", "dcerpc.null_pointer", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6770 { &hf_dcerpc_fragments,
6771 { "Reassembled DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
6772 NULL, 0x0, "DCE/RPC Fragments", HFILL }},
6774 { &hf_dcerpc_fragment,
6775 { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM, BASE_NONE,
6776 NULL, 0x0, NULL, HFILL }},
6778 { &hf_dcerpc_fragment_overlap,
6779 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE,
6780 NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
6782 { &hf_dcerpc_fragment_overlap_conflict,
6783 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE,
6784 NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
6786 { &hf_dcerpc_fragment_multiple_tails,
6787 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE,
6788 NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
6790 { &hf_dcerpc_fragment_too_long_fragment,
6791 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE,
6792 NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
6794 { &hf_dcerpc_fragment_error,
6795 { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE,
6796 NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
6798 { &hf_dcerpc_fragment_count,
6799 { "Fragment count", "dcerpc.fragment.count", FT_UINT32, BASE_DEC,
6800 NULL, 0x0, NULL, HFILL }},
6803 { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE,
6804 NULL, 0, "Time between Request and Response for DCE-RPC calls", HFILL }},
6806 { &hf_dcerpc_reassembled_in,
6807 { "Reassembled PDU in frame", "dcerpc.reassembled_in", FT_FRAMENUM, BASE_NONE,
6808 NULL, 0x0, "The DCE/RPC PDU is completely reassembled in the packet with this number", HFILL }},
6810 { &hf_dcerpc_reassembled_length,
6811 { "Reassembled DCE/RPC length", "dcerpc.reassembled.length", FT_UINT32, BASE_DEC,
6812 NULL, 0x0, "The total length of the reassembled payload", HFILL }},
6814 { &hf_dcerpc_unknown_if_id,
6815 { "Unknown DCERPC interface id", "dcerpc.unknown_if_id", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6817 { &hf_dcerpc_cn_rts_flags,
6818 { "RTS Flags", "dcerpc.cn_rts_flags", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6819 { &hf_dcerpc_cn_rts_flags_none,
6820 {"None", "dcerpc.cn_rts_flags.none", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_NONE, NULL, HFILL }},
6821 { &hf_dcerpc_cn_rts_flags_ping,
6822 { "Ping", "dcerpc.cn_rts.flags.ping", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_PING, NULL, HFILL }},
6823 { &hf_dcerpc_cn_rts_flags_other_cmd,
6824 { "Other Cmd", "dcerpc.cn_rts_flags.other_cmd", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_OTHER_CMD, NULL, HFILL }},
6825 { &hf_dcerpc_cn_rts_flags_recycle_channel,
6826 { "Recycle Channel", "dcerpc.cn_rts_flags.recycle_channel", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_RECYCLE_CHANNEL, NULL, HFILL }},
6827 { &hf_dcerpc_cn_rts_flags_in_channel,
6828 { "In Channel", "dcerpc.cn_rts_flags.in_channel", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_IN_CHANNEL, NULL, HFILL }},
6829 { &hf_dcerpc_cn_rts_flags_out_channel,
6830 { "Out Channel", "dcerpc.cn_rts_flags.out_channel", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_OUT_CHANNEL, NULL, HFILL }},
6831 { &hf_dcerpc_cn_rts_flags_eof,
6832 { "EOF", "dcerpc.cn_rts_flags.eof", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_EOF, NULL, HFILL }},
6833 { &hf_dcerpc_cn_rts_commands_nb,
6834 { "RTS Number of Commands", "dcerpc.cn_rts_commands_nb", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6835 { &hf_dcerpc_cn_rts_command,
6836 { "RTS Command", "dcerpc.cn_rts_command", FT_UINT32, BASE_HEX, VALS(rts_command_vals), 0x0, NULL, HFILL }},
6837 { &hf_dcerpc_cn_rts_command_receivewindowsize,
6838 {"Receive Window Size", "dcerpc.cn_rts_command.receivewindowsize", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6839 { &hf_dcerpc_cn_rts_command_fack_bytesreceived,
6840 {"Bytes Received", "dcerpc.cn_rts_command.fack.bytesreceived", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6841 { &hf_dcerpc_cn_rts_command_fack_availablewindow,
6842 {"Available Window", "dcerpc.cn_rts_command.fack.availablewindow", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6843 { &hf_dcerpc_cn_rts_command_fack_channelcookie,
6844 {"Channel Cookie", "dcerpc.cn_rts_command.fack.channelcookie", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6845 { &hf_dcerpc_cn_rts_command_connectiontimeout,
6846 {"Connection Timeout", "dcerpc.cn_rts_command.connectiontimeout", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6847 { &hf_dcerpc_cn_rts_command_cookie,
6848 {"Cookie", "dcerpc.cn_rts_command.cookie", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6849 { &hf_dcerpc_cn_rts_command_channellifetime,
6850 {"Channel Lifetime", "dcerpc.cn_rts_command.channellifetime", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6851 { &hf_dcerpc_cn_rts_command_clientkeepalive,
6852 {"Client Keepalive", "dcerpc.cn_rts_command.clientkeepalive", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6853 { &hf_dcerpc_cn_rts_command_version,
6854 {"Version", "dcerpc.cn_rts_command.version", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6855 { &hf_dcerpc_cn_rts_command_conformancecount,
6856 {"Conformance Count", "dcerpc.cn_rts_command.padding.conformancecount", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6857 { &hf_dcerpc_cn_rts_command_padding,
6858 { "Padding", "dcerpc.cn_rts_command.padding.padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
6859 { &hf_dcerpc_cn_rts_command_addrtype,
6860 { "Address Type", "dcerpc.cn_rts_command.addrtype", FT_UINT32, BASE_DEC, VALS(rts_addresstype_vals), 0x0, NULL, HFILL }},
6861 { &hf_dcerpc_cn_rts_command_associationgroupid,
6862 {"Association Group ID", "dcerpc.cn_rts_command.associationgroupid", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6863 { &hf_dcerpc_cn_rts_command_forwarddestination,
6864 {"Forward Destination", "dcerpc.cn_rts_command.forwarddestination", FT_UINT32, BASE_DEC, VALS(rts_forward_destination_vals), 0x0, NULL, HFILL }},
6865 { &hf_dcerpc_cn_rts_command_pingtrafficsentnotify,
6866 {"Ping Traffic Sent Notify", "dcerpc.cn_rts_command.pingtrafficsentnotify", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6867 { &hf_dcerpc_sec_vt_signature,
6868 {"SEC_VT_SIGNATURE", "dcerpc.rpc_sec_vt.signature", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6869 { &hf_dcerpc_sec_vt_command_end,
6870 {"SEC_VT_COMMAND_END", "dcerpc.rpc_sec_vt.command.end", FT_BOOLEAN, 16, NULL, 0x4000, NULL, HFILL }},
6871 { &hf_dcerpc_sec_vt_command_must,
6872 {"SEC_VT_MUST_PROCESS_COMMAND", "dcerpc.rpc_sec_vt.command.must_process", FT_BOOLEAN, 16, NULL, 0x8000, NULL, HFILL }},
6873 { &hf_dcerpc_sec_vt_command_cmd,
6874 {"Cmd", "dcerpc.rpc_sec_vt.command.cmd", FT_UINT16, BASE_HEX, VALS(sec_vt_command_cmd_vals), 0x3fff, NULL, HFILL }},
6875 { &hf_dcerpc_sec_vt_command,
6876 {"Command", "dcerpc.rpc_sec_vt.command", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
6877 { &hf_dcerpc_sec_vt_command_length,
6878 {"Length", "dcerpc.rpc_sec_vt.command.length", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL}},
6879 { &hf_dcerpc_sec_vt_bitmask,
6880 {"rpc_sec_vt_bitmask", "dcerpc.rpc_sec_vt.bitmask", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
6881 { &hf_dcerpc_sec_vt_bitmask_sign,
6882 {"CLIENT_SUPPORT_HEADER_SIGNING", "dcerpc.rpc_sec_vt.bitmask.sign", FT_BOOLEAN, 32, NULL, 0x1, NULL, HFILL }},
6883 { &hf_dcerpc_sec_vt_pcontext_uuid,
6884 {"UUID", "dcerpc.rpc_sec_vt.pcontext.interface.uuid", FT_GUID, BASE_NONE, NULL, 0, NULL, HFILL }},
6885 { &hf_dcerpc_sec_vt_pcontext_ver,
6886 {"Version", "dcerpc.rpc_sec_vt.pcontext.interface.ver", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
6887 { &hf_dcerpc_reserved,
6888 {"Reserved", "dcerpc.reserved", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
6889 { &hf_dcerpc_unknown,
6890 {"Unknown", "dcerpc.unknown", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
6891 { &hf_dcerpc_missalign,
6892 {"missalign", "dcerpc.missalign", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
6893 /* Generated from convert_proto_tree_add_text.pl */
6894 { &hf_dcerpc_duplicate_ptr, { "duplicate PTR", "dcerpc.duplicate_ptr", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6895 { &hf_dcerpc_encrypted_stub_data, { "Encrypted stub data", "dcerpc.encrypted_stub_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6896 { &hf_dcerpc_decrypted_stub_data, { "Decrypted stub data", "dcerpc.decrypted_stub_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6897 { &hf_dcerpc_payload_stub_data, { "Payload stub data", "dcerpc.payload_stub_data", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6898 { &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 }},
6899 { &hf_dcerpc_stub_data, { "Stub data", "dcerpc.stub_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6900 { &hf_dcerpc_auth_padding, { "Auth Padding", "dcerpc.auth_padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6901 { &hf_dcerpc_auth_verifier, { "Auth Verifier", "dcerpc.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6902 { &hf_dcerpc_auth_credentials, { "Auth Credentials", "dcerpc.auth_credentials", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6903 { &hf_dcerpc_fault_stub_data, { "Fault stub data", "dcerpc.fault_stub_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6904 { &hf_dcerpc_fragment_data, { "Fragment data", "dcerpc.fragment_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6905 { &hf_dcerpc_cmd_client_ipv4, { "RTS Client address", "dcerpc.cmd_client_ipv4", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6906 { &hf_dcerpc_cmd_client_ipv6, { "RTS Client address", "dcerpc.cmd_client_ipv6", FT_IPv6, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6907 { &hf_dcerpc_authentication_verifier, { "Authentication verifier", "dcerpc.authentication_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6909 static gint *ett[] = {
6911 &ett_dcerpc_cn_flags,
6913 &ett_dcerpc_cn_iface,
6914 &ett_dcerpc_cn_trans_syntax,
6915 &ett_dcerpc_cn_trans_btfn,
6916 &ett_dcerpc_cn_bind_trans_btfn,
6917 &ett_dcerpc_cn_rts_flags,
6918 &ett_dcerpc_cn_rts_command,
6919 &ett_dcerpc_cn_rts_pdu,
6921 &ett_dcerpc_dg_flags1,
6922 &ett_dcerpc_dg_flags2,
6923 &ett_dcerpc_pointer_data,
6925 &ett_dcerpc_fragments,
6926 &ett_dcerpc_fragment,
6927 &ett_dcerpc_krb5_auth_verf,
6928 &ett_dcerpc_verification_trailer,
6929 &ett_dcerpc_sec_vt_command,
6930 &ett_dcerpc_sec_vt_bitmask,
6931 &ett_dcerpc_sec_vt_pcontext,
6932 &ett_dcerpc_sec_vt_header,
6933 &ett_dcerpc_complete_stub_data,
6936 static ei_register_info ei[] = {
6937 { &ei_dcerpc_fragment, { "dcerpc.fragment.reassemble", PI_REASSEMBLE, PI_CHAT, "%s fragment", EXPFILL }},
6938 { &ei_dcerpc_fragment_reassembled, { "dcerpc.fragment_reassembled", PI_REASSEMBLE, PI_CHAT, "%s fragment, reassembled", EXPFILL }},
6939 { &ei_dcerpc_cn_ctx_id_no_bind, { "dcerpc.cn_ctx_id.no_bind", PI_UNDECODED, PI_NOTE, "No bind info for interface Context ID %u - capture start too late?", EXPFILL }},
6940 { &ei_dcerpc_no_request_found, { "dcerpc.no_request_found", PI_SEQUENCE, PI_NOTE, "No request to this DCE/RPC call found", EXPFILL }},
6941 { &ei_dcerpc_cn_status, { "dcerpc.cn_status.expert", PI_RESPONSE_CODE, PI_NOTE, "Fault: %s", EXPFILL }},
6942 { &ei_dcerpc_fragment_multiple, { "dcerpc.fragment_multiple", PI_SEQUENCE, PI_CHAT, "Multiple DCE/RPC fragments/PDU's in one packet", EXPFILL }},
6943 { &ei_dcerpc_context_change, { "dcerpc.context_change", PI_SEQUENCE, PI_CHAT, "Context change: %s", EXPFILL }},
6944 { &ei_dcerpc_bind_not_acknowledged, { "dcerpc.bind_not_acknowledged", PI_SEQUENCE, PI_WARN, "Bind not acknowledged", EXPFILL }},
6945 { &ei_dcerpc_verifier_unavailable, { "dcerpc.verifier_unavailable", PI_UNDECODED, PI_WARN, NULL, EXPFILL }},
6946 { &ei_dcerpc_invalid_pdu_authentication_attempt, { "dcerpc.invalid_pdu_authentication_attempt", PI_UNDECODED, PI_WARN, NULL, EXPFILL }},
6947 /* Generated from convert_proto_tree_add_text.pl */
6948 { &ei_dcerpc_long_frame, { "dcerpc.long_frame", PI_PROTOCOL, PI_WARN, "Long frame", EXPFILL }},
6949 { &ei_dcerpc_cn_rts_command, { "dcerpc.cn_rts_command.unknown", PI_PROTOCOL, PI_WARN, "unknown RTS command number", EXPFILL }},
6952 /* Decode As handling */
6953 static build_valid_func dcerpc_da_build_value[1] = {dcerpc_value};
6954 static decode_as_value_t dcerpc_da_values = {dcerpc_prompt, 1, dcerpc_da_build_value};
6955 static decode_as_t dcerpc_da = {"dcerpc", "DCE-RPC", "dcerpc.uuid",
6956 1, 0, &dcerpc_da_values, NULL, NULL,
6957 dcerpc_populate_list, decode_dcerpc_binding_reset, dcerpc_decode_as_change, dcerpc_decode_as_free};
6959 module_t *dcerpc_module;
6960 expert_module_t* expert_dcerpc;
6962 proto_dcerpc = proto_register_protocol("Distributed Computing Environment / Remote Procedure Call (DCE/RPC)", "DCERPC", "dcerpc");
6963 proto_register_field_array(proto_dcerpc, hf, array_length(hf));
6964 proto_register_subtree_array(ett, array_length(ett));
6965 expert_dcerpc = expert_register_protocol(proto_dcerpc);
6966 expert_register_field_array(expert_dcerpc, ei, array_length(ei));
6968 uuid_dissector_table = register_dissector_table("dcerpc.uuid", "DCE/RPC UUIDs", proto_dcerpc, FT_GUID, BASE_HEX);
6970 register_init_routine(dcerpc_init_protocol);
6971 register_cleanup_routine(dcerpc_cleanup_protocol);
6972 dcerpc_module = prefs_register_protocol(proto_dcerpc, NULL);
6973 prefs_register_bool_preference(dcerpc_module,
6975 "Reassemble DCE/RPC messages spanning multiple TCP segments",
6976 "Whether the DCE/RPC dissector should reassemble messages"
6977 " spanning multiple TCP segments."
6978 " To use this option, you must also enable"
6979 " \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
6980 &dcerpc_cn_desegment);
6981 prefs_register_bool_preference(dcerpc_module,
6982 "reassemble_dcerpc",
6983 "Reassemble DCE/RPC fragments",
6984 "Whether the DCE/RPC dissector should reassemble fragmented DCE/RPC PDUs",
6985 &dcerpc_reassemble);
6986 register_init_routine(dcerpc_reassemble_init);
6987 dcerpc_uuids = g_hash_table_new(dcerpc_uuid_hash, dcerpc_uuid_equal);
6988 dcerpc_tap = register_tap("dcerpc");
6990 register_decode_as(&dcerpc_da);
6992 register_srt_table(proto_dcerpc, NULL, 1, dcerpcstat_packet, dcerpcstat_init, dcerpcstat_param);
6994 tvb_trailer_signature = tvb_new_real_data(TRAILER_SIGNATURE,
6995 sizeof(TRAILER_SIGNATURE),
6996 sizeof(TRAILER_SIGNATURE));
7000 proto_reg_handoff_dcerpc(void)
7002 heur_dissector_add("tcp", dissect_dcerpc_tcp, "DCE/RPC over TCP", "dcerpc_tcp", proto_dcerpc, HEURISTIC_ENABLE);
7003 heur_dissector_add("netbios", dissect_dcerpc_cn_pk, "DCE/RPC over NetBios", "dcerpc_netbios", proto_dcerpc, HEURISTIC_ENABLE);
7004 heur_dissector_add("udp", dissect_dcerpc_dg, "DCE/RPC over UDP", "dcerpc_udp", proto_dcerpc, HEURISTIC_ENABLE);
7005 heur_dissector_add("smb_transact", dissect_dcerpc_cn_smbpipe, "DCE/RPC over SMB", "dcerpc_smb_transact", proto_dcerpc, HEURISTIC_ENABLE);
7006 heur_dissector_add("smb2_pipe_subdissectors", dissect_dcerpc_cn_smb2, "DCE/RPC over SMB2", "dcerpc_smb2", proto_dcerpc, HEURISTIC_ENABLE);
7007 heur_dissector_add("http", dissect_dcerpc_cn_bs, "DCE/RPC over HTTP", "dcerpc_http", proto_dcerpc, HEURISTIC_ENABLE);
7008 dcerpc_smb_init(proto_dcerpc);
7010 guids_add_uuid(&uuid_data_repr_proto, "32bit NDR");
7011 guids_add_uuid(&uuid_ndr64, "64bit NDR");
7012 guids_add_uuid(&uuid_asyncemsmdb, "async MAPI");
7016 * Editor modelines - http://www.wireshark.org/tools/modelines.html
7021 * indent-tabs-mode: nil
7024 * vi: set shiftwidth=4 tabstop=8 expandtab:
7025 * :indentSize=4:tabSize=8:noTabs=true: