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 "packet-tcp.h"
44 #include "packet-dcerpc.h"
45 #include "packet-dcerpc-nt.h"
47 void proto_register_dcerpc(void);
48 void proto_reg_handoff_dcerpc(void);
50 static int dcerpc_tap = -1;
52 /* 32bit Network Data Representation, see DCE/RPC Appendix I */
53 static e_guid_t uuid_data_repr_proto = { 0x8a885d04, 0x1ceb, 0x11c9,
54 { 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60 } };
56 /* 64bit Network Data Representation, introduced in Windows Server 2008 */
57 static e_guid_t uuid_ndr64 = { 0x71710533, 0xbeba, 0x4937,
58 { 0x83, 0x19, 0xb5, 0xdb, 0xef, 0x9c, 0xcc, 0x36 } };
60 /* Bind Time Feature Negotiation, see [MS-RPCE] 3.3.1.5.3 */
61 static e_guid_t uuid_bind_time_feature_nego_00 = { 0x6cb71c2c, 0x9812, 0x4540, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
62 static e_guid_t uuid_bind_time_feature_nego_01 = { 0x6cb71c2c, 0x9812, 0x4540, { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
63 static e_guid_t uuid_bind_time_feature_nego_02 = { 0x6cb71c2c, 0x9812, 0x4540, { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
64 static e_guid_t uuid_bind_time_feature_nego_03 = { 0x6cb71c2c, 0x9812, 0x4540, { 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
66 /* see [MS-OXRPC] Appendix A: Full IDL, http://msdn.microsoft.com/en-us/library/ee217991%28v=exchg.80%29.aspx */
67 static e_guid_t uuid_asyncemsmdb = { 0x5261574a, 0x4572, 0x206e,
68 { 0xb2, 0x68, 0x6b, 0x19, 0x92, 0x13, 0xb4, 0xe4 } };
70 static const value_string pckt_vals[] = {
71 { PDU_REQ, "Request"},
73 { PDU_RESP, "Response"},
74 { PDU_FAULT, "Fault"},
75 { PDU_WORKING, "Working"},
76 { PDU_NOCALL, "Nocall"},
77 { PDU_REJECT, "Reject"},
79 { PDU_CL_CANCEL, "Cl_cancel"},
81 { PDU_CANCEL_ACK, "Cancel_ack"},
83 { PDU_BIND_ACK, "Bind_ack"},
84 { PDU_BIND_NAK, "Bind_nak"},
85 { PDU_ALTER, "Alter_context"},
86 { PDU_ALTER_ACK, "Alter_context_resp"},
87 { PDU_AUTH3, "AUTH3"},
88 { PDU_SHUTDOWN, "Shutdown"},
89 { PDU_CO_CANCEL, "Co_cancel"},
90 { PDU_ORPHANED, "Orphaned"},
91 { PDU_RTS, "RPC-over-HTTP RTS"},
95 static const value_string drep_byteorder_vals[] = {
97 { 1, "Little-endian" },
101 static const value_string drep_character_vals[] = {
107 #define DCE_RPC_DREP_FP_IEEE 0
108 #define DCE_RPC_DREP_FP_VAX 1
109 #define DCE_RPC_DREP_FP_CRAY 2
110 #define DCE_RPC_DREP_FP_IBM 3
112 static const value_string drep_fp_vals[] = {
113 { DCE_RPC_DREP_FP_IEEE, "IEEE" },
114 { DCE_RPC_DREP_FP_VAX, "VAX" },
115 { DCE_RPC_DREP_FP_CRAY, "Cray" },
116 { DCE_RPC_DREP_FP_IBM, "IBM" },
121 * Authentication services.
123 static const value_string authn_protocol_vals[] = {
124 { DCE_C_RPC_AUTHN_PROTOCOL_NONE, "None" },
125 { DCE_C_RPC_AUTHN_PROTOCOL_KRB5, "Kerberos 5" },
126 { DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO, "SPNEGO" },
127 { DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP, "NTLMSSP" },
128 { DCE_C_RPC_AUTHN_PROTOCOL_GSS_SCHANNEL, "SCHANNEL SSP" },
129 { DCE_C_RPC_AUTHN_PROTOCOL_GSS_KERBEROS, "Kerberos SSP" },
130 { DCE_C_RPC_AUTHN_PROTOCOL_DPA,
131 "Distributed Password Authentication SSP"},
132 { DCE_C_RPC_AUTHN_PROTOCOL_MSN, "MSN SSP"},
133 { DCE_C_RPC_AUTHN_PROTOCOL_DIGEST, "Digest SSP"},
134 { DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN, "NETLOGON Secure Channel" },
135 { DCE_C_RPC_AUTHN_PROTOCOL_MQ, "MSMQ SSP"},
142 static const value_string authn_level_vals[] = {
143 { DCE_C_AUTHN_LEVEL_NONE, "None" },
144 { DCE_C_AUTHN_LEVEL_CONNECT, "Connect" },
145 { DCE_C_AUTHN_LEVEL_CALL, "Call" },
146 { DCE_C_AUTHN_LEVEL_PKT, "Packet" },
147 { DCE_C_AUTHN_LEVEL_PKT_INTEGRITY, "Packet integrity" },
148 { DCE_C_AUTHN_LEVEL_PKT_PRIVACY, "Packet privacy" },
153 * Flag bits in first flag field in connectionless PDU header.
155 #define PFCL1_RESERVED_01 0x01 /* Reserved for use by implementations */
156 #define PFCL1_LASTFRAG 0x02 /* If set, the PDU is the last
157 * fragment of a multi-PDU
159 #define PFCL1_FRAG 0x04 /* If set, the PDU is a fragment of
160 a multi-PDU transmission */
161 #define PFCL1_NOFACK 0x08 /* If set, the receiver is not
162 * requested to send a `fack' PDU
163 * for the fragment */
164 #define PFCL1_MAYBE 0x10 /* If set, the PDU is for a `maybe'
166 #define PFCL1_IDEMPOTENT 0x20 /* If set, the PDU is for an idempotent
168 #define PFCL1_BROADCAST 0x40 /* If set, the PDU is for a broadcast
170 #define PFCL1_RESERVED_80 0x80 /* Reserved for use by implementations */
173 * Flag bits in second flag field in connectionless PDU header.
175 #define PFCL2_RESERVED_01 0x01 /* Reserved for use by implementations */
176 #define PFCL2_CANCEL_PENDING 0x02 /* Cancel pending at the call end */
177 #define PFCL2_RESERVED_04 0x04 /* Reserved for future use */
178 #define PFCL2_RESERVED_08 0x08 /* Reserved for future use */
179 #define PFCL2_RESERVED_10 0x10 /* Reserved for future use */
180 #define PFCL2_RESERVED_20 0x20 /* Reserved for future use */
181 #define PFCL2_RESERVED_40 0x40 /* Reserved for future use */
182 #define PFCL2_RESERVED_80 0x80 /* Reserved for future use */
185 * Flag bits in connection-oriented PDU header.
187 #define PFC_FIRST_FRAG 0x01 /* First fragment */
188 #define PFC_LAST_FRAG 0x02 /* Last fragment */
189 #define PFC_PENDING_CANCEL 0x04 /* Cancel was pending at sender */
190 #define PFC_RESERVED_1 0x08
191 #define PFC_CONC_MPX 0x10 /* supports concurrent multiplexing
192 * of a single connection. */
193 #define PFC_DID_NOT_EXECUTE 0x20 /* only meaningful on `fault' packet;
194 * if true, guaranteed call did not
196 #define PFC_MAYBE 0x40 /* `maybe' call semantics requested */
197 #define PFC_OBJECT_UUID 0x80 /* if true, a non-nil object UUID
198 * was specified in the handle, and
199 * is present in the optional object
200 * field. If false, the object field
204 * Tests whether a connection-oriented PDU is fragmented; returns TRUE if
205 * it's not fragmented (i.e., this is both the first *and* last fragment),
206 * and FALSE otherwise.
208 #define PFC_NOT_FRAGMENTED(hdr) \
209 ((hdr->flags&(PFC_FIRST_FRAG|PFC_LAST_FRAG)) == (PFC_FIRST_FRAG|PFC_LAST_FRAG))
212 * Presentation context negotiation result.
214 static const value_string p_cont_result_vals[] = {
216 { 1, "User rejection" },
217 { 2, "Provider rejection" },
218 { 3, "Negotiate ACK" }, /* [MS-RPCE] 2.2.2.4 */
223 * Presentation context negotiation rejection reasons.
225 static const value_string p_provider_reason_vals[] = {
226 { 0, "Reason not specified" },
227 { 1, "Abstract syntax not supported" },
228 { 2, "Proposed transfer syntaxes not supported" },
229 { 3, "Local limit exceeded" },
236 #define REASON_NOT_SPECIFIED 0
237 #define TEMPORARY_CONGESTION 1
238 #define LOCAL_LIMIT_EXCEEDED 2
239 #define CALLED_PADDR_UNKNOWN 3 /* not used */
240 #define PROTOCOL_VERSION_NOT_SUPPORTED 4
241 #define DEFAULT_CONTEXT_NOT_SUPPORTED 5 /* not used */
242 #define USER_DATA_NOT_READABLE 6 /* not used */
243 #define NO_PSAP_AVAILABLE 7 /* not used */
244 #define AUTH_TYPE_NOT_RECOGNIZED 8 /* [MS-RPCE] 2.2.2.5 */
245 #define INVALID_CHECKSUM 9 /* [MS-RPCE] 2.2.2.5 */
247 static const value_string reject_reason_vals[] = {
248 { REASON_NOT_SPECIFIED, "Reason not specified" },
249 { TEMPORARY_CONGESTION, "Temporary congestion" },
250 { LOCAL_LIMIT_EXCEEDED, "Local limit exceeded" },
251 { CALLED_PADDR_UNKNOWN, "Called paddr unknown" },
252 { PROTOCOL_VERSION_NOT_SUPPORTED, "Protocol version not supported" },
253 { DEFAULT_CONTEXT_NOT_SUPPORTED, "Default context not supported" },
254 { USER_DATA_NOT_READABLE, "User data not readable" },
255 { NO_PSAP_AVAILABLE, "No PSAP available" },
256 { AUTH_TYPE_NOT_RECOGNIZED, "Authentication type not recognized" },
257 { INVALID_CHECKSUM, "Invalid checksum" },
262 * Reject status codes.
264 static const value_string reject_status_vals[] = {
265 { 0, "Stub-defined exception" },
266 { 0x00000001, "nca_s_fault_other" },
267 { 0x00000005, "nca_s_fault_access_denied" },
268 { 0x000006f7, "nca_s_fault_ndr" },
269 { 0x000006d8, "nca_s_fault_cant_perform" },
270 { 0x1c000001, "nca_s_fault_int_div_by_zero" },
271 { 0x1c000002, "nca_s_fault_addr_error" },
272 { 0x1c000003, "nca_s_fault_fp_div_zero" },
273 { 0x1c000004, "nca_s_fault_fp_underflow" },
274 { 0x1c000005, "nca_s_fault_fp_overflow" },
275 { 0x1c000006, "nca_s_fault_invalid_tag" },
276 { 0x1c000007, "nca_s_fault_invalid_bound" },
277 { 0x1c000008, "nca_rpc_version_mismatch" },
278 { 0x1c000009, "nca_unspec_reject" },
279 { 0x1c00000a, "nca_s_bad_actid" },
280 { 0x1c00000b, "nca_who_are_you_failed" },
281 { 0x1c00000c, "nca_manager_not_entered" },
282 { 0x1c00000d, "nca_s_fault_cancel" },
283 { 0x1c00000e, "nca_s_fault_ill_inst" },
284 { 0x1c00000f, "nca_s_fault_fp_error" },
285 { 0x1c000010, "nca_s_fault_int_overflow" },
286 { 0x1c000014, "nca_s_fault_pipe_empty" },
287 { 0x1c000015, "nca_s_fault_pipe_closed" },
288 { 0x1c000016, "nca_s_fault_pipe_order" },
289 { 0x1c000017, "nca_s_fault_pipe_discipline" },
290 { 0x1c000018, "nca_s_fault_pipe_comm_error" },
291 { 0x1c000019, "nca_s_fault_pipe_memory" },
292 { 0x1c00001a, "nca_s_fault_context_mismatch" },
293 { 0x1c00001b, "nca_s_fault_remote_no_memory" },
294 { 0x1c00001c, "nca_invalid_pres_context_id" },
295 { 0x1c00001d, "nca_unsupported_authn_level" },
296 { 0x1c00001f, "nca_invalid_checksum" },
297 { 0x1c000020, "nca_invalid_crc" },
298 { 0x1c000021, "ncs_s_fault_user_defined" },
299 { 0x1c000022, "nca_s_fault_tx_open_failed" },
300 { 0x1c000023, "nca_s_fault_codeset_conv_error" },
301 { 0x1c000024, "nca_s_fault_object_not_found" },
302 { 0x1c000025, "nca_s_fault_no_client_stub" },
303 { 0x1c010002, "nca_op_rng_error" },
304 { 0x1c010003, "nca_unk_if"},
305 { 0x1c010006, "nca_wrong_boot_time" },
306 { 0x1c010009, "nca_s_you_crashed" },
307 { 0x1c01000b, "nca_proto_error" },
308 { 0x1c010013, "nca_out_args_too_big" },
309 { 0x1c010014, "nca_server_too_busy" },
310 { 0x1c010017, "nca_unsupported_type" },
311 /* MS Windows specific values
312 * see: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/system_error_codes__1700-3999_.asp
313 * and: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/seccrypto/security/common_hresult_values.asp
314 * and: http://www.megos.ch/support/doserrors.txt
316 * XXX - we might need a way to dynamically add entries here, as higher layer protocols use these values too,
317 * at least MS protocols (like DCOM) do it that way ... */
318 { 0x80004001, "E_NOTIMPL" },
319 { 0x80004003, "E_POINTER" },
320 { 0x80004004, "E_ABORT" },
321 { 0x8000FFFF, "E_UNEXPECTED" },
322 { 0x80010105, "RPC_E_SERVERFAULT" },
323 { 0x80010108, "RPC_E_DISCONNECTED" },
324 { 0x80010113, "RPC_E_INVALID_IPID" },
325 { 0x8001011F, "RPC_E_TIMEOUT" },
326 { 0x80020003, "DISP_E_MEMBERNOTFOUND" },
327 { 0x80020006, "DISP_E_UNKNOWNNAME" },
328 { 0x8002000E, "DISP_E_BADPARAMCOUNT" },
329 { 0x8004CB00, "CBA_E_MALFORMED" },
330 { 0x8004CB01, "CBA_E_UNKNOWNOBJECT" },
331 { 0x8004CB05, "CBA_E_INVALIDID" },
332 { 0x8004CB09, "CBA_E_INVALIDCOOKIE" },
333 { 0x8004CB0B, "CBA_E_QOSTYPEUNSUPPORTED" },
334 { 0x8004CB0C, "CBA_E_QOSVALUEUNSUPPORTED" },
335 { 0x8004CB0F, "CBA_E_NOTAPPLICABLE" },
336 { 0x8004CB12, "CBA_E_LIMITVIOLATION" },
337 { 0x8004CB13, "CBA_E_QOSTYPENOTAPPLICABLE" },
338 { 0x8004CB18, "CBA_E_OUTOFPARTNERACCOS" },
339 { 0x8004CB1C, "CBA_E_FLAGUNSUPPORTED" },
340 { 0x8004CB23, "CBA_E_FRAMECOUNTUNSUPPORTED" },
341 { 0x8004CB25, "CBA_E_MODECHANGE" },
342 { 0x8007000E, "E_OUTOFMEMORY" },
343 { 0x80070057, "E_INVALIDARG" },
344 { 0x800706d1, "RPC_S_PROCNUM_OUT_OF_RANGE" },
345 { 0x80070776, "OR_INVALID_OXID" },
353 #define RTS_FLAG_NONE 0x0000
354 #define RTS_FLAG_PING 0x0001
355 #define RTS_FLAG_OTHER_CMD 0x0002
356 #define RTS_FLAG_RECYCLE_CHANNEL 0x0004
357 #define RTS_FLAG_IN_CHANNEL 0x0008
358 #define RTS_FLAG_OUT_CHANNEL 0x0010
359 #define RTS_FLAG_EOF 0x0020
360 #define RTS_FLAG_ECHO 0x0040
366 #define RTS_CMD_RECEIVEWINDOWSIZE 0x0
367 #define RTS_CMD_FLOWCONTROLACK 0x1
368 #define RTS_CMD_CONNECTIONTIMEOUT 0x2
369 #define RTS_CMD_COOKIE 0x3
370 #define RTS_CMD_CHANNELLIFETIME 0x4
371 #define RTS_CMD_CLIENTKEEPALIVE 0x5
372 #define RTS_CMD_VERSION 0x6
373 #define RTS_CMD_EMPTY 0x7
374 #define RTS_CMD_PADDING 0x8
375 #define RTS_CMD_NEGATIVEANCE 0x9
376 #define RTS_CMD_ANCE 0xA
377 #define RTS_CMD_CLIENTADDRESS 0xB
378 #define RTS_CMD_ASSOCIATIONGROUPID 0xC
379 #define RTS_CMD_DESTINATION 0xD
380 #define RTS_CMD_PINGTRAFFICSENTNOTIFY 0xE
382 static const value_string rts_command_vals[] = {
383 { RTS_CMD_RECEIVEWINDOWSIZE, "ReceiveWindowSize" },
384 { RTS_CMD_FLOWCONTROLACK, "FlowControlAck" },
385 { RTS_CMD_CONNECTIONTIMEOUT, "ConnectionTimeOut" },
386 { RTS_CMD_COOKIE, "Cookie" },
387 { RTS_CMD_CHANNELLIFETIME, "ChannelLifetime" },
388 { RTS_CMD_CLIENTKEEPALIVE, "ClientKeepalive" },
389 { RTS_CMD_VERSION, "Version" },
390 { RTS_CMD_EMPTY, "Empty" },
391 { RTS_CMD_PADDING, "Padding" },
392 { RTS_CMD_NEGATIVEANCE, "NegativeANCE" },
393 { RTS_CMD_ANCE, "ANCE" },
394 { RTS_CMD_CLIENTADDRESS, "ClientAddress" },
395 { RTS_CMD_ASSOCIATIONGROUPID, "AssociationGroupId" },
396 { RTS_CMD_DESTINATION, "Destination" },
397 { RTS_CMD_PINGTRAFFICSENTNOTIFY, "PingTrafficSentNotify" },
402 * RTS client address type
407 static const value_string rts_addresstype_vals[] = {
408 { RTS_IPV4, "IPV4" },
409 { RTS_IPV6, "IPV6" },
414 * RTS Forward destination
417 static const value_string rts_forward_destination_vals[] = {
419 { 0x1, "FDInProxy" },
421 { 0x3, "FDOutProxy" },
425 /* we need to keep track of what transport were used, ie what handle we came
426 * in through so we know what kind of pinfo->dce_smb_fid was passed to us.
428 /* Value of -1 is reserved for "not DCE packet" in packet_info.dcetransporttype. */
429 #define DCE_TRANSPORT_UNKNOWN 0
430 #define DCE_CN_TRANSPORT_SMBPIPE 1
433 static int proto_dcerpc = -1;
436 static int hf_dcerpc_request_in = -1;
437 static int hf_dcerpc_time = -1;
438 static int hf_dcerpc_response_in = -1;
439 static int hf_dcerpc_ver = -1;
440 static int hf_dcerpc_ver_minor = -1;
441 static int hf_dcerpc_packet_type = -1;
442 static int hf_dcerpc_cn_flags = -1;
443 static int hf_dcerpc_cn_flags_first_frag = -1;
444 static int hf_dcerpc_cn_flags_last_frag = -1;
445 static int hf_dcerpc_cn_flags_cancel_pending = -1;
446 static int hf_dcerpc_cn_flags_reserved = -1;
447 static int hf_dcerpc_cn_flags_mpx = -1;
448 static int hf_dcerpc_cn_flags_dne = -1;
449 static int hf_dcerpc_cn_flags_maybe = -1;
450 static int hf_dcerpc_cn_flags_object = -1;
451 static int hf_dcerpc_drep = -1;
452 int hf_dcerpc_drep_byteorder = -1;
453 int hf_dcerpc_ndr_padding = -1;
454 static int hf_dcerpc_drep_character = -1;
455 static int hf_dcerpc_drep_fp = -1;
456 static int hf_dcerpc_cn_frag_len = -1;
457 static int hf_dcerpc_cn_auth_len = -1;
458 static int hf_dcerpc_cn_call_id = -1;
459 static int hf_dcerpc_cn_max_xmit = -1;
460 static int hf_dcerpc_cn_max_recv = -1;
461 static int hf_dcerpc_cn_assoc_group = -1;
462 static int hf_dcerpc_cn_num_ctx_items = -1;
463 static int hf_dcerpc_cn_ctx_item = -1;
464 static int hf_dcerpc_cn_ctx_id = -1;
465 static int hf_dcerpc_cn_num_trans_items = -1;
466 static int hf_dcerpc_cn_bind_abstract_syntax = -1;
467 static int hf_dcerpc_cn_bind_if_id = -1;
468 static int hf_dcerpc_cn_bind_if_ver = -1;
469 static int hf_dcerpc_cn_bind_if_ver_minor = -1;
470 static int hf_dcerpc_cn_bind_trans_syntax = -1;
471 static int hf_dcerpc_cn_bind_trans_id = -1;
472 static int hf_dcerpc_cn_bind_trans_ver = -1;
473 static int hf_dcerpc_cn_bind_trans_btfn_01 = -1;
474 static int hf_dcerpc_cn_bind_trans_btfn_02 = -1;
475 static int hf_dcerpc_cn_alloc_hint = -1;
476 static int hf_dcerpc_cn_sec_addr_len = -1;
477 static int hf_dcerpc_cn_sec_addr = -1;
478 static int hf_dcerpc_cn_num_results = -1;
479 static int hf_dcerpc_cn_ack_result = -1;
480 static int hf_dcerpc_cn_ack_reason = -1;
481 static int hf_dcerpc_cn_ack_trans_id = -1;
482 static int hf_dcerpc_cn_ack_trans_ver = -1;
483 static int hf_dcerpc_cn_ack_btfn = -1;
484 static int hf_dcerpc_cn_reject_reason = -1;
485 static int hf_dcerpc_cn_num_protocols = -1;
486 static int hf_dcerpc_cn_protocol_ver_major = -1;
487 static int hf_dcerpc_cn_protocol_ver_minor = -1;
488 static int hf_dcerpc_cn_cancel_count = -1;
489 static int hf_dcerpc_cn_status = -1;
490 static int hf_dcerpc_cn_deseg_req = -1;
491 static int hf_dcerpc_cn_rts_flags = -1;
492 static int hf_dcerpc_cn_rts_flags_none = -1;
493 static int hf_dcerpc_cn_rts_flags_ping = -1;
494 static int hf_dcerpc_cn_rts_flags_other_cmd = -1;
495 static int hf_dcerpc_cn_rts_flags_recycle_channel = -1;
496 static int hf_dcerpc_cn_rts_flags_in_channel = -1;
497 static int hf_dcerpc_cn_rts_flags_out_channel = -1;
498 static int hf_dcerpc_cn_rts_flags_eof = -1;
499 static int hf_dcerpc_cn_rts_commands_nb = -1;
500 static int hf_dcerpc_cn_rts_command = -1;
501 static int hf_dcerpc_cn_rts_command_receivewindowsize = -1;
502 static int hf_dcerpc_cn_rts_command_fack_bytesreceived = -1;
503 static int hf_dcerpc_cn_rts_command_fack_availablewindow = -1;
504 static int hf_dcerpc_cn_rts_command_fack_channelcookie = -1;
505 static int hf_dcerpc_cn_rts_command_connectiontimeout = -1;
506 static int hf_dcerpc_cn_rts_command_cookie = -1;
507 static int hf_dcerpc_cn_rts_command_channellifetime = -1;
508 static int hf_dcerpc_cn_rts_command_clientkeepalive = -1;
509 static int hf_dcerpc_cn_rts_command_version = -1;
510 static int hf_dcerpc_cn_rts_command_conformancecount = -1;
511 static int hf_dcerpc_cn_rts_command_padding = -1;
512 static int hf_dcerpc_cn_rts_command_addrtype = -1;
513 static int hf_dcerpc_cn_rts_command_associationgroupid = -1;
514 static int hf_dcerpc_cn_rts_command_forwarddestination = -1;
515 static int hf_dcerpc_cn_rts_command_pingtrafficsentnotify = -1;
516 static int hf_dcerpc_auth_type = -1;
517 static int hf_dcerpc_auth_level = -1;
518 static int hf_dcerpc_auth_pad_len = -1;
519 static int hf_dcerpc_auth_rsrvd = -1;
520 static int hf_dcerpc_auth_ctx_id = -1;
521 static int hf_dcerpc_dg_flags1 = -1;
522 static int hf_dcerpc_dg_flags1_rsrvd_01 = -1;
523 static int hf_dcerpc_dg_flags1_last_frag = -1;
524 static int hf_dcerpc_dg_flags1_frag = -1;
525 static int hf_dcerpc_dg_flags1_nofack = -1;
526 static int hf_dcerpc_dg_flags1_maybe = -1;
527 static int hf_dcerpc_dg_flags1_idempotent = -1;
528 static int hf_dcerpc_dg_flags1_broadcast = -1;
529 static int hf_dcerpc_dg_flags1_rsrvd_80 = -1;
530 static int hf_dcerpc_dg_flags2 = -1;
531 static int hf_dcerpc_dg_flags2_rsrvd_01 = -1;
532 static int hf_dcerpc_dg_flags2_cancel_pending = -1;
533 static int hf_dcerpc_dg_flags2_rsrvd_04 = -1;
534 static int hf_dcerpc_dg_flags2_rsrvd_08 = -1;
535 static int hf_dcerpc_dg_flags2_rsrvd_10 = -1;
536 static int hf_dcerpc_dg_flags2_rsrvd_20 = -1;
537 static int hf_dcerpc_dg_flags2_rsrvd_40 = -1;
538 static int hf_dcerpc_dg_flags2_rsrvd_80 = -1;
539 static int hf_dcerpc_dg_serial_hi = -1;
540 static int hf_dcerpc_obj_id = -1;
541 static int hf_dcerpc_dg_if_id = -1;
542 static int hf_dcerpc_dg_act_id = -1;
543 static int hf_dcerpc_dg_serial_lo = -1;
544 static int hf_dcerpc_dg_ahint = -1;
545 static int hf_dcerpc_dg_ihint = -1;
546 static int hf_dcerpc_dg_frag_len = -1;
547 static int hf_dcerpc_dg_frag_num = -1;
548 static int hf_dcerpc_dg_auth_proto = -1;
549 static int hf_dcerpc_opnum = -1;
550 static int hf_dcerpc_dg_seqnum = -1;
551 static int hf_dcerpc_dg_server_boot = -1;
552 static int hf_dcerpc_dg_if_ver = -1;
553 static int hf_dcerpc_krb5_av_prot_level = -1;
554 static int hf_dcerpc_krb5_av_key_vers_num = -1;
555 static int hf_dcerpc_krb5_av_key_auth_verifier = -1;
556 static int hf_dcerpc_dg_cancel_vers = -1;
557 static int hf_dcerpc_dg_cancel_id = -1;
558 static int hf_dcerpc_dg_server_accepting_cancels = -1;
559 static int hf_dcerpc_dg_fack_vers = -1;
560 static int hf_dcerpc_dg_fack_window_size = -1;
561 static int hf_dcerpc_dg_fack_max_tsdu = -1;
562 static int hf_dcerpc_dg_fack_max_frag_size = -1;
563 static int hf_dcerpc_dg_fack_serial_num = -1;
564 static int hf_dcerpc_dg_fack_selack_len = -1;
565 static int hf_dcerpc_dg_fack_selack = -1;
566 static int hf_dcerpc_dg_status = -1;
567 static int hf_dcerpc_array_max_count = -1;
568 static int hf_dcerpc_array_offset = -1;
569 static int hf_dcerpc_array_actual_count = -1;
570 static int hf_dcerpc_op = -1;
571 static int hf_dcerpc_referent_id32 = -1;
572 static int hf_dcerpc_referent_id64 = -1;
573 static int hf_dcerpc_null_pointer = -1;
574 static int hf_dcerpc_fragments = -1;
575 static int hf_dcerpc_fragment = -1;
576 static int hf_dcerpc_fragment_overlap = -1;
577 static int hf_dcerpc_fragment_overlap_conflict = -1;
578 static int hf_dcerpc_fragment_multiple_tails = -1;
579 static int hf_dcerpc_fragment_too_long_fragment = -1;
580 static int hf_dcerpc_fragment_error = -1;
581 static int hf_dcerpc_fragment_count = -1;
582 static int hf_dcerpc_reassembled_in = -1;
583 static int hf_dcerpc_reassembled_length = -1;
584 static int hf_dcerpc_unknown_if_id = -1;
585 /* Generated from convert_proto_tree_add_text.pl */
586 static int hf_dcerpc_duplicate_ptr = -1;
587 static int hf_dcerpc_encrypted_stub_data = -1;
588 static int hf_dcerpc_decrypted_stub_data = -1;
589 static int hf_dcerpc_stub_data = -1;
590 static int hf_dcerpc_auth_padding = -1;
591 static int hf_dcerpc_auth_verifier = -1;
592 static int hf_dcerpc_auth_credentials = -1;
593 static int hf_dcerpc_fault_stub_data = -1;
594 static int hf_dcerpc_fragment_data = -1;
595 static int hf_dcerpc_cmd_client_ipv4 = -1;
596 static int hf_dcerpc_cmd_client_ipv6 = -1;
597 static int hf_dcerpc_authentication_verifier = -1;
599 static gint ett_dcerpc = -1;
600 static gint ett_dcerpc_cn_flags = -1;
601 static gint ett_dcerpc_cn_ctx = -1;
602 static gint ett_dcerpc_cn_iface = -1;
603 static gint ett_dcerpc_cn_trans_syntax = -1;
604 static gint ett_dcerpc_cn_trans_btfn = -1;
605 static gint ett_dcerpc_cn_rts_flags = -1;
606 static gint ett_dcerpc_cn_rts_command = -1;
607 static gint ett_dcerpc_cn_rts_pdu = -1;
608 static gint ett_dcerpc_drep = -1;
609 static gint ett_dcerpc_dg_flags1 = -1;
610 static gint ett_dcerpc_dg_flags2 = -1;
611 static gint ett_dcerpc_pointer_data = -1;
612 static gint ett_dcerpc_string = -1;
613 static gint ett_dcerpc_fragments = -1;
614 static gint ett_dcerpc_fragment = -1;
615 static gint ett_dcerpc_krb5_auth_verf = -1;
617 static expert_field ei_dcerpc_fragment_multiple = EI_INIT;
618 static expert_field ei_dcerpc_cn_status = EI_INIT;
619 static expert_field ei_dcerpc_fragment_reassembled = EI_INIT;
620 static expert_field ei_dcerpc_fragment = EI_INIT;
621 static expert_field ei_dcerpc_no_request_found = EI_INIT;
622 static expert_field ei_dcerpc_context_change = EI_INIT;
623 static expert_field ei_dcerpc_cn_ctx_id_no_bind = EI_INIT;
624 static expert_field ei_dcerpc_bind_not_acknowledged = EI_INIT;
625 static expert_field ei_dcerpc_verifier_unavailable = EI_INIT;
626 static expert_field ei_dcerpc_invalid_pdu_authentication_attempt = EI_INIT;
627 /* Generated from convert_proto_tree_add_text.pl */
628 static expert_field ei_dcerpc_long_frame = EI_INIT;
629 static expert_field ei_dcerpc_cn_rts_command = EI_INIT;
632 static GSList *decode_dcerpc_bindings = NULL;
634 * To keep track of ctx_id mappings.
636 * Every time we see a bind call we update this table.
637 * Note that we always specify a SMB FID. For non-SMB transports this
640 static GHashTable *dcerpc_binds = NULL;
642 typedef struct _dcerpc_bind_key {
643 conversation_t *conv;
645 guint64 transport_salt;
648 typedef struct _dcerpc_bind_value {
654 /* Extra data for DCERPC handling and tracking of context ids */
655 typedef struct _dcerpc_decode_as_data {
656 guint16 dcectxid; /**< Context ID (DCERPC-specific) */
657 int dcetransporttype; /**< Transport type
658 * Value -1 means "not a DCERPC packet"
660 guint64 dcetransportsalt; /**< fid: if transporttype==DCE_CN_TRANSPORT_SMBPIPE */
661 } dcerpc_decode_as_data;
663 static dcerpc_decode_as_data*
664 dcerpc_get_decode_data(packet_info* pinfo)
666 dcerpc_decode_as_data* data = (dcerpc_decode_as_data*)p_get_proto_data(pinfo->pool, pinfo, proto_dcerpc, 0);
669 data = wmem_new0(pinfo->pool, dcerpc_decode_as_data);
670 data->dcetransporttype = -1;
671 p_add_proto_data(pinfo->pool, pinfo, proto_dcerpc, 0, data);
678 * Registers a conversation/UUID binding association, so that
679 * we can invoke the proper sub-dissector for a given DCERPC
682 * @param binding all values needed to create and bind a new conversation
684 * @return Pointer to newly-added UUID/conversation binding.
686 static struct _dcerpc_bind_value *
687 dcerpc_add_conv_to_bind_table(decode_dcerpc_bind_values_t *binding)
689 dcerpc_bind_value *bind_value;
690 dcerpc_bind_key *key;
691 conversation_t *conv;
693 conv = find_conversation(
703 conv = conversation_new(
713 bind_value = (dcerpc_bind_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_value));
714 bind_value->uuid = binding->uuid;
715 bind_value->ver = binding->ver;
716 /* For now, assume all DCE/RPC we pick from "decode as" is using
717 standard ndr and not ndr64.
718 We should make this selectable from the dialog in the future
720 bind_value->transport = uuid_data_repr_proto;
722 key = (dcerpc_bind_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_key));
724 key->ctx_id = binding->ctx_id;
725 key->transport_salt = binding->transport_salt;
727 /* add this entry to the bind table */
728 g_hash_table_insert(dcerpc_binds, key, bind_value);
734 /* inject one of our bindings into the dcerpc binding table */
736 decode_dcerpc_inject_binding(gpointer data, gpointer user_data _U_)
738 dcerpc_add_conv_to_bind_table((decode_dcerpc_bind_values_t *) data);
741 /* inject all of our bindings into the dcerpc binding table */
743 decode_dcerpc_inject_bindings(void) {
744 g_slist_foreach(decode_dcerpc_bindings, decode_dcerpc_inject_binding, NULL /* user_data */);
749 decode_dcerpc_binding_free(void *binding_in)
751 decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t *)binding_in;
753 g_free((void *) binding->addr_a.data);
754 g_free((void *) binding->addr_b.data);
756 g_string_free(binding->ifname, TRUE);
761 dcerpc_decode_as_free(gpointer value)
763 decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t *)value;
765 decode_dcerpc_binding_free(binding);
768 /* removes all bindings */
770 decode_dcerpc_reset_all(void)
772 decode_dcerpc_bind_values_t *binding;
774 while (decode_dcerpc_bindings) {
775 binding = (decode_dcerpc_bind_values_t *)decode_dcerpc_bindings->data;
777 decode_dcerpc_binding_free(binding);
778 decode_dcerpc_bindings = g_slist_remove(
779 decode_dcerpc_bindings,
780 decode_dcerpc_bindings->data);
786 decode_dcerpc_add_show_list(decode_add_show_list_func func, gpointer user_data)
788 g_slist_foreach(decode_dcerpc_bindings, func, user_data);
792 dcerpc_prompt(packet_info *pinfo, gchar* result)
794 GString *str = g_string_new("Replace binding between:\r\n"),
795 *address_str = g_string_new("");
796 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
798 switch (pinfo->ptype) {
800 g_string_append(address_str, "Address: ToBeDone TCP port");
803 g_string_append(address_str, "Address: ToBeDone UDP port");
806 g_string_append(address_str, "Address: ToBeDone Unknown port type");
809 g_string_append_printf(str, "%s: %u\r\n", address_str->str, pinfo->srcport);
810 g_string_append(str, "&\r\n");
811 g_string_append_printf(str, "%s: %u\r\n", address_str->str, pinfo->destport);
812 g_string_append_printf(str, "&\r\nContext ID: %u\r\n", decode_data->dcectxid);
813 g_string_append_printf(str, "&\r\nSMB FID: %"G_GINT64_MODIFIER"u\r\n",
814 dcerpc_get_transport_salt(pinfo));
815 g_string_append(str, "with:\r\n");
817 g_strlcpy(result, str->str, MAX_DECODE_AS_PROMPT_LEN);
818 g_string_free(str, TRUE);
819 g_string_free(address_str, TRUE);
823 dcerpc_value(packet_info *pinfo)
825 decode_dcerpc_bind_values_t *binding;
826 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
829 binding = g_new(decode_dcerpc_bind_values_t,1);
830 copy_address(&binding->addr_a, &pinfo->src);
831 copy_address(&binding->addr_b, &pinfo->dst);
832 binding->ptype = pinfo->ptype;
833 binding->port_a = pinfo->srcport;
834 binding->port_b = pinfo->destport;
835 binding->ctx_id = decode_data->dcectxid;
836 binding->transport_salt = dcerpc_get_transport_salt(pinfo);
837 binding->ifname = NULL;
838 /*binding->uuid = NULL;*/
844 struct dcerpc_decode_as_populate
846 decode_as_add_to_list_func add_to_list;
851 decode_dcerpc_add_to_list(gpointer key, gpointer value, gpointer user_data)
853 struct dcerpc_decode_as_populate* populate = (struct dcerpc_decode_as_populate*)user_data;
855 /*dcerpc_uuid_key *k = key;*/
856 dcerpc_uuid_value *v = (dcerpc_uuid_value *)value;
858 if (strcmp(v->name, "(none)"))
859 populate->add_to_list("DCE-RPC", v->name, key, populate->ui_element);
863 dcerpc_populate_list(const gchar *table_name _U_, decode_as_add_to_list_func add_to_list, gpointer ui_element)
865 struct dcerpc_decode_as_populate populate;
867 populate.add_to_list = add_to_list;
868 populate.ui_element = ui_element;
870 g_hash_table_foreach(dcerpc_uuids, decode_dcerpc_add_to_list, &populate);
873 /* compare two bindings (except the interface related things, e.g. uuid) */
875 decode_dcerpc_binding_cmp(gconstpointer a, gconstpointer b)
877 const decode_dcerpc_bind_values_t *binding_a = (const decode_dcerpc_bind_values_t *)a;
878 const decode_dcerpc_bind_values_t *binding_b = (const decode_dcerpc_bind_values_t *)b;
881 /* don't compare uuid and ver! */
883 addresses_equal(&binding_a->addr_a, &binding_b->addr_a) &&
884 addresses_equal(&binding_a->addr_b, &binding_b->addr_b) &&
885 binding_a->ptype == binding_b->ptype &&
886 binding_a->port_a == binding_b->port_a &&
887 binding_a->port_b == binding_b->port_b &&
888 binding_a->ctx_id == binding_b->ctx_id &&
889 binding_a->transport_salt == binding_b->transport_salt)
899 /* remove a binding (looking the same way as the given one) */
901 decode_dcerpc_binding_reset(const char *name _U_, const gpointer pattern)
903 decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t*)pattern;
905 decode_dcerpc_bind_values_t *old_binding;
907 /* find the old binding (if it exists) */
908 le = g_slist_find_custom(decode_dcerpc_bindings,
910 decode_dcerpc_binding_cmp);
914 old_binding = (decode_dcerpc_bind_values_t *)le->data;
916 decode_dcerpc_bindings = g_slist_remove(decode_dcerpc_bindings, le->data);
918 g_free((void *) old_binding->addr_a.data);
919 g_free((void *) old_binding->addr_b.data);
920 g_string_free(old_binding->ifname, TRUE);
926 dcerpc_decode_as_change(const char *name, const gpointer pattern, gpointer handle, gchar* list_name)
928 decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t*)pattern;
929 decode_dcerpc_bind_values_t *stored_binding;
930 dcerpc_uuid_key *key = *((dcerpc_uuid_key**)handle);
933 binding->ifname = g_string_new(list_name);
934 binding->uuid = key->uuid;
935 binding->ver = key->ver;
937 /* remove a probably existing old binding */
938 decode_dcerpc_binding_reset(name, binding);
940 /* clone the new binding and append it to the list */
941 stored_binding = g_new(decode_dcerpc_bind_values_t,1);
942 *stored_binding = *binding;
943 copy_address(&stored_binding->addr_a, &binding->addr_a);
944 copy_address(&stored_binding->addr_b, &binding->addr_b);
945 stored_binding->ifname = g_string_new(binding->ifname->str);
947 decode_dcerpc_bindings = g_slist_append (decode_dcerpc_bindings, stored_binding);
952 static const fragment_items dcerpc_frag_items = {
953 &ett_dcerpc_fragments,
954 &ett_dcerpc_fragment,
956 &hf_dcerpc_fragments,
958 &hf_dcerpc_fragment_overlap,
959 &hf_dcerpc_fragment_overlap_conflict,
960 &hf_dcerpc_fragment_multiple_tails,
961 &hf_dcerpc_fragment_too_long_fragment,
962 &hf_dcerpc_fragment_error,
963 &hf_dcerpc_fragment_count,
965 &hf_dcerpc_reassembled_length,
966 /* Reassembled data field */
971 /* list of hooks to be called when init_protocols is done */
972 GHookList dcerpc_hooks_init_protos;
974 /* try to desegment big DCE/RPC packets over TCP? */
975 static gboolean dcerpc_cn_desegment = TRUE;
977 /* reassemble DCE/RPC fragments */
978 /* reassembly of cl dcerpc fragments will not work for the case where ONE frame
979 might contain multiple dcerpc fragments for different PDUs.
980 this case would be so unusual/weird so if you got captures like that:
983 reassembly of co dcerpc fragments will not work for the case where TCP/SMB frames
984 are coming in out of sequence, but that will hurt in a lot of other places as well.
986 static gboolean dcerpc_reassemble = TRUE;
987 static reassembly_table dcerpc_co_reassembly_table;
988 static reassembly_table dcerpc_cl_reassembly_table;
990 typedef struct _dcerpc_fragment_key {
995 } dcerpc_fragment_key;
998 dcerpc_fragment_hash(gconstpointer k)
1000 const dcerpc_fragment_key* key = (const dcerpc_fragment_key*) k;
1005 hash_val += key->id;
1006 hash_val += key->act_id.data1;
1007 hash_val += key->act_id.data2 << 16;
1008 hash_val += key->act_id.data3;
1014 dcerpc_fragment_equal(gconstpointer k1, gconstpointer k2)
1016 const dcerpc_fragment_key* key1 = (const dcerpc_fragment_key*) k1;
1017 const dcerpc_fragment_key* key2 = (const dcerpc_fragment_key*) k2;
1019 /*key.id is the first item to compare since item is most
1020 likely to differ between sessions, thus shortcircuiting
1021 the comparison of addresses.
1023 return (((key1->id == key2->id)
1024 && (addresses_equal(&key1->src, &key2->src))
1025 && (addresses_equal(&key1->dst, &key2->dst))
1026 && (memcmp (&key1->act_id, &key2->act_id, sizeof (e_guid_t)) == 0))
1030 /* allocate a persistent dcerpc fragment key to insert in the hash */
1032 dcerpc_fragment_temporary_key(const packet_info *pinfo, const guint32 id,
1035 dcerpc_fragment_key *key = g_slice_new(dcerpc_fragment_key);
1036 e_dce_dg_common_hdr_t *hdr = (e_dce_dg_common_hdr_t *)data;
1038 key->src = pinfo->src;
1039 key->dst = pinfo->dst;
1041 key->act_id = hdr->act_id;
1046 /* allocate a persistent dcerpc fragment key to insert in the hash */
1048 dcerpc_fragment_persistent_key(const packet_info *pinfo, const guint32 id,
1051 dcerpc_fragment_key *key = g_slice_new(dcerpc_fragment_key);
1052 e_dce_dg_common_hdr_t *hdr = (e_dce_dg_common_hdr_t *)data;
1054 copy_address(&key->src, &pinfo->src);
1055 copy_address(&key->dst, &pinfo->dst);
1057 key->act_id = hdr->act_id;
1063 dcerpc_fragment_free_temporary_key(gpointer ptr)
1065 dcerpc_fragment_key *key = (dcerpc_fragment_key *)ptr;
1068 g_slice_free(dcerpc_fragment_key, key);
1072 dcerpc_fragment_free_persistent_key(gpointer ptr)
1074 dcerpc_fragment_key *key = (dcerpc_fragment_key *)ptr;
1078 * Free up the copies of the addresses from the old key.
1080 g_free((gpointer)key->src.data);
1081 g_free((gpointer)key->dst.data);
1083 g_slice_free(dcerpc_fragment_key, key);
1087 static const reassembly_table_functions dcerpc_cl_reassembly_table_functions = {
1088 dcerpc_fragment_hash,
1089 dcerpc_fragment_equal,
1090 dcerpc_fragment_temporary_key,
1091 dcerpc_fragment_persistent_key,
1092 dcerpc_fragment_free_temporary_key,
1093 dcerpc_fragment_free_persistent_key
1097 dcerpc_reassemble_init(void)
1100 * XXX - addresses_ports_reassembly_table_functions?
1101 * Or can a single connection-oriented DCE RPC session persist
1102 * over multiple transport layer connections?
1104 reassembly_table_init(&dcerpc_co_reassembly_table,
1105 &addresses_reassembly_table_functions);
1106 reassembly_table_init(&dcerpc_cl_reassembly_table,
1107 &dcerpc_cl_reassembly_table_functions);
1111 * Authentication subdissectors. Used to dissect authentication blobs in
1112 * DCERPC binds, requests and responses.
1115 typedef struct _dcerpc_auth_subdissector {
1118 dcerpc_auth_subdissector_fns auth_fns;
1119 } dcerpc_auth_subdissector;
1121 static GSList *dcerpc_auth_subdissector_list;
1123 static dcerpc_auth_subdissector_fns *get_auth_subdissector_fns(
1124 guint8 auth_level, guint8 auth_type)
1129 for (i = 0; (data = g_slist_nth_data(dcerpc_auth_subdissector_list, i)); i++) {
1130 dcerpc_auth_subdissector *asd = (dcerpc_auth_subdissector *)data;
1132 if ((asd->auth_level == auth_level) &&
1133 (asd->auth_type == auth_type))
1134 return &asd->auth_fns;
1140 void register_dcerpc_auth_subdissector(guint8 auth_level, guint8 auth_type,
1141 dcerpc_auth_subdissector_fns *fns)
1143 dcerpc_auth_subdissector *d;
1145 if (get_auth_subdissector_fns(auth_level, auth_type))
1148 d = (dcerpc_auth_subdissector *)g_malloc(sizeof(dcerpc_auth_subdissector));
1150 d->auth_level = auth_level;
1151 d->auth_type = auth_type;
1152 memcpy(&d->auth_fns, fns, sizeof(dcerpc_auth_subdissector_fns));
1154 dcerpc_auth_subdissector_list = g_slist_append(dcerpc_auth_subdissector_list, d);
1157 /* Hand off verifier data to a registered dissector */
1159 static void dissect_auth_verf(tvbuff_t *auth_tvb, packet_info *pinfo,
1161 dcerpc_auth_subdissector_fns *auth_fns,
1162 e_dce_cn_common_hdr_t *hdr,
1163 dcerpc_auth_info *auth_info)
1165 dcerpc_dissect_fnct_t *fn = NULL;
1166 /* XXX - "stub" a fake DCERPC INFO STRUCTURE
1167 If a dcerpc_info is really needed, update
1168 the call stacks to include it
1170 FAKE_DCERPC_INFO_STRUCTURE
1172 switch (hdr->ptype) {
1175 fn = auth_fns->bind_fn;
1179 fn = auth_fns->bind_ack_fn;
1182 fn = auth_fns->auth3_fn;
1185 fn = auth_fns->req_verf_fn;
1188 fn = auth_fns->resp_verf_fn;
1192 /* Don't know how to handle authentication data in this
1194 proto_tree_add_expert_format(tree, pinfo, &ei_dcerpc_invalid_pdu_authentication_attempt,
1196 "Don't know how to dissect authentication data for %s pdu type",
1197 val_to_str(hdr->ptype, pckt_vals, "Unknown (%u)"));
1203 fn(auth_tvb, 0, pinfo, tree, &di, hdr->drep);
1205 proto_tree_add_expert_format(tree, pinfo, &ei_dcerpc_verifier_unavailable,
1206 auth_tvb, 0, hdr->auth_len,
1207 "%s Verifier unavailable",
1208 val_to_str(auth_info->auth_type,
1209 authn_protocol_vals,
1214 /* Hand off payload data to a registered dissector */
1216 static tvbuff_t *decode_encrypted_data(tvbuff_t *data_tvb,
1219 dcerpc_auth_subdissector_fns *auth_fns,
1220 gboolean is_request,
1221 dcerpc_auth_info *auth_info)
1223 dcerpc_decode_data_fnct_t *fn;
1226 fn = auth_fns->req_data_fn;
1228 fn = auth_fns->resp_data_fn;
1231 return fn(data_tvb, auth_tvb, 0, pinfo, auth_info);
1240 /* the registered subdissectors */
1241 GHashTable *dcerpc_uuids = NULL;
1244 dcerpc_uuid_equal(gconstpointer k1, gconstpointer k2)
1246 const dcerpc_uuid_key *key1 = (const dcerpc_uuid_key *)k1;
1247 const dcerpc_uuid_key *key2 = (const dcerpc_uuid_key *)k2;
1248 return ((memcmp(&key1->uuid, &key2->uuid, sizeof (e_guid_t)) == 0)
1249 && (key1->ver == key2->ver));
1253 dcerpc_uuid_hash(gconstpointer k)
1255 const dcerpc_uuid_key *key = (const dcerpc_uuid_key *)k;
1256 /* This isn't perfect, but the Data1 part of these is almost always
1258 return key->uuid.data1;
1262 dcerpc_init_uuid(int proto, int ett, e_guid_t *uuid, guint16 ver,
1263 dcerpc_sub_dissector *procs, int opnum_hf)
1265 dcerpc_uuid_key *key = (dcerpc_uuid_key *)g_malloc(sizeof (*key));
1266 dcerpc_uuid_value *value = (dcerpc_uuid_value *)g_malloc(sizeof (*value));
1267 header_field_info *hf_info;
1268 module_t *samr_module;
1269 const char *filter_name = proto_get_protocol_filter_name(proto);
1274 value->proto = find_protocol_by_id(proto);
1275 value->proto_id = proto;
1277 value->name = proto_get_protocol_short_name(value->proto);
1278 value->procs = procs;
1279 value->opnum_hf = opnum_hf;
1281 g_hash_table_insert(dcerpc_uuids, key, value);
1283 hf_info = proto_registrar_get_nth(opnum_hf);
1284 hf_info->strings = value_string_from_subdissectors(procs);
1286 /* add this GUID to the global name resolving */
1287 guids_add_uuid(uuid, proto_get_protocol_short_name(value->proto));
1289 /* Register the samr.nt_password preference as obsolete */
1290 /* This should be in packet-dcerpc-samr.c */
1291 if (strcmp(filter_name, "samr") == 0) {
1292 samr_module = prefs_register_protocol(proto, NULL);
1293 prefs_register_obsolete_preference(samr_module, "nt_password");
1297 /* Function to find the name of a registered protocol
1298 * or NULL if the protocol/version is not known to wireshark.
1301 dcerpc_get_proto_name(e_guid_t *uuid, guint16 ver)
1303 dcerpc_uuid_key key;
1304 dcerpc_uuid_value *sub_proto;
1308 if (!(sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key))) {
1311 return sub_proto->name;
1314 /* Function to find the opnum hf-field of a registered protocol
1315 * or -1 if the protocol/version is not known to wireshark.
1318 dcerpc_get_proto_hf_opnum(e_guid_t *uuid, guint16 ver)
1320 dcerpc_uuid_key key;
1321 dcerpc_uuid_value *sub_proto;
1325 if (!(sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key))) {
1328 return sub_proto->opnum_hf;
1331 /* Create a value_string consisting of DCERPC opnum and name from a
1332 subdissector array. */
1334 value_string *value_string_from_subdissectors(dcerpc_sub_dissector *sd)
1336 value_string *vs = NULL;
1341 for (i = 0; sd[i].name; i++) {
1343 vs[i].value = sd[i].num;
1344 vs[i].strptr = sd[i].name;
1350 vs = (value_string *)wmem_alloc(wmem_epan_scope(), (num_sd + 1) * sizeof(value_string));
1354 vs[num_sd].value = 0;
1355 vs[num_sd].strptr = NULL;
1360 /* Function to find the subdissector table of a registered protocol
1361 * or NULL if the protocol/version is not known to wireshark.
1363 dcerpc_sub_dissector *
1364 dcerpc_get_proto_sub_dissector(e_guid_t *uuid, guint16 ver)
1366 dcerpc_uuid_key key;
1367 dcerpc_uuid_value *sub_proto;
1371 if (!(sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key))) {
1374 return sub_proto->procs;
1380 dcerpc_bind_equal(gconstpointer k1, gconstpointer k2)
1382 const dcerpc_bind_key *key1 = (const dcerpc_bind_key *)k1;
1383 const dcerpc_bind_key *key2 = (const dcerpc_bind_key *)k2;
1384 return ((key1->conv == key2->conv)
1385 && (key1->ctx_id == key2->ctx_id)
1386 && (key1->transport_salt == key2->transport_salt));
1390 dcerpc_bind_hash(gconstpointer k)
1392 const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
1395 hash = GPOINTER_TO_UINT(key->conv);
1396 hash += key->ctx_id;
1397 /* sizeof(guint) might be smaller than sizeof(guint64) */
1398 hash += (guint)key->transport_salt;
1399 hash += (guint)(key->transport_salt << sizeof(guint));
1405 * To keep track of callid mappings. Should really use some generic
1406 * conversation support instead.
1408 static GHashTable *dcerpc_cn_calls = NULL;
1409 static GHashTable *dcerpc_dg_calls = NULL;
1411 typedef struct _dcerpc_cn_call_key {
1412 conversation_t *conv;
1414 guint64 transport_salt;
1415 } dcerpc_cn_call_key;
1417 typedef struct _dcerpc_dg_call_key {
1418 conversation_t *conv;
1421 } dcerpc_dg_call_key;
1425 dcerpc_cn_call_equal(gconstpointer k1, gconstpointer k2)
1427 const dcerpc_cn_call_key *key1 = (const dcerpc_cn_call_key *)k1;
1428 const dcerpc_cn_call_key *key2 = (const dcerpc_cn_call_key *)k2;
1429 return ((key1->conv == key2->conv)
1430 && (key1->call_id == key2->call_id)
1431 && (key1->transport_salt == key2->transport_salt));
1435 dcerpc_dg_call_equal(gconstpointer k1, gconstpointer k2)
1437 const dcerpc_dg_call_key *key1 = (const dcerpc_dg_call_key *)k1;
1438 const dcerpc_dg_call_key *key2 = (const dcerpc_dg_call_key *)k2;
1439 return ((key1->conv == key2->conv)
1440 && (key1->seqnum == key2->seqnum)
1441 && ((memcmp(&key1->act_id, &key2->act_id, sizeof (e_guid_t)) == 0)));
1445 dcerpc_cn_call_hash(gconstpointer k)
1447 const dcerpc_cn_call_key *key = (const dcerpc_cn_call_key *)k;
1450 hash = GPOINTER_TO_UINT(key->conv);
1451 hash += key->call_id;
1452 /* sizeof(guint) might be smaller than sizeof(guint64) */
1453 hash += (guint)key->transport_salt;
1454 hash += (guint)(key->transport_salt << sizeof(guint));
1460 dcerpc_dg_call_hash(gconstpointer k)
1462 const dcerpc_dg_call_key *key = (const dcerpc_dg_call_key *)k;
1463 return (GPOINTER_TO_UINT(key->conv) + key->seqnum + key->act_id.data1
1464 + (key->act_id.data2 << 16) + key->act_id.data3
1465 + (key->act_id.data4[0] << 24) + (key->act_id.data4[1] << 16)
1466 + (key->act_id.data4[2] << 8) + (key->act_id.data4[3] << 0)
1467 + (key->act_id.data4[4] << 24) + (key->act_id.data4[5] << 16)
1468 + (key->act_id.data4[6] << 8) + (key->act_id.data4[7] << 0));
1471 /* to keep track of matched calls/responses
1472 this one uses the same value struct as calls, but the key is the frame id
1473 and call id; there can be more than one call in a frame.
1475 XXX - why not just use the same keys as are used for calls?
1478 static GHashTable *dcerpc_matched = NULL;
1480 typedef struct _dcerpc_matched_key {
1483 } dcerpc_matched_key;
1486 dcerpc_matched_equal(gconstpointer k1, gconstpointer k2)
1488 const dcerpc_matched_key *key1 = (const dcerpc_matched_key *)k1;
1489 const dcerpc_matched_key *key2 = (const dcerpc_matched_key *)k2;
1490 return ((key1->frame == key2->frame)
1491 && (key1->call_id == key2->call_id));
1495 dcerpc_matched_hash(gconstpointer k)
1497 const dcerpc_matched_key *key = (const dcerpc_matched_key *)k;
1502 uuid_equal(e_guid_t *uuid1, e_guid_t *uuid2)
1504 if( (uuid1->data1 != uuid2->data1)
1505 ||(uuid1->data2 != uuid2->data2)
1506 ||(uuid1->data3 != uuid2->data3)
1507 ||(uuid1->data4[0] != uuid2->data4[0])
1508 ||(uuid1->data4[1] != uuid2->data4[1])
1509 ||(uuid1->data4[2] != uuid2->data4[2])
1510 ||(uuid1->data4[3] != uuid2->data4[3])
1511 ||(uuid1->data4[4] != uuid2->data4[4])
1512 ||(uuid1->data4[5] != uuid2->data4[5])
1513 ||(uuid1->data4[6] != uuid2->data4[6])
1514 ||(uuid1->data4[7] != uuid2->data4[7]) ){
1521 dcerpcstat_init(struct register_srt* srt, GArray* srt_array, srt_gui_init_cb gui_callback, void* gui_data)
1523 dcerpcstat_tap_data_t* tap_data = (dcerpcstat_tap_data_t*)get_srt_table_param_data(srt);
1524 srt_stat_table *dcerpc_srt_table;
1526 dcerpc_sub_dissector *procs;
1528 DISSECTOR_ASSERT(tap_data);
1530 hf_opnum = dcerpc_get_proto_hf_opnum(&tap_data->uuid, tap_data->ver);
1531 procs = dcerpc_get_proto_sub_dissector(&tap_data->uuid, tap_data->ver);
1534 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);
1536 dcerpc_srt_table = init_srt_table(tap_data->prog, NULL, srt_array, tap_data->num_procedures, NULL, NULL, gui_callback, gui_data, tap_data);
1539 for(i=0;i<tap_data->num_procedures;i++){
1541 const char *proc_name;
1543 proc_name = "unknown";
1544 for(j=0;procs[j].name;j++)
1546 if (procs[j].num == i)
1548 proc_name = procs[j].name;
1552 init_srt_table_row(dcerpc_srt_table, i, proc_name);
1557 dcerpcstat_packet(void *pss, packet_info *pinfo, epan_dissect_t *edt _U_, const void *prv)
1560 srt_stat_table *dcerpc_srt_table;
1561 srt_data_t *data = (srt_data_t *)pss;
1562 const dcerpc_info *ri = (dcerpc_info *)prv;
1563 dcerpcstat_tap_data_t* tap_data;
1565 dcerpc_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
1566 tap_data = (dcerpcstat_tap_data_t*)dcerpc_srt_table->table_specific_data;
1571 if(!ri->call_data->req_frame){
1572 /* we have not seen the request so we don't know the delta*/
1575 if(ri->call_data->opnum >= tap_data->num_procedures){
1576 /* don't handle this since it's outside of known table */
1580 /* we are only interested in reply packets */
1581 if(ri->ptype != PDU_RESP){
1585 /* we are only interested in certain program/versions */
1586 if( (!uuid_equal( (&ri->call_data->uuid), (&tap_data->uuid)))
1587 ||(ri->call_data->ver != tap_data->ver)){
1591 add_srt_table_data(dcerpc_srt_table, ri->call_data->opnum, &ri->call_data->req_time, pinfo);
1597 dcerpcstat_param(register_srt_t* srt, const char* opt_arg, char** err)
1600 guint32 i, max_procs;
1601 dcerpcstat_tap_data_t* tap_data;
1602 guint d1,d2,d3,d40,d41,d42,d43,d44,d45,d46,d47;
1605 dcerpc_sub_dissector *procs;
1607 if (sscanf(opt_arg, ",%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x,%d.%d%n",
1608 &d1,&d2,&d3,&d40,&d41,&d42,&d43,&d44,&d45,&d46,&d47,&major,&minor,&pos) == 13)
1610 if ((major < 0) || (major > 65535)) {
1611 *err = g_strdup_printf("dcerpcstat_init() Major version number %d is invalid - must be positive and <= 65535", major);
1614 if ((minor < 0) || (minor > 65535)) {
1615 *err = g_strdup_printf("dcerpcstat_init() Minor version number %d is invalid - must be positive and <= 65535", minor);
1620 tap_data = g_new0(dcerpcstat_tap_data_t, 1);
1622 tap_data->uuid.data1 = d1;
1623 tap_data->uuid.data2 = d2;
1624 tap_data->uuid.data3 = d3;
1625 tap_data->uuid.data4[0] = d40;
1626 tap_data->uuid.data4[1] = d41;
1627 tap_data->uuid.data4[2] = d42;
1628 tap_data->uuid.data4[3] = d43;
1629 tap_data->uuid.data4[4] = d44;
1630 tap_data->uuid.data4[5] = d45;
1631 tap_data->uuid.data4[6] = d46;
1632 tap_data->uuid.data4[7] = d47;
1634 procs = dcerpc_get_proto_sub_dissector(&tap_data->uuid, ver);
1635 tap_data->prog = dcerpc_get_proto_name(&tap_data->uuid, ver);
1636 tap_data->ver = ver;
1638 for(i=0,max_procs=0;procs[i].name;i++)
1640 if(procs[i].num>max_procs)
1642 max_procs = procs[i].num;
1645 tap_data->num_procedures = max_procs+1;
1647 set_srt_table_param_data(srt, tap_data);
1651 *err = g_strdup_printf("<uuid>,<major version>.<minor version>[,<filter>]");
1659 * Utility functions. Modeled after packet-rpc.c
1663 dissect_dcerpc_uint8(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1664 proto_tree *tree, guint8 *drep,
1665 int hfindex, guint8 *pdata)
1669 data = tvb_get_guint8(tvb, offset);
1670 if (tree && hfindex != -1) {
1671 proto_tree_add_item(tree, hfindex, tvb, offset, 1, DREP_ENC_INTEGER(drep));
1679 dissect_dcerpc_uint16(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1680 proto_tree *tree, guint8 *drep,
1681 int hfindex, guint16 *pdata)
1685 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1686 ? tvb_get_letohs(tvb, offset)
1687 : tvb_get_ntohs(tvb, offset));
1689 if (tree && hfindex != -1) {
1690 proto_tree_add_item(tree, hfindex, tvb, offset, 2, DREP_ENC_INTEGER(drep));
1698 dissect_dcerpc_uint32(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1699 proto_tree *tree, guint8 *drep,
1700 int hfindex, guint32 *pdata)
1704 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1705 ? tvb_get_letohl(tvb, offset)
1706 : tvb_get_ntohl(tvb, offset));
1708 if (tree && hfindex != -1) {
1709 proto_tree_add_item(tree, hfindex, tvb, offset, 4, DREP_ENC_INTEGER(drep));
1716 /* handles 32 bit unix time_t */
1718 dissect_dcerpc_time_t(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1719 proto_tree *tree, guint8 *drep,
1720 int hfindex, guint32 *pdata)
1725 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1726 ? tvb_get_letohl(tvb, offset)
1727 : tvb_get_ntohl(tvb, offset));
1731 if (tree && hfindex != -1) {
1732 if (data == 0xffffffff) {
1733 /* special case, no time specified */
1734 proto_tree_add_time_format_value(tree, hfindex, tvb, offset, 4, &tv, "No time specified");
1736 proto_tree_add_time(tree, hfindex, tvb, offset, 4, &tv);
1746 dissect_dcerpc_uint64(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1747 proto_tree *tree, dcerpc_info *di, guint8 *drep,
1748 int hfindex, guint64 *pdata)
1752 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1753 ? tvb_get_letoh64(tvb, offset)
1754 : tvb_get_ntoh64(tvb, offset));
1756 if (tree && hfindex != -1) {
1757 header_field_info *hfinfo;
1759 /* This might be a field that is either 32bit, in NDR or
1760 64 bits in NDR64. So we must be careful and call the right
1763 hfinfo = proto_registrar_get_nth(hfindex);
1765 switch (hfinfo->type) {
1767 proto_tree_add_uint64(tree, hfindex, tvb, offset, 8, data);
1770 proto_tree_add_int64(tree, hfindex, tvb, offset, 8, data);
1773 /* The value is truncated to 32bits. 64bit values have only been
1774 seen on fuzz-tested files */
1775 DISSECTOR_ASSERT((di->call_data->flags & DCERPC_IS_NDR64) || (data <= G_MAXUINT32));
1776 proto_tree_add_uint(tree, hfindex, tvb, offset, 8, (guint32)data);
1786 dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1787 proto_tree *tree, guint8 *drep,
1788 int hfindex, gfloat *pdata)
1794 case(DCE_RPC_DREP_FP_IEEE):
1795 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1796 ? tvb_get_letohieee_float(tvb, offset)
1797 : tvb_get_ntohieee_float(tvb, offset));
1798 if (tree && hfindex != -1) {
1799 proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
1802 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
1803 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1804 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
1806 /* ToBeDone: non IEEE floating formats */
1807 /* Set data to a negative infinity value */
1809 if (tree && hfindex != -1) {
1810 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep[1]);
1820 dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1821 proto_tree *tree, guint8 *drep,
1822 int hfindex, gdouble *pdata)
1828 case(DCE_RPC_DREP_FP_IEEE):
1829 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1830 ? tvb_get_letohieee_double(tvb, offset)
1831 : tvb_get_ntohieee_double(tvb, offset));
1832 if (tree && hfindex != -1) {
1833 proto_tree_add_double(tree, hfindex, tvb, offset, 8, data);
1836 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
1837 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1838 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
1840 /* ToBeDone: non IEEE double formats */
1841 /* Set data to a negative infinity value */
1842 data = -G_MAXDOUBLE;
1843 if (tree && hfindex != -1) {
1844 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep[1]);
1854 dissect_dcerpc_uuid_t(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1855 proto_tree *tree, guint8 *drep,
1856 int hfindex, e_guid_t *pdata)
1861 if (drep[0] & DREP_LITTLE_ENDIAN) {
1862 tvb_get_letohguid(tvb, offset, (e_guid_t *) &uuid);
1864 tvb_get_ntohguid(tvb, offset, (e_guid_t *) &uuid);
1866 if (tree && hfindex != -1) {
1867 proto_tree_add_guid(tree, hfindex, tvb, offset, 16, (e_guid_t *) &uuid);
1877 * a couple simpler things
1880 dcerpc_tvb_get_ntohs(tvbuff_t *tvb, gint offset, guint8 *drep)
1882 if (drep[0] & DREP_LITTLE_ENDIAN) {
1883 return tvb_get_letohs(tvb, offset);
1885 return tvb_get_ntohs(tvb, offset);
1890 dcerpc_tvb_get_ntohl(tvbuff_t *tvb, gint offset, guint8 *drep)
1892 if (drep[0] & DREP_LITTLE_ENDIAN) {
1893 return tvb_get_letohl(tvb, offset);
1895 return tvb_get_ntohl(tvb, offset);
1900 dcerpc_tvb_get_uuid(tvbuff_t *tvb, gint offset, guint8 *drep, e_guid_t *uuid)
1902 if (drep[0] & DREP_LITTLE_ENDIAN) {
1903 tvb_get_letohguid(tvb, offset, (e_guid_t *) uuid);
1905 tvb_get_ntohguid(tvb, offset, (e_guid_t *) uuid);
1911 /* function to dissect a unidimensional conformant array */
1913 dissect_ndr_ucarray_core(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1914 proto_tree *tree, dcerpc_info *di, guint8 *drep,
1915 dcerpc_dissect_fnct_t *fnct_bytes,
1916 dcerpc_dissect_fnct_blk_t *fnct_block)
1920 int conformance_size = 4;
1922 if (di->call_data->flags & DCERPC_IS_NDR64) {
1923 conformance_size = 8;
1926 if (di->conformant_run) {
1929 /* conformant run, just dissect the max_count header */
1930 old_offset = offset;
1931 di->conformant_run = 0;
1932 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1933 hf_dcerpc_array_max_count, &val);
1934 di->array_max_count = (gint32)val;
1935 di->array_max_count_offset = offset-conformance_size;
1936 di->conformant_run = 1;
1937 di->conformant_eaten = offset-old_offset;
1939 /* we don't remember where in the bytestream this field was */
1940 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, conformance_size, di->array_max_count);
1942 /* real run, dissect the elements */
1944 old_offset = offset;
1945 offset = (*fnct_block)(tvb, offset, di->array_max_count,
1946 pinfo, tree, di, drep);
1947 if (offset <= old_offset)
1948 THROW(ReportedBoundsError);
1950 for (i=0 ;i<di->array_max_count; i++) {
1951 old_offset = offset;
1952 offset = (*fnct_bytes)(tvb, offset, pinfo, tree, di, drep);
1953 if (offset <= old_offset)
1954 THROW(ReportedBoundsError);
1963 dissect_ndr_ucarray_block(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1964 proto_tree *tree, dcerpc_info *di, guint8 *drep,
1965 dcerpc_dissect_fnct_blk_t *fnct)
1967 return dissect_ndr_ucarray_core(tvb, offset, pinfo, tree, di, drep, NULL, fnct);
1971 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1972 proto_tree *tree, dcerpc_info *di, guint8 *drep,
1973 dcerpc_dissect_fnct_t *fnct)
1975 return dissect_ndr_ucarray_core(tvb, offset, pinfo, tree, di, drep, fnct, NULL);
1978 /* function to dissect a unidimensional conformant and varying array
1979 * depending on the dissection function passed as a parameter,
1980 * content of the array will be dissected as a block or byte by byte
1983 dissect_ndr_ucvarray_core(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1984 proto_tree *tree, dcerpc_info *di, guint8 *drep,
1985 dcerpc_dissect_fnct_t *fnct_bytes,
1986 dcerpc_dissect_fnct_blk_t *fnct_block)
1990 int conformance_size = 4;
1992 if (di->call_data->flags & DCERPC_IS_NDR64) {
1993 conformance_size = 8;
1996 if (di->conformant_run) {
1999 /* conformant run, just dissect the max_count header */
2000 old_offset = offset;
2001 di->conformant_run = 0;
2002 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
2003 hf_dcerpc_array_max_count, &val);
2004 DISSECTOR_ASSERT(val <= G_MAXUINT32);
2005 di->array_max_count = (guint32)val;
2006 di->array_max_count_offset = offset-conformance_size;
2007 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
2008 hf_dcerpc_array_offset, &val);
2009 DISSECTOR_ASSERT(val <= G_MAXUINT32);
2010 di->array_offset = (guint32)val;
2011 di->array_offset_offset = offset-conformance_size;
2012 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
2013 hf_dcerpc_array_actual_count, &val);
2014 DISSECTOR_ASSERT(val <= G_MAXUINT32);
2015 di->array_actual_count = (guint32)val;
2016 di->array_actual_count_offset = offset-conformance_size;
2017 di->conformant_run = 1;
2018 di->conformant_eaten = offset-old_offset;
2020 /* we don't remember where in the bytestream these fields were */
2021 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, conformance_size, di->array_max_count);
2022 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, conformance_size, di->array_offset);
2023 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, conformance_size, di->array_actual_count);
2025 /* real run, dissect the elements */
2027 old_offset = offset;
2028 offset = (*fnct_block)(tvb, offset, di->array_actual_count,
2029 pinfo, tree, di, drep);
2030 if (offset <= old_offset)
2031 THROW(ReportedBoundsError);
2033 for (i=0 ;i<di->array_actual_count; i++) {
2034 old_offset = offset;
2035 offset = (*fnct_bytes)(tvb, offset, pinfo, tree, di, drep);
2036 if (offset <= old_offset)
2037 THROW(ReportedBoundsError);
2046 dissect_ndr_ucvarray_block(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2047 proto_tree *tree, dcerpc_info *di, guint8 *drep,
2048 dcerpc_dissect_fnct_blk_t *fnct)
2050 return dissect_ndr_ucvarray_core(tvb, offset, pinfo, tree, di, drep, NULL, fnct);
2054 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2055 proto_tree *tree, dcerpc_info *di, guint8 *drep,
2056 dcerpc_dissect_fnct_t *fnct)
2058 return dissect_ndr_ucvarray_core(tvb, offset, pinfo, tree, di, drep, fnct, NULL);
2060 /* function to dissect a unidimensional varying array */
2062 dissect_ndr_uvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2063 proto_tree *tree, dcerpc_info *di, guint8 *drep,
2064 dcerpc_dissect_fnct_t *fnct)
2068 int conformance_size = 4;
2070 if (di->call_data->flags & DCERPC_IS_NDR64) {
2071 conformance_size = 8;
2074 if (di->conformant_run) {
2077 /* conformant run, just dissect the max_count header */
2078 old_offset = offset;
2079 di->conformant_run = 0;
2080 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
2081 hf_dcerpc_array_offset, &val);
2082 DISSECTOR_ASSERT(val <= G_MAXUINT32);
2083 di->array_offset = (guint32)val;
2084 di->array_offset_offset = offset-conformance_size;
2085 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
2086 hf_dcerpc_array_actual_count, &val);
2087 DISSECTOR_ASSERT(val <= G_MAXUINT32);
2088 di->array_actual_count = (guint32)val;
2089 di->array_actual_count_offset = offset-conformance_size;
2090 di->conformant_run = 1;
2091 di->conformant_eaten = offset-old_offset;
2093 /* we don't remember where in the bytestream these fields were */
2094 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, conformance_size, di->array_offset);
2095 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, conformance_size, di->array_actual_count);
2097 /* real run, dissect the elements */
2098 for (i=0; i<di->array_actual_count; i++) {
2099 offset = (*fnct)(tvb, offset, pinfo, tree, di, drep);
2106 /* Dissect an string of bytes. This corresponds to
2107 IDL of the form '[string] byte *foo'.
2109 It can also be used for a conformant varying array of bytes if
2110 the contents of the array should be shown as a big blob, rather
2111 than showing each byte as an individual element.
2113 XXX - which of those is really the IDL type for, for example,
2114 the encrypted data in some MAPI packets? (Microsoft hasn't
2117 XXX - does this need to do all the conformant array stuff that
2118 "dissect_ndr_ucvarray()" does? These are presumably for strings
2119 that are conformant and varying - they're stored like conformant
2120 varying arrays of bytes. */
2122 dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo,
2123 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2127 if (di->conformant_run) {
2128 /* just a run to handle conformant arrays, no scalars to dissect */
2132 /* NDR array header */
2134 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
2135 hf_dcerpc_array_max_count, NULL);
2137 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
2138 hf_dcerpc_array_offset, NULL);
2140 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
2141 hf_dcerpc_array_actual_count, &len);
2143 DISSECTOR_ASSERT(len <= G_MAXUINT32);
2145 proto_tree_add_item(tree, di->hf_index, tvb, offset, (guint32)len,
2149 offset += (guint32)len;
2154 /* For dissecting arrays that are to be interpreted as strings. */
2156 /* Dissect an NDR conformant varying string of elements.
2157 The length of each element is given by the 'size_is' parameter;
2158 the elements are assumed to be characters or wide characters.
2160 XXX - does this need to do all the conformant array stuff that
2161 "dissect_ndr_ucvarray()" does? */
2163 dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2164 proto_tree *tree, dcerpc_info *di, guint8 *drep, int size_is,
2165 int hfindex, gboolean add_subtree, char **data)
2167 header_field_info *hfinfo;
2168 proto_item *string_item;
2169 proto_tree *string_tree;
2174 /* Make sure this really is a string field. */
2175 hfinfo = proto_registrar_get_nth(hfindex);
2176 DISSECTOR_ASSERT(hfinfo->type == FT_STRING);
2178 if (di->conformant_run) {
2179 /* just a run to handle conformant arrays, no scalars to dissect */
2184 string_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_dcerpc_string, &string_item,
2185 proto_registrar_get_name(hfindex));
2191 /* NDR array header */
2193 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
2194 hf_dcerpc_array_max_count, NULL);
2196 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
2197 hf_dcerpc_array_offset, NULL);
2199 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
2200 hf_dcerpc_array_actual_count, &len);
2202 /* The value is truncated to 32bits. 64bit values have only been
2203 seen on fuzztested files */
2204 buffer_len = size_is * (guint32)len;
2207 if (!di->no_align && (offset % size_is))
2208 offset += size_is - (offset % size_is);
2211 * "tvb_get_string_enc()" throws an exception if the entire string
2212 * isn't in the tvbuff. If the length is bogus, this should
2213 * keep us from trying to allocate an immensely large buffer.
2214 * (It won't help if the length is *valid* but immensely large,
2215 * but that's another matter; in any case, that would happen only
2216 * if we had an immensely large tvbuff....)
2218 * XXX - so why are we doing tvb_ensure_bytes_exist()?
2220 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
2221 if (size_is == sizeof(guint16)) {
2223 * Assume little-endian UTF-16.
2225 * XXX - is this always little-endian?
2227 s = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, buffer_len,
2228 ENC_UTF_16|ENC_LITTLE_ENDIAN);
2231 * XXX - what if size_is is neither 1 nor 2?
2233 s = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, buffer_len,
2234 DREP_ENC_CHAR(drep));
2236 if (tree && buffer_len)
2237 proto_tree_add_string(string_tree, hfindex, tvb, offset,
2240 if (string_item != NULL)
2241 proto_item_append_text(string_item, ": %s", s);
2246 offset += buffer_len;
2248 proto_item_set_end(string_item, tvb, offset);
2254 dissect_ndr_cstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2255 proto_tree *tree, dcerpc_info *di, guint8 *drep, int size_is,
2256 int hfindex, gboolean add_subtree, char **data)
2258 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep, size_is, hfindex, add_subtree, data);
2261 /* Dissect an conformant varying string of chars.
2262 This corresponds to IDL of the form '[string] char *foo'.
2264 XXX - at least according to the DCE RPC 1.1 spec, a string has
2265 a null terminator, which isn't necessary as a terminator for
2266 the transfer language (as there's a length), but is presumably
2267 there for the benefit of null-terminated-string languages
2268 such as C. Is this ever used for purely counted strings?
2269 (Not that it matters if it is.) */
2271 dissect_ndr_char_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2272 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2274 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep,
2275 sizeof(guint8), di->hf_index,
2279 /* Dissect a conformant varying string of wchars (wide characters).
2280 This corresponds to IDL of the form '[string] wchar *foo'
2282 XXX - at least according to the DCE RPC 1.1 spec, a string has
2283 a null terminator, which isn't necessary as a terminator for
2284 the transfer language (as there's a length), but is presumably
2285 there for the benefit of null-terminated-string languages
2286 such as C. Is this ever used for purely counted strings?
2287 (Not that it matters if it is.) */
2289 dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2290 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2292 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep,
2293 sizeof(guint16), di->hf_index,
2297 /* This function is aimed for PIDL usage and dissects a UNIQUE pointer to
2301 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)
2304 gint levels = CB_STR_ITEM_LEVELS(param);
2306 offset = dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep,
2310 if (!di->conformant_run) {
2311 /* Append string to COL_INFO */
2312 if (param & PIDL_SET_COL_INFO) {
2313 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", s);
2315 /* Save string to dcv->private_data */
2316 if ((param & PIDL_STR_SAVE)
2317 && (!pinfo->fd->flags.visited)) {
2318 dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2319 dcv->private_data = wmem_strdup(wmem_file_scope(), s);
2321 /* Append string to upper-level proto_items */
2322 if ((levels > 0) && tree && s && s[0]) {
2323 proto_item_append_text(tree, ": %s", s);
2324 tree = tree->parent;
2327 proto_item_append_text(tree, ": %s", s);
2328 tree = tree->parent;
2330 while (levels > 0) {
2331 proto_item_append_text(tree, " %s", s);
2332 tree = tree->parent;
2343 /* Dissect an NDR varying string of elements.
2344 The length of each element is given by the 'size_is' parameter;
2345 the elements are assumed to be characters or wide characters.
2348 dissect_ndr_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2349 proto_tree *tree, dcerpc_info *di, guint8 *drep, int size_is,
2350 int hfindex, gboolean add_subtree, char **data)
2352 header_field_info *hfinfo;
2353 proto_item *string_item;
2354 proto_tree *string_tree;
2359 /* Make sure this really is a string field. */
2360 hfinfo = proto_registrar_get_nth(hfindex);
2361 DISSECTOR_ASSERT(hfinfo->type == FT_STRING);
2363 if (di->conformant_run) {
2364 /* just a run to handle conformant arrays, no scalars to dissect */
2369 string_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_dcerpc_string, &string_item,
2370 proto_registrar_get_name(hfindex));
2376 /* NDR array header */
2377 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
2378 hf_dcerpc_array_offset, NULL);
2380 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
2381 hf_dcerpc_array_actual_count, &len);
2383 DISSECTOR_ASSERT(len <= G_MAXUINT32);
2384 buffer_len = size_is * (guint32)len;
2387 if (!di->no_align && (offset % size_is))
2388 offset += size_is - (offset % size_is);
2391 * "tvb_get_string_enc()" throws an exception if the entire string
2392 * isn't in the tvbuff. If the length is bogus, this should
2393 * keep us from trying to allocate an immensely large buffer.
2394 * (It won't help if the length is *valid* but immensely large,
2395 * but that's another matter; in any case, that would happen only
2396 * if we had an immensely large tvbuff....)
2398 * XXX - so why are we doing tvb_ensure_bytes_exist()?
2400 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
2401 if (size_is == sizeof(guint16)) {
2403 * Assume little-endian UTF-16.
2405 * XXX - is this always little-endian?
2407 s = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, buffer_len,
2408 ENC_UTF_16|ENC_LITTLE_ENDIAN);
2411 * XXX - what if size_is is neither 1 nor 2?
2413 s = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, buffer_len,
2414 DREP_ENC_CHAR(drep));
2416 if (tree && buffer_len)
2417 proto_tree_add_string(string_tree, hfindex, tvb, offset,
2420 if (string_item != NULL)
2421 proto_item_append_text(string_item, ": %s", s);
2426 offset += buffer_len;
2428 proto_item_set_end(string_item, tvb, offset);
2433 /* Dissect an varying string of chars.
2434 This corresponds to IDL of the form '[string] char *foo'.
2436 XXX - at least according to the DCE RPC 1.1 spec, a string has
2437 a null terminator, which isn't necessary as a terminator for
2438 the transfer language (as there's a length), but is presumably
2439 there for the benefit of null-terminated-string languages
2440 such as C. Is this ever used for purely counted strings?
2441 (Not that it matters if it is.) */
2443 dissect_ndr_char_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2444 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2446 return dissect_ndr_vstring(tvb, offset, pinfo, tree, di, drep,
2447 sizeof(guint8), di->hf_index,
2451 /* Dissect a varying string of wchars (wide characters).
2452 This corresponds to IDL of the form '[string] wchar *foo'
2454 XXX - at least according to the DCE RPC 1.1 spec, a string has
2455 a null terminator, which isn't necessary as a terminator for
2456 the transfer language (as there's a length), but is presumably
2457 there for the benefit of null-terminated-string languages
2458 such as C. Is this ever used for purely counted strings?
2459 (Not that it matters if it is.) */
2461 dissect_ndr_wchar_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2462 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2464 return dissect_ndr_vstring(tvb, offset, pinfo, tree, di, drep,
2465 sizeof(guint16), di->hf_index,
2470 /* ndr pointer handling */
2471 /* list of pointers encountered so far */
2472 static GSList *ndr_pointer_list = NULL;
2474 /* position where in the list to insert newly encountered pointers */
2475 static int ndr_pointer_list_pos = 0;
2477 /* Boolean controlling whether pointers are top-level or embedded */
2478 static gboolean pointers_are_top_level = TRUE;
2480 /* as a kludge, we represent all embedded reference pointers as id == -1
2481 hoping that his will not collide with any non-ref pointers */
2482 typedef struct ndr_pointer_data {
2484 proto_item *item; /* proto_item for pointer */
2485 proto_tree *tree; /* subtree of above item */
2486 dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
2488 dcerpc_callback_fnct_t *callback;
2489 void *callback_args;
2490 } ndr_pointer_data_t;
2493 init_ndr_pointer_list(dcerpc_info *di)
2495 di->conformant_run = 0;
2497 while (ndr_pointer_list) {
2498 ndr_pointer_data_t *npd = (ndr_pointer_data_t *)g_slist_nth_data(ndr_pointer_list, 0);
2499 ndr_pointer_list = g_slist_remove(ndr_pointer_list, npd);
2503 ndr_pointer_list = NULL;
2504 ndr_pointer_list_pos = 0;
2505 pointers_are_top_level = TRUE;
2509 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, dcerpc_info *di, guint8 *drep)
2511 int found_new_pointer;
2520 found_new_pointer = 0;
2521 len = g_slist_length(ndr_pointer_list);
2522 for (i=next_pointer; i<len; i++) {
2523 ndr_pointer_data_t *tnpd = (ndr_pointer_data_t *)g_slist_nth_data(ndr_pointer_list, i);
2525 dcerpc_dissect_fnct_t *fnct;
2528 found_new_pointer = 1;
2531 ndr_pointer_list_pos = i+1;
2532 di->hf_index = tnpd->hf_index;
2533 /* first a run to handle any conformant
2535 di->conformant_run = 1;
2536 di->conformant_eaten = 0;
2537 old_offset = offset;
2538 offset = (*(fnct))(tvb, offset, pinfo, NULL, di, drep);
2540 DISSECTOR_ASSERT((offset-old_offset) == di->conformant_eaten);
2541 /* This is to check for any bugs in the dissectors.
2543 * Basically, the NDR representation will store all
2544 * arrays in two blocks, one block with the dimension
2545 * description, like size, number of elements and such,
2546 * and another block that contains the actual data stored
2548 * If the array is embedded directly inside another,
2549 * encapsulating aggregate type, like a union or struct,
2550 * then these two blocks will be stored at different places
2551 * in the bytestream, with other data between the blocks.
2553 * For this reason, all pointers to types (both aggregate
2554 * and scalar, for simplicity no distinction is made)
2555 * will have its dissector called twice.
2556 * The dissector will first be called with conformant_run == 1
2557 * in which mode the dissector MUST NOT consume any data from
2558 * the tvbuff (i.e. may not dissect anything) except the
2559 * initial control block for arrays.
2560 * The second time the dissector is called, with
2561 * conformant_run == 0, all other data for the type will be
2564 * All dissect_ndr_<type> dissectors are already prepared
2565 * for this and knows when it should eat data from the tvb
2566 * and when not to, so implementors of dissectors will
2567 * normally not need to worry about this or even know about
2568 * it. However, if a dissector for an aggregate type calls
2569 * a subdissector from outside packet-dcerpc.c, such as
2570 * the dissector in packet-smb.c for NT Security Descriptors
2571 * as an example, then it is VERY important to encapsulate
2572 * this call to an external subdissector with the appropriate
2573 * test for conformant_run, i.e. it will need something like
2575 * dcerpc_info *di (received as function parameter)
2577 * if (di->conformant_run) {
2581 * to make sure it makes the right thing.
2582 * This assert will signal when someone has forgotten to
2583 * make the dissector aware of this requirement.
2586 /* now we dissect the actual pointer */
2587 di->conformant_run = 0;
2588 old_offset = offset;
2589 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, di, drep);
2591 tnpd->callback(pinfo, tnpd->tree, tnpd->item, di, tvb, old_offset, offset, tnpd->callback_args);
2592 proto_item_set_len(tnpd->item, offset - old_offset);
2596 } while (found_new_pointer);
2603 add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
2604 dcerpc_info *di, dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index,
2605 dcerpc_callback_fnct_t *callback, void *callback_args)
2607 ndr_pointer_data_t *npd;
2609 /* check if this pointer is valid */
2610 if (id != 0xffffffff) {
2611 dcerpc_call_value *value;
2613 value = di->call_data;
2615 if (di->ptype == PDU_REQ) {
2616 if (!(pinfo->fd->flags.visited)) {
2617 if (id > value->max_ptr) {
2618 value->max_ptr = id;
2622 /* if we haven't seen the request bail out since we can't
2623 know whether this is the first non-NULL instance
2625 if (value->req_frame == 0) {
2626 /* XXX THROW EXCEPTION */
2629 /* We saw this one in the request frame, nothing to
2631 if (id <= value->max_ptr) {
2637 npd = (ndr_pointer_data_t *)g_malloc(sizeof(ndr_pointer_data_t));
2642 npd->hf_index = hf_index;
2643 npd->callback = callback;
2644 npd->callback_args = callback_args;
2645 ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
2646 ndr_pointer_list_pos);
2647 ndr_pointer_list_pos++;
2652 find_pointer_index(guint32 id)
2654 ndr_pointer_data_t *npd;
2657 len = g_slist_length(ndr_pointer_list);
2658 for (i=0; i<len; i++) {
2659 npd = (ndr_pointer_data_t *)g_slist_nth_data(ndr_pointer_list, i);
2661 if (npd->id == id) {
2670 /* This function dissects an NDR pointer and stores the callback for later
2671 * deferred dissection.
2673 * fnct is the callback function for when we have reached this object in
2676 * type is what type of pointer.
2678 * this is text is what text we should put in any created tree node.
2680 * hf_index is what hf value we want to pass to the callback function when
2681 * it is called, the callback can later pick this one up from di->hf_index.
2683 * callback is executed after the pointer has been dereferenced.
2685 * callback_args is passed as an argument to the callback function
2687 * See packet-dcerpc-samr.c for examples
2690 dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2691 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2692 int type, const char *text, int hf_index,
2693 dcerpc_callback_fnct_t *callback, void *callback_args)
2695 proto_tree *tr = NULL;
2696 gint start_offset = offset;
2697 int pointer_size = 4;
2699 if (di->conformant_run) {
2700 /* this call was only for dissecting the header for any
2701 embedded conformant array. we will not parse any
2702 pointers in this mode.
2706 if (di->call_data->flags & DCERPC_IS_NDR64) {
2711 /*TOP LEVEL REFERENCE POINTER*/
2712 if ( pointers_are_top_level
2713 && (type == NDR_POINTER_REF) ) {
2716 /* we must find out a nice way to do the length here */
2717 tr = proto_tree_add_subtree(tree, tvb, offset, 0,
2718 ett_dcerpc_pointer_data, &item, text);
2720 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
2721 hf_index, callback, callback_args);
2725 /*TOP LEVEL FULL POINTER*/
2726 if ( pointers_are_top_level
2727 && (type == NDR_POINTER_PTR) ) {
2732 /* get the referent id */
2733 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
2735 /* we got a NULL pointer */
2737 proto_tree_add_bytes_format_value(tree, hf_dcerpc_null_pointer, tvb, offset-pointer_size,
2738 pointer_size, NULL, "%s", text);
2742 /* see if we have seen this pointer before
2743 The value is truncated to 32bits. 64bit values have only been
2744 seen on fuzz-tested files */
2745 idx = find_pointer_index((guint32)id);
2747 /* we have seen this pointer before */
2749 proto_tree_add_string(tree, hf_dcerpc_duplicate_ptr, tvb, offset-pointer_size, pointer_size, text);
2754 tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
2755 pointer_size, ett_dcerpc_pointer_data, &item, text);
2756 if (di->call_data->flags & DCERPC_IS_NDR64) {
2757 proto_tree_add_uint64(tr, hf_dcerpc_referent_id64, tvb,
2758 offset-pointer_size, pointer_size, id);
2760 proto_tree_add_uint(tr, hf_dcerpc_referent_id32, tvb,
2761 offset-pointer_size, pointer_size, (guint32)id);
2763 add_pointer_to_list(pinfo, tr, item, di, fnct, (guint32)id, hf_index,
2764 callback, callback_args);
2767 /*TOP LEVEL UNIQUE POINTER*/
2768 if ( pointers_are_top_level
2769 && (type == NDR_POINTER_UNIQUE) ) {
2773 /* get the referent id */
2774 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
2776 /* we got a NULL pointer */
2778 proto_tree_add_bytes_format_value(tree, hf_dcerpc_null_pointer, tvb, offset-pointer_size,
2779 pointer_size, NULL, "%s",text);
2784 tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
2786 ett_dcerpc_pointer_data, &item, text);
2787 if (di->call_data->flags & DCERPC_IS_NDR64) {
2788 proto_tree_add_uint64(tr, hf_dcerpc_referent_id64, tvb,
2789 offset-pointer_size, pointer_size, id);
2791 proto_tree_add_uint(tr, hf_dcerpc_referent_id32, tvb,
2792 offset-pointer_size, pointer_size, (guint32)id);
2794 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
2795 hf_index, callback, callback_args);
2799 /*EMBEDDED REFERENCE POINTER*/
2800 if ( (!pointers_are_top_level)
2801 && (type == NDR_POINTER_REF) ) {
2805 /* get the referent id */
2806 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
2809 tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
2811 ett_dcerpc_pointer_data,&item,text);
2812 if (di->call_data->flags & DCERPC_IS_NDR64) {
2813 proto_tree_add_uint64(tr, hf_dcerpc_referent_id64, tvb,
2814 offset-pointer_size, pointer_size, id);
2816 proto_tree_add_uint(tr, hf_dcerpc_referent_id32, tvb,
2817 offset-pointer_size, pointer_size, (guint32)id);
2819 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
2820 hf_index, callback, callback_args);
2824 /*EMBEDDED UNIQUE POINTER*/
2825 if ( (!pointers_are_top_level)
2826 && (type == NDR_POINTER_UNIQUE) ) {
2830 /* get the referent id */
2831 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
2833 /* we got a NULL pointer */
2835 proto_tree_add_bytes_format_value(tree, hf_dcerpc_null_pointer, tvb, offset-pointer_size,
2836 pointer_size, NULL, "%s",text);
2841 tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
2843 ett_dcerpc_pointer_data,&item,text);
2844 if (di->call_data->flags & DCERPC_IS_NDR64) {
2845 proto_tree_add_uint64(tr, hf_dcerpc_referent_id64, tvb,
2846 offset-pointer_size, pointer_size, id);
2848 proto_tree_add_uint(tr, hf_dcerpc_referent_id32, tvb,
2849 offset-pointer_size, pointer_size, (guint32)id);
2851 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
2852 hf_index, callback, callback_args);
2856 /*EMBEDDED FULL POINTER*/
2857 if ( (!pointers_are_top_level)
2858 && (type == NDR_POINTER_PTR) ) {
2863 /* get the referent id */
2864 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
2866 /* we got a NULL pointer */
2868 proto_tree_add_bytes_format_value(tree, hf_dcerpc_null_pointer, tvb, offset-pointer_size,
2869 pointer_size, NULL, "%s",text);
2873 /* see if we have seen this pointer before
2874 The value is truncated to 32bits. 64bit values have only been
2875 seen on fuzztested files */
2876 idx = find_pointer_index((guint32)id);
2878 /* we have seen this pointer before */
2880 proto_tree_add_string(tree, hf_dcerpc_duplicate_ptr, tvb, offset-pointer_size, pointer_size, text);
2885 tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
2887 ett_dcerpc_pointer_data, &item, text);
2888 if (di->call_data->flags & DCERPC_IS_NDR64) {
2889 proto_tree_add_uint64(tr, hf_dcerpc_referent_id64, tvb,
2890 offset-pointer_size, pointer_size, id);
2892 proto_tree_add_uint(tr, hf_dcerpc_referent_id32, tvb,
2893 offset-pointer_size, pointer_size, (guint32)id);
2895 add_pointer_to_list(pinfo, tr, item, di, fnct, (guint32)id, hf_index,
2896 callback, callback_args);
2902 /* After each top level pointer we have dissected we have to
2903 dissect all deferrals before we move on to the next top level
2905 if (pointers_are_top_level == TRUE) {
2906 pointers_are_top_level = FALSE;
2907 offset = dissect_deferred_pointers(pinfo, tvb, offset, di, drep);
2908 pointers_are_top_level = TRUE;
2911 /* Set the length for the new subtree */
2913 proto_item_set_len(tr, offset-start_offset);
2919 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2920 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2921 int type, const char *text, int hf_index)
2923 return dissect_ndr_pointer_cb(
2924 tvb, offset, pinfo, tree, di, drep, fnct, type, text, hf_index,
2928 dissect_ndr_toplevel_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2929 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2930 int type, const char *text, int hf_index)
2934 pointers_are_top_level = TRUE;
2935 ret = dissect_ndr_pointer_cb(
2936 tvb, offset, pinfo, tree, di, drep, fnct, type, text, hf_index,
2941 dissect_ndr_embedded_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2942 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2943 int type, const char *text, int hf_index)
2947 pointers_are_top_level = FALSE;
2948 ret = dissect_ndr_pointer_cb(
2949 tvb, offset, pinfo, tree, di, drep, fnct, type, text, hf_index,
2955 show_stub_data(tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
2956 dcerpc_auth_info *auth_info, gboolean is_encrypted)
2958 int length, plain_length, auth_pad_len;
2959 guint auth_pad_offset;
2962 * We don't show stub data unless we have some in the tvbuff;
2963 * however, in the protocol tree, we show, as the number of
2964 * bytes, the reported number of bytes, not the number of bytes
2965 * that happen to be in the tvbuff.
2967 if (tvb_reported_length_remaining(tvb, offset) > 0) {
2968 auth_pad_len = auth_info?auth_info->auth_pad_len:0;
2969 length = tvb_reported_length_remaining(tvb, offset);
2971 /* if auth_pad_len is larger than length then we ignore auth_pad_len totally */
2972 plain_length = length - auth_pad_len;
2973 if (plain_length < 1) {
2974 plain_length = length;
2977 auth_pad_offset = offset + plain_length;
2979 if ((auth_info != NULL) &&
2980 (auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)) {
2982 proto_tree_add_item(dcerpc_tree, hf_dcerpc_encrypted_stub_data, tvb, offset, length, ENC_NA);
2983 /* is the padding is still inside the encrypted blob, don't display it explicit */
2986 proto_tree_add_item(dcerpc_tree, hf_dcerpc_decrypted_stub_data, tvb, offset, plain_length, ENC_NA);
2989 proto_tree_add_item(dcerpc_tree, hf_dcerpc_stub_data, tvb, offset, plain_length, ENC_NA);
2991 /* If there is auth padding at the end of the stub, display it */
2992 if (auth_pad_len != 0) {
2993 proto_tree_add_item(dcerpc_tree, hf_dcerpc_auth_padding, tvb, auth_pad_offset, auth_pad_len, ENC_NA);
2999 dcerpc_try_handoff(packet_info *pinfo, proto_tree *tree,
3000 proto_tree *dcerpc_tree,
3001 tvbuff_t *volatile tvb, tvbuff_t *decrypted_tvb,
3002 guint8 *drep, dcerpc_info *info,
3003 dcerpc_auth_info *auth_info)
3005 volatile gint offset = 0;
3006 dcerpc_uuid_key key;
3007 dcerpc_uuid_value *sub_proto;
3008 proto_tree *volatile sub_tree = NULL;
3009 dcerpc_sub_dissector *proc;
3010 const gchar *name = NULL;
3011 const char *volatile saved_proto;
3012 guint length = 0, reported_length = 0;
3013 tvbuff_t *volatile stub_tvb;
3014 volatile guint auth_pad_len;
3015 volatile int auth_pad_offset;
3016 proto_item *sub_item = NULL;
3017 proto_item *pi, *hidden_item;
3019 dcerpc_dissect_fnct_t *volatile sub_dissect;
3021 key.uuid = info->call_data->uuid;
3022 key.ver = info->call_data->ver;
3024 if ((sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key)) == NULL
3025 || !proto_is_protocol_enabled(sub_proto->proto)) {
3027 * We don't have a dissector for this UUID, or the protocol
3028 * for that UUID is disabled.
3031 hidden_item = proto_tree_add_boolean(dcerpc_tree, hf_dcerpc_unknown_if_id,
3032 tvb, offset, 0, TRUE);
3033 PROTO_ITEM_SET_HIDDEN(hidden_item);
3034 col_append_fstr(pinfo->cinfo, COL_INFO, " %s V%u",
3035 guids_resolve_guid_to_str(&info->call_data->uuid), info->call_data->ver);
3037 if (decrypted_tvb != NULL) {
3038 show_stub_data(decrypted_tvb, 0, dcerpc_tree, auth_info,
3041 show_stub_data(tvb, 0, dcerpc_tree, auth_info, TRUE);
3045 for (proc = sub_proto->procs; proc->name; proc++) {
3046 if (proc->num == info->call_data->opnum) {
3052 col_set_str(pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
3055 col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown operation %u %s",
3056 info->call_data->opnum,
3057 (info->ptype == PDU_REQ) ? "request" : "response");
3059 col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
3060 name, (info->ptype == PDU_REQ) ? "request" : "response");
3062 sub_dissect = (info->ptype == PDU_REQ) ?
3063 proc->dissect_rqst : proc->dissect_resp;
3066 sub_item = proto_tree_add_item(tree, sub_proto->proto_id,
3067 (decrypted_tvb != NULL)?decrypted_tvb:tvb,
3071 sub_tree = proto_item_add_subtree(sub_item, sub_proto->ett);
3073 proto_item_append_text(sub_item, ", unknown operation %u",
3074 info->call_data->opnum);
3076 proto_item_append_text(sub_item, ", %s", name);
3080 * Put the operation number into the tree along with
3081 * the operation's name.
3083 if (sub_proto->opnum_hf != -1)
3084 proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
3085 tvb, 0, 0, info->call_data->opnum,
3086 "Operation: %s (%u)",
3087 name ? name : "Unknown operation",
3088 info->call_data->opnum);
3090 proto_tree_add_uint_format_value(sub_tree, hf_dcerpc_op, tvb,
3091 0, 0, info->call_data->opnum,
3093 name ? name : "Unknown operation",
3094 info->call_data->opnum);
3096 if ((info->ptype == PDU_REQ) && (info->call_data->rep_frame != 0)) {
3097 pi = proto_tree_add_uint(sub_tree, hf_dcerpc_response_in,
3098 tvb, 0, 0, info->call_data->rep_frame);
3099 PROTO_ITEM_SET_GENERATED(pi);
3101 if ((info->ptype == PDU_RESP) && (info->call_data->req_frame != 0)) {
3102 pi = proto_tree_add_uint(sub_tree, hf_dcerpc_request_in,
3103 tvb, 0, 0, info->call_data->req_frame);
3104 PROTO_ITEM_SET_GENERATED(pi);
3108 if (decrypted_tvb != NULL) {
3109 /* Either there was no encryption or we successfully decrypted
3110 the encrypted payload. */
3112 /* We have a subdissector - call it. */
3113 saved_proto = pinfo->current_proto;
3114 pinfo->current_proto = sub_proto->name;
3116 init_ndr_pointer_list(info);
3118 length = tvb_captured_length(decrypted_tvb);
3119 reported_length = tvb_reported_length(decrypted_tvb);
3122 * Remove the authentication padding from the stub data.
3124 if ((auth_info != NULL) && (auth_info->auth_pad_len != 0)) {
3125 if (reported_length >= auth_info->auth_pad_len) {
3127 * OK, the padding length isn't so big that it
3128 * exceeds the stub length. Trim the reported
3129 * length of the tvbuff.
3131 reported_length -= auth_info->auth_pad_len;
3134 * If that exceeds the actual amount of data in
3135 * the tvbuff (which means we have at least one
3136 * byte of authentication padding in the tvbuff),
3137 * trim the actual amount.
3139 if (length > reported_length)
3140 length = reported_length;
3142 stub_tvb = tvb_new_subset(decrypted_tvb, 0, length, reported_length);
3143 auth_pad_len = auth_info->auth_pad_len;
3144 auth_pad_offset = reported_length;
3147 * The padding length exceeds the stub length.
3148 * Don't bother dissecting the stub, trim the padding
3149 * length to what's in the stub data, and show the
3150 * entire stub as authentication padding.
3153 auth_pad_len = reported_length;
3154 auth_pad_offset = 0;
3159 * No authentication padding.
3161 stub_tvb = decrypted_tvb;
3163 auth_pad_offset = 0;
3167 proto_item_set_len(sub_item, length);
3170 if (stub_tvb != NULL) {
3172 * Catch all exceptions other than BoundsError, so that even
3173 * if the stub data is bad, we still show the authentication
3176 * If we get BoundsError, it means the frame was cut short
3177 * by a snapshot length, so there's nothing more to
3178 * dissect; just re-throw that exception.
3183 offset = sub_dissect(stub_tvb, 0, pinfo, sub_tree,
3186 /* If we have a subdissector and it didn't dissect all
3187 data in the tvb, make a note of it. */
3188 remaining = tvb_reported_length_remaining(stub_tvb, offset);
3189 if (remaining > 0) {
3190 proto_tree_add_expert(sub_tree, pinfo, &ei_dcerpc_long_frame, stub_tvb, offset, remaining);
3191 col_append_fstr(pinfo->cinfo, COL_INFO,
3192 "[Long frame (%d byte%s)]",
3194 plurality(remaining, "", "s"));
3197 } CATCH_NONFATAL_ERRORS {
3199 * Somebody threw an exception that means that there
3200 * was a problem dissecting the payload; that means
3201 * that a dissector was found, so we don't need to
3202 * dissect the payload as data or update the protocol
3205 * Just show the exception and then drive on to show
3206 * the authentication padding.
3208 show_exception(stub_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
3212 /* If there is auth padding at the end of the stub, display it */
3213 if (auth_pad_len != 0) {
3214 proto_tree_add_item(dcerpc_tree, hf_dcerpc_auth_padding, decrypted_tvb, auth_pad_offset, auth_pad_len, ENC_NA);
3217 pinfo->current_proto = saved_proto;
3219 /* No subdissector - show it as stub data. */
3220 if (decrypted_tvb) {
3221 show_stub_data(decrypted_tvb, 0, sub_tree, auth_info, FALSE);
3223 show_stub_data(tvb, 0, sub_tree, auth_info, TRUE);
3227 show_stub_data(tvb, 0, sub_tree, auth_info, TRUE);
3229 tap_queue_packet(dcerpc_tap, pinfo, info);
3234 dissect_dcerpc_verifier(tvbuff_t *tvb, packet_info *pinfo,
3235 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
3236 dcerpc_auth_info *auth_info)
3240 auth_info->auth_data = NULL;
3242 if (auth_info->auth_size != 0) {
3243 dcerpc_auth_subdissector_fns *auth_fns;
3246 auth_offset = hdr->frag_len - hdr->auth_len;
3248 auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
3251 auth_info->auth_data = auth_tvb;
3253 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
3254 auth_info->auth_type))) {
3256 * Catch all bounds-error exceptions, so that even if the
3257 * verifier is bad or we don't have all of it, we still
3258 * show the stub data.
3261 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
3263 } CATCH_BOUNDS_ERRORS {
3264 show_exception(auth_tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
3267 proto_tree_add_item(dcerpc_tree, hf_dcerpc_auth_verifier, auth_tvb, 0, hdr->auth_len, ENC_NA);
3271 return hdr->auth_len;
3275 dissect_dcerpc_cn_auth(tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
3276 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
3277 gboolean are_credentials, dcerpc_auth_info *auth_info)
3279 volatile int offset;
3282 * Initially set auth_level and auth_type to zero to indicate that we
3283 * haven't yet seen any authentication level information.
3285 auth_info->auth_level = 0;
3286 auth_info->auth_type = 0;
3287 auth_info->auth_size = 0;
3288 auth_info->auth_pad_len = 0;
3291 * The authentication information is at the *end* of the PDU; in
3292 * request and response PDUs, the request and response stub data
3295 * Is there any authentication data (i.e., is the authentication length
3296 * non-zero), and is the authentication length valid (i.e., is it, plus
3297 * 8 bytes for the type/level/pad length/reserved/context id, less than
3298 * or equal to the fragment length minus the starting offset of the
3303 && ((hdr->auth_len + 8) <= (hdr->frag_len - stub_offset))) {
3306 * Yes, there is authentication data, and the length is valid.
3307 * Do we have all the bytes of stub data?
3308 * (If not, we'd throw an exception dissecting *that*, so don't
3309 * bother trying to dissect the authentication information and
3310 * throwing another exception there.)
3312 offset = hdr->frag_len - (hdr->auth_len + 8);
3313 if (offset == 0 || tvb_offset_exists(tvb, offset - 1)) {
3315 * Either there's no stub data, or the last byte of the stub
3316 * data is present in the captured data, so we shouldn't
3317 * get a BoundsError dissecting the stub data.
3319 * Try dissecting the authentication data.
3320 * Catch all exceptions, so that even if the auth info is bad
3321 * or we don't have all of it, we still show the stuff we
3322 * dissect after this, such as stub data.
3325 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3326 hf_dcerpc_auth_type,
3327 &auth_info->auth_type);
3328 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3329 hf_dcerpc_auth_level,
3330 &auth_info->auth_level);
3332 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3333 hf_dcerpc_auth_pad_len,
3334 &auth_info->auth_pad_len);
3335 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3336 hf_dcerpc_auth_rsrvd, NULL);
3337 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3338 hf_dcerpc_auth_ctx_id, NULL);
3341 * Dissect the authentication data.
3343 if (are_credentials) {
3345 dcerpc_auth_subdissector_fns *auth_fns;
3347 auth_tvb = tvb_new_subset(tvb, offset,
3348 MIN(hdr->auth_len,tvb_reported_length_remaining(tvb, offset)),
3351 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
3352 auth_info->auth_type)))
3353 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
3356 proto_tree_add_item(dcerpc_tree, hf_dcerpc_auth_credentials, tvb, offset, hdr->auth_len, ENC_NA);
3359 /* Compute the size of the auth block. Note that this should not
3360 include auth padding, since when NTLMSSP encryption is used, the
3361 padding is actually inside the encrypted stub */
3362 auth_info->auth_size = hdr->auth_len + 8;
3363 } CATCH_BOUNDS_ERRORS {
3364 show_exception(tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
3371 /* We need to hash in the SMB fid number to generate a unique hash table
3372 * key as DCERPC over SMB allows several pipes over the same TCP/IP
3374 * We pass this function the transport type here to make sure we only look
3375 * at this function if it came across an SMB pipe.
3376 * Other transports might need to mix in their own extra multiplexing data
3377 * as well in the future.
3381 dcerpc_get_transport_salt(packet_info *pinfo)
3383 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
3385 switch (decode_data->dcetransporttype) {
3386 case DCE_CN_TRANSPORT_SMBPIPE:
3387 /* DCERPC over smb */
3388 return decode_data->dcetransportsalt;
3391 /* Some other transport... */
3396 dcerpc_set_transport_salt(guint64 dcetransportsalt, packet_info *pinfo)
3398 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
3400 decode_data->dcetransportsalt = dcetransportsalt;
3404 * Connection oriented packet types
3408 dissect_dcerpc_cn_bind(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3409 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
3411 conversation_t *conv = find_or_create_conversation(pinfo);
3412 guint8 num_ctx_items = 0;
3415 guint8 num_trans_items;
3420 guint16 if_ver, if_ver_minor;
3421 dcerpc_auth_info auth_info;
3423 const char *uuid_name = NULL;
3424 proto_item *iface_item = NULL;
3425 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
3427 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3428 hf_dcerpc_cn_max_xmit, NULL);
3430 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3431 hf_dcerpc_cn_max_recv, NULL);
3433 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3434 hf_dcerpc_cn_assoc_group, NULL);
3436 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3437 hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
3442 col_append_fstr(pinfo->cinfo, COL_INFO, ", %u context items:", num_ctx_items);
3444 for (i = 0; i < num_ctx_items; i++) {
3445 proto_item *ctx_item = NULL;
3446 proto_tree *ctx_tree = NULL, *iface_tree = NULL;
3447 gint ctx_offset = offset;
3449 dissect_dcerpc_uint16(tvb, offset, pinfo, NULL, hdr->drep,
3450 hf_dcerpc_cn_ctx_id, &ctx_id);
3452 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3453 /* (if we have multiple contexts, this might cause "decode as"
3454 * to behave unpredictably) */
3455 decode_data->dcectxid = ctx_id;
3458 ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_item,
3461 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
3464 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree, hdr->drep,
3465 hf_dcerpc_cn_ctx_id, &ctx_id);
3466 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, ctx_tree, hdr->drep,
3467 hf_dcerpc_cn_num_trans_items, &num_trans_items);
3470 proto_item_append_text(ctx_item, "[%u]: Context ID:%u", i+1, ctx_id);
3476 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &if_id);
3479 iface_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_abstract_syntax, tvb, offset, 0, ENC_NA);
3480 iface_tree = proto_item_add_subtree(iface_item, ett_dcerpc_cn_iface);
3482 uuid_str = guid_to_str(wmem_packet_scope(), (e_guid_t*)&if_id);
3483 uuid_name = guids_get_uuid_name(&if_id);
3485 proto_tree_add_guid_format(iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
3486 offset, 16, (e_guid_t *) &if_id, "Interface: %s UUID: %s", uuid_name, uuid_str);
3487 proto_item_append_text(iface_item, ": %s", uuid_name);
3488 proto_item_append_text(ctx_item, ", %s", uuid_name);
3490 proto_tree_add_guid_format(iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
3491 offset, 16, (e_guid_t *) &if_id, "Interface UUID: %s", uuid_str);
3492 proto_item_append_text(iface_item, ": %s", uuid_str);
3493 proto_item_append_text(ctx_item, ", %s", uuid_str);
3498 if (hdr->drep[0] & DREP_LITTLE_ENDIAN) {
3499 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
3500 hf_dcerpc_cn_bind_if_ver, &if_ver);
3501 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
3502 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
3504 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
3505 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
3506 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
3507 hf_dcerpc_cn_bind_if_ver, &if_ver);
3511 proto_item_append_text(iface_item, " V%u.%u", if_ver, if_ver_minor);
3512 proto_item_set_len(iface_item, 20);
3515 memset(&trans_id, 0, sizeof(trans_id));
3516 for (j = 0; j < num_trans_items; j++) {
3517 proto_tree *trans_tree = NULL;
3518 proto_item *trans_item = NULL;
3519 proto_item *uuid_item = NULL;
3521 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &trans_id);
3524 trans_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_trans_syntax, tvb, offset, 0, ENC_NA);
3525 trans_tree = proto_item_add_subtree(trans_item, ett_dcerpc_cn_trans_syntax);
3527 uuid_str = guid_to_str(wmem_packet_scope(), (e_guid_t *) &trans_id);
3528 uuid_name = guids_get_uuid_name(&trans_id);
3531 uuid_item = proto_tree_add_guid_format(trans_tree, hf_dcerpc_cn_bind_trans_id, tvb, offset, 16, (e_guid_t *) &trans_id, "Transfer Syntax: %s UUID:%s", uuid_name, uuid_str);
3532 proto_item_append_text(trans_item, "[%u]: %s", j+1, uuid_name);
3533 proto_item_append_text(ctx_item, ", %s", uuid_name);
3535 uuid_item = proto_tree_add_guid_format(trans_tree, hf_dcerpc_cn_bind_trans_id, tvb, offset, 16, (e_guid_t *) &trans_id, "Transfer Syntax: %s", uuid_str);
3536 proto_item_append_text(trans_item, "[%u]: %s", j+1, uuid_str);
3537 proto_item_append_text(ctx_item, ", %s", uuid_str);
3540 /* check for [MS-RPCE] 3.3.1.5.3 Bind Time Feature Negotiation */
3541 if (trans_id.data1 == 0x6cb71c2c && trans_id.data2 == 0x9812 && trans_id.data3 == 0x4540) {
3542 proto_tree *uuid_tree = proto_item_add_subtree(uuid_item, ett_dcerpc_cn_trans_btfn);
3543 proto_tree_add_boolean(uuid_tree, hf_dcerpc_cn_bind_trans_btfn_01, tvb, offset+8, 1, trans_id.data4[0]);
3544 proto_tree_add_boolean(uuid_tree, hf_dcerpc_cn_bind_trans_btfn_02, tvb, offset+8, 1, trans_id.data4[0]);
3549 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, trans_tree, hdr->drep,
3550 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
3552 proto_item_set_len(trans_item, 20);
3553 proto_item_append_text(trans_item, " V%u", trans_ver);
3557 /* if this is the first time we've seen this packet, we need to
3558 update the dcerpc_binds table so that any later calls can
3559 match to the interface.
3560 XXX We assume that BINDs will NEVER be fragmented.
3562 if (!(pinfo->fd->flags.visited)) {
3563 dcerpc_bind_key *key;
3564 dcerpc_bind_value *value;
3566 key = (dcerpc_bind_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_key));
3568 key->ctx_id = ctx_id;
3569 key->transport_salt = dcerpc_get_transport_salt(pinfo);
3571 value = (dcerpc_bind_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_value));
3572 value->uuid = if_id;
3573 value->ver = if_ver;
3574 value->transport = trans_id;
3576 /* add this entry to the bind table */
3577 g_hash_table_insert(dcerpc_binds, key, value);
3581 col_append_fstr(pinfo->cinfo, COL_INFO, ",");
3582 col_append_fstr(pinfo->cinfo, COL_INFO, " %s V%u.%u (%s)",
3583 guids_resolve_guid_to_str(&if_id), if_ver, if_ver_minor,
3584 guids_resolve_guid_to_str(&trans_id));
3587 proto_item_set_len(ctx_item, offset - ctx_offset);
3592 * XXX - we should save the authentication type *if* we have
3593 * an authentication header, and associate it with an authentication
3594 * context, so subsequent PDUs can use that context.
3596 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
3600 dissect_dcerpc_cn_bind_ack(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3601 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
3603 guint16 max_xmit, max_recv;
3604 guint16 sec_addr_len;
3611 dcerpc_auth_info auth_info;
3612 const char *uuid_name = NULL;
3613 const char *result_str = NULL;
3615 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3616 hf_dcerpc_cn_max_xmit, &max_xmit);
3618 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3619 hf_dcerpc_cn_max_recv, &max_recv);
3621 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3622 hf_dcerpc_cn_assoc_group, NULL);
3624 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3625 hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
3626 if (sec_addr_len != 0) {
3627 proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
3628 sec_addr_len, ENC_ASCII|ENC_NA);
3629 offset += sec_addr_len;
3633 offset += 4 - offset % 4;
3636 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3637 hf_dcerpc_cn_num_results, &num_results);
3642 col_append_fstr(pinfo->cinfo, COL_INFO, ", max_xmit: %u max_recv: %u, %u results:",
3643 max_xmit, max_recv, num_results);
3645 for (i = 0; i < num_results; i++) {
3646 proto_tree *ctx_tree = NULL;
3647 proto_item *ctx_item = NULL;
3650 ctx_tree = proto_tree_add_subtree_format(dcerpc_tree, tvb, offset, 24, ett_dcerpc_cn_ctx, &ctx_item, "Ctx Item[%u]:", i+1);
3653 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree,
3654 hdr->drep, hf_dcerpc_cn_ack_result,
3657 /* [MS-RPCE] 3.3.1.5.3 check if this Ctx Item is the response to a Bind Time Feature Negotiation request */
3659 const int old_offset = offset;
3660 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree, hdr->drep, hf_dcerpc_cn_ack_btfn, &reason);
3661 proto_tree_add_boolean(ctx_tree, hf_dcerpc_cn_bind_trans_btfn_01, tvb, old_offset, 1, reason);
3662 proto_tree_add_boolean(ctx_tree, hf_dcerpc_cn_bind_trans_btfn_02, tvb, old_offset, 1, reason);
3663 } else if (result != 0) {
3664 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree,
3665 hdr->drep, hf_dcerpc_cn_ack_reason,
3669 * The reason for rejection isn't meaningful, and often isn't
3670 * set, when the syntax was accepted.
3675 result_str = val_to_str(result, p_cont_result_vals, "Unknown result (%u)");
3678 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &trans_id);
3679 uuid_name = guids_get_uuid_name(&trans_id);
3681 uuid_name = guid_to_str(wmem_packet_scope(), (e_guid_t *) &trans_id);
3683 proto_tree_add_guid_format(ctx_tree, hf_dcerpc_cn_ack_trans_id, tvb,
3684 offset, 16, (e_guid_t *) &trans_id, "Transfer Syntax: %s",
3686 proto_item_append_text(ctx_item, " %s, %s", result_str, uuid_name);
3690 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, ctx_tree, hdr->drep,
3691 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
3694 col_append_fstr(pinfo->cinfo, COL_INFO, ",");
3695 col_append_fstr(pinfo->cinfo, COL_INFO, " %s", result_str);
3699 * XXX - do we need to do anything with the authentication level
3700 * we get back from this?
3702 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
3706 dissect_dcerpc_cn_bind_nak(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3707 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
3710 guint8 num_protocols;
3713 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
3714 hdr->drep, hf_dcerpc_cn_reject_reason,
3717 col_append_fstr(pinfo->cinfo, COL_INFO, " reason: %s",
3718 val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
3720 if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
3721 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3722 hf_dcerpc_cn_num_protocols,
3725 for (i = 0; i < num_protocols; i++) {
3726 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
3727 hdr->drep, hf_dcerpc_cn_protocol_ver_major,
3729 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
3730 hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
3736 /* Return a string describing a DCE/RPC fragment as first, middle, or end
3739 #define PFC_FRAG_MASK 0x03
3742 fragment_type(guint8 flags)
3744 static const char* t[4] = {
3750 return t[flags & PFC_FRAG_MASK];
3753 /* Dissect stub data (payload) of a DCERPC packet. */
3756 dissect_dcerpc_cn_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
3757 proto_tree *dcerpc_tree, proto_tree *tree,
3758 e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
3759 dcerpc_auth_info *auth_info, guint32 alloc_hint _U_,
3762 gint length, reported_length;
3763 gboolean save_fragmented;
3764 fragment_head *fd_head = NULL;
3766 tvbuff_t *auth_tvb, *payload_tvb, *decrypted_tvb;
3768 proto_item *parent_pi;
3769 proto_item *dcerpc_tree_item;
3771 save_fragmented = pinfo->fragmented;
3773 length = tvb_reported_length_remaining(tvb, offset);
3774 reported_length = tvb_reported_length_remaining(tvb, offset);
3775 if (reported_length < 0 ||
3776 (guint32)reported_length < auth_info->auth_size) {
3777 /* We don't even have enough bytes for the authentication
3781 reported_length -= auth_info->auth_size;
3782 if (length > reported_length)
3783 length = reported_length;
3784 payload_tvb = tvb_new_subset(tvb, offset, length, reported_length);
3787 /*don't bother if we don't have the entire tvb */
3788 /*XXX we should really make sure we calculate auth_info->auth_data
3789 and use that one instead of this auth_tvb hack
3791 if (tvb_captured_length(tvb) == tvb_reported_length(tvb)) {
3792 if (tvb_reported_length_remaining(tvb, offset+length) > 8) {
3793 auth_tvb = tvb_new_subset_remaining(tvb, offset+length+8);
3797 /* Decrypt the PDU if it is encrypted */
3799 if (auth_info->auth_type &&
3800 (auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)) {
3802 * We know the authentication type, and the authentication
3803 * level is "Packet privacy", meaning the payload is
3804 * encrypted; attempt to decrypt it.
3806 dcerpc_auth_subdissector_fns *auth_fns;
3808 /* Start out assuming we won't succeed in decrypting. */
3809 decrypted_tvb = NULL;
3810 /* Schannel needs information into the footer (verifier) in order to setup decryption keys
3811 * so we call it in order to have a chance to decipher the data
3813 if (DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN == auth_info->auth_type) {
3814 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, auth_info);
3817 if ((auth_fns = get_auth_subdissector_fns(
3818 auth_info->auth_level, auth_info->auth_type))) {
3821 result = decode_encrypted_data(
3822 payload_tvb, auth_tvb, pinfo, auth_fns,
3823 hdr->ptype == PDU_REQ, auth_info);
3827 proto_tree_add_item(dcerpc_tree, hf_dcerpc_encrypted_stub_data, payload_tvb, 0, -1, ENC_NA);
3829 add_new_data_source(
3830 pinfo, result, "Decrypted stub data");
3833 decrypted_tvb = result;
3837 decrypted_tvb = payload_tvb;
3839 /* if this packet is not fragmented, just dissect it and exit */
3840 if (PFC_NOT_FRAGMENTED(hdr)) {
3841 pinfo->fragmented = FALSE;
3844 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
3845 hdr->drep, di, auth_info);
3847 pinfo->fragmented = save_fragmented;
3851 /* The packet is fragmented. */
3852 pinfo->fragmented = TRUE;
3854 /* debug output of essential fragment data. */
3855 /* leave it here for future debugging sessions */
3856 /*printf("DCE num:%u offset:%u frag_len:%u tvb_len:%u\n",
3857 pinfo->fd->num, offset, hdr->frag_len, tvb_reported_length(decrypted_tvb));*/
3859 /* if we are not doing reassembly and this is the first fragment
3860 then just dissect it and exit
3861 XXX - if we're not doing reassembly, can we decrypt an
3864 if ( (!dcerpc_reassemble) && (hdr->flags & PFC_FIRST_FRAG) ) {
3867 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
3868 hdr->drep, di, auth_info);
3870 expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment, "%s fragment", fragment_type(hdr->flags));
3872 pinfo->fragmented = save_fragmented;
3876 /* if we have already seen this packet, see if it was reassembled
3877 and if so dissect the full pdu.
3880 if (pinfo->fd->flags.visited) {
3881 fd_head = fragment_get_reassembled(&dcerpc_co_reassembly_table, frame);
3885 /* if we are not doing reassembly and it was neither a complete PDU
3886 nor the first fragment then there is nothing more we can do
3887 so we just have to exit
3889 if ( !dcerpc_reassemble || (tvb_captured_length(tvb) != tvb_reported_length(tvb)) )
3892 /* if we didn't get 'frame' we don't know where the PDU started and thus
3893 it is pointless to continue
3898 /* from now on we must attempt to reassemble the PDU
3901 /* if we get here we know it is the first time we see the packet
3902 and we also know it is only a fragment and not a full PDU,
3903 thus we must reassemble it.
3906 /* Do we have any non-encrypted data to reassemble? */
3907 if (decrypted_tvb == NULL) {
3908 /* No. We can't even try to reassemble. */
3912 /* defragmentation is a bit tricky, as there's no offset of the fragment
3913 * in the protocol data.
3915 * just use fragment_add_seq_next() and hope that TCP/SMB segments coming
3916 * in with the correct sequence.
3918 fd_head = fragment_add_seq_next(&dcerpc_co_reassembly_table,
3919 decrypted_tvb, 0, pinfo, frame, NULL,
3920 tvb_reported_length(decrypted_tvb),
3921 hdr->flags&PFC_LAST_FRAG ? FALSE : TRUE /* more_frags */);
3925 /* if reassembly is complete and this is the last fragment
3926 * (multiple fragments in one PDU are possible!)
3927 * dissect the full PDU
3929 if (fd_head && (fd_head->flags & FD_DEFRAGMENTED) ) {
3931 if ((pinfo->fd->num == fd_head->reassembled_in) && (hdr->flags & PFC_LAST_FRAG) ) {
3933 proto_item *frag_tree_item;
3935 next_tvb = tvb_new_chain((decrypted_tvb)?decrypted_tvb:payload_tvb,
3938 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3939 show_fragment_tree(fd_head, &dcerpc_frag_items,
3940 tree, pinfo, next_tvb, &frag_tree_item);
3941 /* the toplevel fragment subtree is now behind all desegmented data,
3942 * move it right behind the DCE/RPC tree */
3943 dcerpc_tree_item = proto_tree_get_parent(dcerpc_tree);
3944 if (frag_tree_item && dcerpc_tree_item) {
3945 proto_tree_move_item(tree, dcerpc_tree_item, frag_tree_item);
3948 pinfo->fragmented = FALSE;
3950 expert_add_info_format(pinfo, frag_tree_item, &ei_dcerpc_fragment_reassembled, "%s fragment, reassembled", fragment_type(hdr->flags));
3952 dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb,
3953 next_tvb, hdr->drep, di, auth_info);
3956 if (decrypted_tvb) {
3957 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
3958 decrypted_tvb, 0, 0, fd_head->reassembled_in);
3960 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
3961 payload_tvb, 0, 0, fd_head->reassembled_in);
3963 PROTO_ITEM_SET_GENERATED(pi);
3964 parent_pi = proto_tree_get_parent(dcerpc_tree);
3965 if (parent_pi != NULL) {
3966 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
3968 col_append_fstr(pinfo->cinfo, COL_INFO,
3969 " [DCE/RPC %s fragment, reas: #%u]", fragment_type(hdr->flags), fd_head->reassembled_in);
3970 expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment_reassembled, "%s fragment, reassembled in #%u", fragment_type(hdr->flags), fd_head->reassembled_in);
3973 /* Reassembly not complete - some fragments
3974 are missing. Just show the stub data. */
3975 expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment, "%s fragment", fragment_type(hdr->flags));
3977 if (decrypted_tvb) {
3978 show_stub_data(decrypted_tvb, 0, tree, auth_info, FALSE);
3980 show_stub_data(payload_tvb, 0, tree, auth_info, TRUE);
3984 pinfo->fragmented = save_fragmented;
3988 dissect_dcerpc_cn_rqst(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3989 proto_tree *dcerpc_tree, proto_tree *tree,
3990 e_dce_cn_common_hdr_t *hdr)
3992 conversation_t *conv;
3995 e_guid_t obj_id = DCERPC_UUID_NULL;
3996 dcerpc_auth_info auth_info;
3999 proto_item *parent_pi;
4000 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
4002 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4003 hf_dcerpc_cn_alloc_hint, &alloc_hint);
4005 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4006 hf_dcerpc_cn_ctx_id, &ctx_id);
4007 parent_pi = proto_tree_get_parent(dcerpc_tree);
4008 if (parent_pi != NULL) {
4009 proto_item_append_text(parent_pi, ", Ctx: %u", ctx_id);
4012 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4013 hf_dcerpc_opnum, &opnum);
4015 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
4016 decode_data->dcectxid = ctx_id;
4018 col_append_fstr(pinfo->cinfo, COL_INFO, ", opnum: %u, Ctx: %u",
4021 if (hdr->flags & PFC_OBJECT_UUID) {
4022 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &obj_id);
4024 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
4025 offset, 16, (e_guid_t *) &obj_id, "Object UUID: %s",
4026 guid_to_str(wmem_packet_scope(), (e_guid_t *) &obj_id));
4032 * XXX - what if this was set when the connection was set up,
4033 * and we just have a security context?
4035 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
4037 conv = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
4038 pinfo->srcport, pinfo->destport, 0);
4040 show_stub_data(tvb, offset, dcerpc_tree, &auth_info, TRUE);
4042 dcerpc_matched_key matched_key, *new_matched_key;
4043 dcerpc_call_value *value;
4045 /* !!! we can NOT check flags.visited here since this will interact
4046 badly with when SMB handles (i.e. calls the subdissector)
4047 and desegmented pdu's .
4048 Instead we check if this pdu is already in the matched table or not
4050 matched_key.frame = pinfo->fd->num;
4051 matched_key.call_id = hdr->call_id;
4052 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
4054 dcerpc_bind_key bind_key;
4055 dcerpc_bind_value *bind_value;
4057 bind_key.conv = conv;
4058 bind_key.ctx_id = ctx_id;
4059 bind_key.transport_salt = dcerpc_get_transport_salt(pinfo);
4061 if ((bind_value = (dcerpc_bind_value *)g_hash_table_lookup(dcerpc_binds, &bind_key)) ) {
4062 if (!(hdr->flags&PFC_FIRST_FRAG)) {
4063 dcerpc_cn_call_key call_key;
4064 dcerpc_call_value *call_value;
4066 call_key.conv = conv;
4067 call_key.call_id = hdr->call_id;
4068 call_key.transport_salt = dcerpc_get_transport_salt(pinfo);
4069 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_cn_calls, &call_key))) {
4070 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
4071 *new_matched_key = matched_key;
4072 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
4076 dcerpc_cn_call_key *call_key;
4077 dcerpc_call_value *call_value;
4079 /* We found the binding and it is the first fragment
4080 (or a complete PDU) of a dcerpc pdu so just add
4081 the call to both the call table and the
4084 call_key = (dcerpc_cn_call_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_cn_call_key));
4085 call_key->conv = conv;
4086 call_key->call_id = hdr->call_id;
4087 call_key->transport_salt = dcerpc_get_transport_salt(pinfo);
4089 /* if there is already a matching call in the table
4090 remove it so it is replaced with the new one */
4091 if (g_hash_table_lookup(dcerpc_cn_calls, call_key)) {
4092 g_hash_table_remove(dcerpc_cn_calls, call_key);
4095 call_value = (dcerpc_call_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_call_value));
4096 call_value->uuid = bind_value->uuid;
4097 call_value->ver = bind_value->ver;
4098 call_value->object_uuid = obj_id;
4099 call_value->opnum = opnum;
4100 call_value->req_frame = pinfo->fd->num;
4101 call_value->req_time = pinfo->fd->abs_ts;
4102 call_value->rep_frame = 0;
4103 call_value->max_ptr = 0;
4104 call_value->se_data = NULL;
4105 call_value->private_data = NULL;
4106 call_value->pol = NULL;
4107 call_value->flags = 0;
4108 if (!memcmp(&bind_value->transport, &uuid_ndr64, sizeof(uuid_ndr64))) {
4109 call_value->flags |= DCERPC_IS_NDR64;
4112 g_hash_table_insert(dcerpc_cn_calls, call_key, call_value);
4114 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
4115 *new_matched_key = matched_key;
4116 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
4125 di = wmem_new0(wmem_packet_scope(), dcerpc_info);
4126 /* handoff this call */
4127 di->dcerpc_procedure_name = "";
4129 di->call_id = hdr->call_id;
4130 di->transport_salt = dcerpc_get_transport_salt(pinfo);
4131 di->ptype = PDU_REQ;
4132 di->call_data = value;
4135 if (value->rep_frame != 0) {
4136 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
4137 tvb, 0, 0, value->rep_frame);
4138 PROTO_ITEM_SET_GENERATED(pi);
4139 if (parent_pi != NULL) {
4140 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
4144 dissect_dcerpc_cn_stub(tvb, offset, pinfo, dcerpc_tree, tree,
4145 hdr, di, &auth_info, alloc_hint,
4148 /* no bind information, simply show stub data */
4149 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);
4150 show_stub_data(tvb, offset, dcerpc_tree, &auth_info, TRUE);
4154 /* Dissect the verifier */
4155 dissect_dcerpc_verifier(tvb, pinfo, dcerpc_tree, hdr, &auth_info);
4160 dissect_dcerpc_cn_resp(tvbuff_t *tvb, gint offset, packet_info *pinfo,
4161 proto_tree *dcerpc_tree, proto_tree *tree,
4162 e_dce_cn_common_hdr_t *hdr)
4164 dcerpc_call_value *value = NULL;
4165 conversation_t *conv;
4167 dcerpc_auth_info auth_info;
4170 proto_item *parent_pi;
4171 e_guid_t obj_id_null = DCERPC_UUID_NULL;
4172 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
4174 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4175 hf_dcerpc_cn_alloc_hint, &alloc_hint);
4177 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4178 hf_dcerpc_cn_ctx_id, &ctx_id);
4179 parent_pi = proto_tree_get_parent(dcerpc_tree);
4180 if (parent_pi != NULL) {
4181 proto_item_append_text(parent_pi, ", Ctx: %u", ctx_id);
4184 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
4185 decode_data->dcectxid = ctx_id;
4187 col_append_fstr(pinfo->cinfo, COL_INFO, ", Ctx: %u", ctx_id);
4189 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4190 hf_dcerpc_cn_cancel_count, NULL);
4195 * XXX - what if this was set when the connection was set up,
4196 * and we just have a security context?
4198 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
4200 conv = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
4201 pinfo->srcport, pinfo->destport, 0);
4204 /* no point in creating one here, really */
4205 show_stub_data(tvb, offset, dcerpc_tree, &auth_info, TRUE);
4207 dcerpc_matched_key matched_key, *new_matched_key;
4209 /* !!! we can NOT check flags.visited here since this will interact
4210 badly with when SMB handles (i.e. calls the subdissector)
4211 and desegmented pdu's .
4212 Instead we check if this pdu is already in the matched table or not
4214 matched_key.frame = pinfo->fd->num;
4215 matched_key.call_id = hdr->call_id;
4216 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
4218 dcerpc_cn_call_key call_key;
4219 dcerpc_call_value *call_value;
4221 call_key.conv = conv;
4222 call_key.call_id = hdr->call_id;
4223 call_key.transport_salt = dcerpc_get_transport_salt(pinfo);
4225 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_cn_calls, &call_key))) {
4226 /* extra sanity check, only match them if the reply
4227 came after the request */
4228 if (call_value->req_frame<pinfo->fd->num) {
4229 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
4230 *new_matched_key = matched_key;
4231 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
4233 if (call_value->rep_frame == 0) {
4234 call_value->rep_frame = pinfo->fd->num;
4243 di = wmem_new0(wmem_packet_scope(), dcerpc_info);
4244 /* handoff this call */
4245 di->dcerpc_procedure_name = "";
4247 di->call_id = hdr->call_id;
4248 di->transport_salt = dcerpc_get_transport_salt(pinfo);
4249 di->ptype = PDU_RESP;
4250 di->call_data = value;
4252 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
4254 /* (optional) "Object UUID" from request */
4255 if (dcerpc_tree && (memcmp(&value->object_uuid, &obj_id_null, sizeof(obj_id_null)) != 0)) {
4256 pi = proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
4257 offset, 0, (e_guid_t *) &value->object_uuid, "Object UUID: %s",
4258 guid_to_str(wmem_packet_scope(), (e_guid_t *) &value->object_uuid));
4259 PROTO_ITEM_SET_GENERATED(pi);
4263 if (value->req_frame != 0) {
4265 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4266 tvb, 0, 0, value->req_frame);
4267 PROTO_ITEM_SET_GENERATED(pi);
4268 if (parent_pi != NULL) {
4269 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
4271 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
4272 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
4273 PROTO_ITEM_SET_GENERATED(pi);
4275 proto_tree_add_expert(dcerpc_tree, pinfo, &ei_dcerpc_no_request_found, tvb, 0, 0);
4278 dissect_dcerpc_cn_stub(tvb, offset, pinfo, dcerpc_tree, tree,
4279 hdr, di, &auth_info, alloc_hint,
4282 /* no bind information, simply show stub data */
4283 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);
4284 show_stub_data(tvb, offset, dcerpc_tree, &auth_info, TRUE);
4288 /* Dissect the verifier */
4289 dissect_dcerpc_verifier(tvb, pinfo, dcerpc_tree, hdr, &auth_info);
4293 dissect_dcerpc_cn_fault(tvbuff_t *tvb, gint offset, packet_info *pinfo,
4294 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
4296 dcerpc_call_value *value = NULL;
4297 conversation_t *conv;
4301 dcerpc_auth_info auth_info;
4302 proto_item *pi = NULL;
4303 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
4305 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4306 hf_dcerpc_cn_alloc_hint, &alloc_hint);
4308 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4309 hf_dcerpc_cn_ctx_id, &ctx_id);
4311 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4312 hf_dcerpc_cn_cancel_count, NULL);
4317 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4318 hf_dcerpc_cn_status, &status);
4320 status = ((hdr->drep[0] & DREP_LITTLE_ENDIAN)
4321 ? tvb_get_letohl(tvb, offset)
4322 : tvb_get_ntohl(tvb, offset));
4324 pi = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_status, tvb, offset, 4, DREP_ENC_INTEGER(hdr->drep));
4327 expert_add_info_format(pinfo, pi, &ei_dcerpc_cn_status, "Fault: %s", val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
4329 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
4330 decode_data->dcectxid = ctx_id;
4332 col_append_fstr(pinfo->cinfo, COL_INFO,
4333 ", Ctx: %u, status: %s", ctx_id,
4334 val_to_str(status, reject_status_vals,
4335 "Unknown (0x%08x)"));
4341 * XXX - what if this was set when the connection was set up,
4342 * and we just have a security context?
4344 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
4346 conv = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
4347 pinfo->srcport, pinfo->destport, 0);
4349 /* no point in creating one here, really */
4351 dcerpc_matched_key matched_key, *new_matched_key;
4353 /* !!! we can NOT check flags.visited here since this will interact
4354 badly with when SMB handles (i.e. calls the subdissector)
4355 and desegmented pdu's .
4356 Instead we check if this pdu is already in the matched table or not
4358 matched_key.frame = pinfo->fd->num;
4359 matched_key.call_id = hdr->call_id;
4360 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
4362 dcerpc_cn_call_key call_key;
4363 dcerpc_call_value *call_value;
4365 call_key.conv = conv;
4366 call_key.call_id = hdr->call_id;
4367 call_key.transport_salt = dcerpc_get_transport_salt(pinfo);
4369 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_cn_calls, &call_key))) {
4370 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
4371 *new_matched_key = matched_key;
4372 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
4375 if (call_value->rep_frame == 0) {
4376 call_value->rep_frame = pinfo->fd->num;
4383 int length, stub_length;
4385 proto_item *parent_pi;
4387 di = wmem_new0(wmem_packet_scope(), dcerpc_info);
4388 /* handoff this call */
4389 di->dcerpc_procedure_name = "";
4391 di->call_id = hdr->call_id;
4392 di->transport_salt = dcerpc_get_transport_salt(pinfo);
4393 di->ptype = PDU_FAULT;
4394 di->call_data = value;
4396 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
4397 if (value->req_frame != 0) {
4399 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4400 tvb, 0, 0, value->req_frame);
4401 PROTO_ITEM_SET_GENERATED(pi);
4402 parent_pi = proto_tree_get_parent(dcerpc_tree);
4403 if (parent_pi != NULL) {
4404 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
4406 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
4407 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
4408 PROTO_ITEM_SET_GENERATED(pi);
4410 proto_tree_add_expert(dcerpc_tree, pinfo, &ei_dcerpc_no_request_found, tvb, 0, 0);
4413 length = tvb_reported_length_remaining(tvb, offset);
4414 /* as we now create a tvb in dissect_dcerpc_cn() containing only the
4415 * stub_data, the following calculation is no longer valid:
4416 * stub_length = hdr->frag_len - offset - auth_info.auth_size;
4417 * simply use the remaining length of the tvb instead.
4418 * XXX - or better use the reported_length?!?
4420 stub_length = length;
4421 if (length > stub_length)
4422 length = stub_length;
4424 /* If we don't have reassembly enabled, or this packet contains
4425 the entire PDU, or if we don't have all the data in this
4426 fragment, just call the handoff directly if this is the
4427 first fragment or the PDU isn't fragmented. */
4428 if ( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
4429 !tvb_bytes_exist(tvb, offset, stub_length) ) {
4430 if (hdr->flags&PFC_FIRST_FRAG) {
4431 /* First fragment, possibly the only fragment */
4433 * XXX - should there be a third routine for each
4434 * function in an RPC subdissector, to handle
4435 * fault responses? The DCE RPC 1.1 spec says
4436 * three's "stub data" here, which I infer means
4437 * that it's protocol-specific and call-specific.
4439 * It should probably get passed the status code
4440 * as well, as that might be protocol-specific.
4442 if (stub_length > 0) {
4443 proto_tree_add_item(dcerpc_tree, hf_dcerpc_fault_stub_data, tvb, offset, stub_length, ENC_NA);
4446 /* PDU is fragmented and this isn't the first fragment */
4447 if (stub_length > 0) {
4448 proto_tree_add_item(dcerpc_tree, hf_dcerpc_fragment_data, tvb, offset, stub_length, ENC_NA);
4452 /* Reassembly is enabled, the PDU is fragmented, and
4453 we have all the data in the fragment; the first two
4454 of those mean we should attempt reassembly, and the
4455 third means we can attempt reassembly. */
4458 proto_tree_add_item(dcerpc_tree, hf_dcerpc_fragment_data, tvb, offset, stub_length, ENC_NA);
4461 if (hdr->flags&PFC_FIRST_FRAG) { /* FIRST fragment */
4462 if ( (!pinfo->fd->flags.visited) && value->rep_frame ) {
4463 fragment_add_seq_next(&dcerpc_co_reassembly_table,
4465 pinfo, value->rep_frame, NULL,
4469 } else if (hdr->flags&PFC_LAST_FRAG) { /* LAST fragment */
4470 if ( value->rep_frame ) {
4471 fragment_head *fd_head;
4473 fd_head = fragment_add_seq_next(&dcerpc_co_reassembly_table,
4475 pinfo, value->rep_frame, NULL,
4480 /* We completed reassembly */
4482 proto_item *frag_tree_item;
4484 next_tvb = tvb_new_chain(tvb, fd_head->tvb_data);
4485 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
4486 show_fragment_tree(fd_head, &dcerpc_frag_items,
4487 dcerpc_tree, pinfo, next_tvb, &frag_tree_item);
4490 * XXX - should there be a third routine for each
4491 * function in an RPC subdissector, to handle
4492 * fault responses? The DCE RPC 1.1 spec says
4493 * three's "stub data" here, which I infer means
4494 * that it's protocol-specific and call-specific.
4496 * It should probably get passed the status code
4497 * as well, as that might be protocol-specific.
4501 proto_tree_add_item(dcerpc_tree, hf_dcerpc_stub_data, tvb, offset, stub_length, ENC_NA);
4506 } else { /* MIDDLE fragment(s) */
4507 if ( (!pinfo->fd->flags.visited) && value->rep_frame ) {
4508 fragment_add_seq_next(&dcerpc_co_reassembly_table,
4510 pinfo, value->rep_frame, NULL,
4521 dissect_dcerpc_cn_rts(tvbuff_t *tvb, gint offset, packet_info *pinfo,
4522 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
4524 proto_item *tf = NULL;
4525 proto_item *parent_pi = NULL;
4526 proto_tree *cn_rts_pdu_tree = NULL;
4528 guint16 commands_nb = 0;
4531 const char *info_str = NULL;
4532 static const int * flags[] = {
4533 &hf_dcerpc_cn_rts_flags_none,
4534 &hf_dcerpc_cn_rts_flags_ping,
4535 &hf_dcerpc_cn_rts_flags_other_cmd,
4536 &hf_dcerpc_cn_rts_flags_recycle_channel,
4537 &hf_dcerpc_cn_rts_flags_in_channel,
4538 &hf_dcerpc_cn_rts_flags_out_channel,
4539 &hf_dcerpc_cn_rts_flags_eof,
4543 /* Dissect specific RTS header */
4544 rts_flags = dcerpc_tvb_get_ntohs(tvb, offset, hdr->drep);
4545 proto_tree_add_bitmask_value_with_flags(dcerpc_tree, tvb, offset, hf_dcerpc_cn_rts_flags,
4546 ett_dcerpc_cn_rts_flags, flags, rts_flags, BMT_NO_APPEND);
4549 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4550 hf_dcerpc_cn_rts_commands_nb, &commands_nb);
4552 /* Create the RTS PDU tree - we do not yet know its name */
4553 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);
4555 cmd = (guint32 *)wmem_alloc(wmem_packet_scope(), sizeof (guint32) * (commands_nb + 1));
4557 /* Dissect commands */
4558 for (i = 0; i < commands_nb; ++i) {
4559 proto_tree *cn_rts_command_tree = NULL;
4560 const guint32 command = dcerpc_tvb_get_ntohl(tvb, offset, hdr->drep);
4562 tf = proto_tree_add_uint(cn_rts_pdu_tree, hf_dcerpc_cn_rts_command, tvb, offset, 4, command);
4563 cn_rts_command_tree = proto_item_add_subtree(tf, ett_dcerpc_cn_rts_command);
4566 case RTS_CMD_RECEIVEWINDOWSIZE:
4567 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_receivewindowsize, NULL);
4569 case RTS_CMD_FLOWCONTROLACK:
4570 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_fack_bytesreceived, NULL);
4571 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_fack_availablewindow, NULL);
4572 offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_fack_channelcookie, NULL);
4574 case RTS_CMD_CONNECTIONTIMEOUT:
4575 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_connectiontimeout, NULL);
4577 case RTS_CMD_COOKIE:
4578 offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_cookie, NULL);
4580 case RTS_CMD_CHANNELLIFETIME:
4581 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_channellifetime, NULL);
4583 case RTS_CMD_CLIENTKEEPALIVE:
4584 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_clientkeepalive, NULL);
4586 case RTS_CMD_VERSION:
4587 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_version, NULL);
4591 case RTS_CMD_PADDING: {
4593 const guint32 conformance_count = dcerpc_tvb_get_ntohl(tvb, offset, hdr->drep);
4594 proto_tree_add_uint(cn_rts_command_tree, hf_dcerpc_cn_rts_command_conformancecount, tvb, offset, 4, conformance_count);
4596 padding = (guint8 *)tvb_memdup(NULL, tvb, offset, conformance_count);
4597 proto_tree_add_bytes(cn_rts_command_tree, hf_dcerpc_cn_rts_command_padding, tvb, offset, conformance_count, padding);
4598 offset += conformance_count;
4600 case RTS_CMD_NEGATIVEANCE:
4604 case RTS_CMD_CLIENTADDRESS: {
4606 const guint32 addrtype = dcerpc_tvb_get_ntohl(tvb, offset, hdr->drep);
4607 proto_tree_add_uint(cn_rts_command_tree, hf_dcerpc_cn_rts_command_addrtype, tvb, offset, 4, addrtype);
4611 const guint32 addr4 = tvb_get_ipv4(tvb, offset);
4612 proto_tree_add_ipv4_format_value(cn_rts_command_tree, hf_dcerpc_cmd_client_ipv4, tvb, offset, 4, addr4, "%s", get_hostname(addr4));
4616 struct e_in6_addr addr6;
4617 tvb_get_ipv6(tvb, offset, &addr6);
4618 proto_tree_add_ipv6_format_value(cn_rts_command_tree, hf_dcerpc_cmd_client_ipv6, tvb, offset, 16, &addr6, "%s", get_hostname6(&addr6));
4622 padding = (guint8 *)tvb_memdup(NULL, tvb, offset, 12);
4623 proto_tree_add_bytes(cn_rts_command_tree, hf_dcerpc_cn_rts_command_padding, tvb, offset, 12, padding);
4626 case RTS_CMD_ASSOCIATIONGROUPID:
4627 offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_associationgroupid, NULL);
4629 case RTS_CMD_DESTINATION:
4630 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_forwarddestination, NULL);
4632 case RTS_CMD_PINGTRAFFICSENTNOTIFY:
4633 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_pingtrafficsentnotify, NULL);
4636 expert_add_info(pinfo, tf, &ei_dcerpc_cn_rts_command);
4641 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RPCH");
4643 /* Define which PDU Body we are dealing with */
4644 info_str = "unknown RTS PDU";
4646 switch (rts_flags) {
4648 switch (commands_nb) {
4650 if (cmd[0] == 0x2) {
4651 info_str = "CONN/A3";
4652 } else if (cmd[0] == 0x3) {
4653 info_str = "IN_R1/A5,IN_R1/A6,IN_R2/A2,IN_R2/A5,OUT_R2/A4";
4654 } else if (cmd[0] == 0x7) {
4655 info_str = "IN_R1/B1";
4656 } else if (cmd[0] == 0x0) {
4657 info_str = "IN_R1/B2";
4658 } else if (cmd[0] == 0xD) {
4659 info_str = "IN_R2/A3,IN_R2/A4";
4660 } else if (cmd[0] == 0xA) {
4661 info_str = "OUT_R1/A9,OUT_R1/A10,OUT_R1/A11,OUT_R2/B1,OUT_R2/B2";
4665 if ((cmd[0] == 0x0) && (cmd[1] == 0x6)) {
4666 info_str = "CONN/B3";
4667 } else if ((cmd[0] == 0xD) && (cmd[1] == 0xA)) {
4668 info_str = "OUT_R2/A5,OUT_R2/A6";
4672 if ((cmd[0] == 0x6) && (cmd[1] == 0x0) && (cmd[2] == 0x2)) {
4673 info_str = "CONN/C1,CONN/C2";
4677 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x0)) {
4678 info_str = "CONN/A1";
4679 } else if ((cmd[0] == 0xD) && (cmd[1] == 0x6) && (cmd[2] == 0x0) && (cmd[3] == 0x2)) {
4680 info_str = "IN_R1/A3,IN_R1/A4";
4684 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x4) && (cmd[4] == 0x5) && (cmd[5] == 0xC)) {
4685 info_str = "CONN/B1";
4693 switch (commands_nb) {
4698 if ((cmd[0] == 0x7) || (cmd[0] == 0x8)) {
4699 info_str = "OUT_R2/C1";
4706 case RTS_FLAG_OTHER_CMD:
4707 switch (commands_nb) {
4709 if (cmd[0] == 0x5) {
4710 info_str = "Keep-Alive";
4711 } else if (cmd[0] == 0xE) {
4712 info_str = "PingTrafficSentNotify";
4713 } else if (cmd[0] == 0x1) {
4714 info_str = "FlowControlAck";
4718 if ((cmd[0] == 0xD) && (cmd[1] == 0x1)) {
4719 info_str = "FlowControlAckWithDestination";
4726 case RTS_FLAG_RECYCLE_CHANNEL:
4727 switch (commands_nb) {
4729 if (cmd[0] == 0xD) {
4730 info_str = "OUT_R1/A1,OUT_R1/A2,OUT_R2/A1,OUT_R2/A2";
4734 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3)) {
4735 info_str = "IN_R1/A1,IN_R2/A1";
4739 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3) && (cmd[4] == 0x0)) {
4740 info_str = "OUT_R1/A3,OUT_R2/A3";
4747 case RTS_FLAG_IN_CHANNEL|RTS_FLAG_RECYCLE_CHANNEL:
4748 switch (commands_nb) {
4750 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3) && (cmd[4] == 0x0) && (cmd[5] == 0x2)) {
4751 info_str = "IN_R1/A2";
4758 case RTS_FLAG_IN_CHANNEL:
4759 switch (commands_nb) {
4761 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x0) && (cmd[4] == 0x2) && (cmd[5] == 0xC) && (cmd[6] == 0xB)) {
4762 info_str = "CONN/B2";
4769 case RTS_FLAG_OUT_CHANNEL|RTS_FLAG_RECYCLE_CHANNEL:
4770 switch (commands_nb) {
4772 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3) && (cmd[4] == 0x4) && (cmd[5] == 0) && (cmd[6] == 0x2)) {
4773 info_str = "OUT_R1/A4";
4780 case RTS_FLAG_OUT_CHANNEL:
4781 switch (commands_nb) {
4783 if ((cmd[0] == 0xD) && (cmd[1] == 0x3)) {
4784 info_str = "OUT_R1/A7,OUT_R1/A8,OUT_R2/A8";
4788 if ((cmd[0] == 0xD) && (cmd[1] == 0x6) && (cmd[2] == 0x2)) {
4789 info_str = "OUT_R1/A5,OUT_R1/A6";
4790 } else if ((cmd[0] == 0xD) && (cmd[1] == 0x3) && (cmd[2] == 0x6)) {
4791 info_str = "OUT_R2/A7";
4795 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x4) && (cmd[4] == 0x0)) {
4796 info_str = "CONN/A2";
4804 switch (commands_nb) {
4806 if (cmd[0] == 0xA) {
4807 info_str = "OUT_R2/B3";
4815 switch (commands_nb) {
4827 col_add_fstr(pinfo->cinfo, COL_INFO, "%s, ", info_str);
4828 col_set_fence(pinfo->cinfo,COL_INFO);
4830 parent_pi = proto_tree_get_parent(dcerpc_tree);
4831 if (parent_pi != NULL) {
4832 proto_item_append_text(parent_pi, ", %s", info_str);
4837 is_dcerpc(tvbuff_t *tvb, int offset, packet_info *pinfo _U_)
4840 guint8 rpc_ver_minor;
4843 if (!tvb_bytes_exist(tvb, offset, sizeof(e_dce_cn_common_hdr_t)))
4844 return FALSE; /* not enough information to check */
4846 rpc_ver = tvb_get_guint8(tvb, offset++);
4849 rpc_ver_minor = tvb_get_guint8(tvb, offset++);
4850 if ((rpc_ver_minor != 0) && (rpc_ver_minor != 1))
4852 ptype = tvb_get_guint8(tvb, offset++);
4853 if (ptype > PDU_RTS)
4860 * DCERPC dissector for connection oriented calls.
4863 dissect_dcerpc_cn(tvbuff_t *tvb, int offset, packet_info *pinfo,
4864 proto_tree *tree, gboolean can_desegment, int *pkt_len)
4866 static const guint8 nulls[4] = { 0 };
4870 proto_item *ti = NULL;
4871 proto_item *tf = NULL;
4872 proto_tree *dcerpc_tree = NULL;
4873 proto_tree *drep_tree = NULL;
4874 e_dce_cn_common_hdr_t hdr;
4875 dcerpc_auth_info auth_info;
4876 tvbuff_t *fragment_tvb;
4877 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
4878 static const int * hdr_flags[] = {
4879 &hf_dcerpc_cn_flags_object,
4880 &hf_dcerpc_cn_flags_maybe,
4881 &hf_dcerpc_cn_flags_dne,
4882 &hf_dcerpc_cn_flags_mpx,
4883 &hf_dcerpc_cn_flags_reserved,
4884 &hf_dcerpc_cn_flags_cancel_pending,
4885 &hf_dcerpc_cn_flags_last_frag,
4886 &hf_dcerpc_cn_flags_first_frag,
4891 * when done over nbt, dcerpc requests are padded with 4 bytes of null
4892 * data for some reason.
4894 * XXX - if that's always the case, the right way to do this would
4895 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
4896 * the 4 bytes of null padding, and make that the dissector
4897 * used for "netbios".
4899 if (tvb_memeql(tvb, offset, nulls, 4) == 0) {
4908 * Check if this looks like a C/O DCERPC call
4910 if (!is_dcerpc(tvb, offset, pinfo))
4913 start_offset = offset;
4914 hdr.rpc_ver = tvb_get_guint8(tvb, offset++);
4915 hdr.rpc_ver_minor = tvb_get_guint8(tvb, offset++);
4916 hdr.ptype = tvb_get_guint8(tvb, offset++);
4918 hdr.flags = tvb_get_guint8(tvb, offset++);
4919 tvb_memcpy(tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
4920 offset += (int)sizeof (hdr.drep);
4922 hdr.frag_len = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
4924 hdr.auth_len = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
4926 hdr.call_id = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
4929 if (decode_data->dcectxid == 0) {
4930 col_append_fstr(pinfo->cinfo, COL_DCE_CALL, "%u", hdr.call_id);
4932 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
4933 * prepend a delimiter */
4934 col_append_fstr(pinfo->cinfo, COL_DCE_CALL, "#%u", hdr.call_id);
4937 if (can_desegment && pinfo->can_desegment
4938 && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
4939 pinfo->desegment_offset = start_offset;
4940 pinfo->desegment_len = hdr.frag_len - tvb_reported_length_remaining(tvb, start_offset);
4941 *pkt_len = 0; /* desegmentation required */
4945 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCERPC");
4947 if (decode_data->dcectxid != 0) {
4948 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
4949 * append a delimiter and set a column fence */
4950 col_append_str(pinfo->cinfo, COL_INFO, " # ");
4951 col_set_fence(pinfo->cinfo,COL_INFO);
4953 col_add_fstr(pinfo->cinfo, COL_INFO, "%s: call_id: %u",
4954 pckt_vals[hdr.ptype].strptr, hdr.call_id);
4956 if (decode_data->dcectxid != 0) {
4957 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU */
4958 expert_add_info(pinfo, NULL, &ei_dcerpc_fragment_multiple);
4961 offset = start_offset;
4962 tvb_ensure_bytes_exist(tvb, offset, 16);
4964 ti = proto_tree_add_item(tree, proto_dcerpc, tvb, offset, hdr.frag_len, ENC_NA);
4965 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
4968 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
4971 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset, 1, hdr.rpc_ver_minor);
4974 tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
4977 #if 0 /* XXX - too much "output noise", removed for now */
4978 if (hdr.ptype == PDU_BIND || hdr.ptype == PDU_ALTER ||
4979 hdr.ptype == PDU_BIND_ACK || hdr.ptype == PDU_ALTER_ACK)
4980 expert_add_info_format(pinfo, tf, &ei_dcerpc_context_change, "Context change: %s", val_to_str(hdr.ptype, pckt_vals, "(0x%x)"));
4982 if (hdr.ptype == PDU_BIND_NAK)
4983 expert_add_info(pinfo, tf, &ei_dcerpc_bind_not_acknowledged);
4986 proto_item_append_text(ti, " %s, Fragment: %s",
4987 val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"),
4988 fragment_type(hdr.flags));
4991 proto_tree_add_bitmask_value_with_flags(dcerpc_tree, tvb, offset, hf_dcerpc_cn_flags,
4992 ett_dcerpc_cn_flags, hdr_flags, hdr.flags, BMT_NO_APPEND);
4995 col_append_fstr(pinfo->cinfo, COL_INFO, ", Fragment: %s", fragment_type(hdr.flags));
4998 tf = proto_tree_add_bytes(dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
4999 drep_tree = proto_item_add_subtree(tf, ett_dcerpc_drep);
5001 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
5002 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
5003 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
5004 offset += (int)sizeof (hdr.drep);
5006 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
5009 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
5012 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
5016 proto_item_append_text(ti, ", FragLen: %u, Call: %u", hdr.frag_len, hdr.call_id);
5020 * None of the stuff done above should throw an exception, because
5021 * we would have rejected this as "not DCE RPC" if we didn't have all
5022 * of it. (XXX - perhaps we should request reassembly if we have
5023 * enough of the header to consider it DCE RPC but not enough to
5024 * get the fragment length; in that case the stuff still wouldn't
5025 * throw an exception.)
5027 * The rest of the stuff might, so return the PDU length to our caller.
5028 * XXX - should we construct a tvbuff containing only the PDU and
5029 * use that? Or should we have separate "is this a DCE RPC PDU",
5030 * "how long is it", and "dissect it" routines - which might let us
5031 * do most of the work in "tcp_dissect_pdus()"?
5033 if (pkt_len != NULL)
5034 *pkt_len = hdr.frag_len + padding;
5036 /* The remaining bytes in the current tvb might contain multiple
5037 * DCE/RPC fragments, so create a new tvb subset for this fragment.
5038 * Only limit the end of the fragment, but not the offset start,
5039 * as the authentication function dissect_dcerpc_cn_auth() will fail
5040 * (and other functions might fail as well) computing the right start
5043 subtvb_len = MIN(hdr.frag_len, tvb_reported_length(tvb));
5044 fragment_tvb = tvb_new_subset(tvb, start_offset,
5045 subtvb_len /* length */,
5046 hdr.frag_len /* reported_length */);
5049 * Packet type specific stuff is next.
5051 switch (hdr.ptype) {
5054 dissect_dcerpc_cn_bind(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
5059 dissect_dcerpc_cn_bind_ack(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
5064 * Nothing after the common header other than credentials.
5066 dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr, TRUE,
5071 dissect_dcerpc_cn_rqst(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, tree, &hdr);
5075 dissect_dcerpc_cn_resp(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, tree, &hdr);
5079 dissect_dcerpc_cn_fault(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
5083 dissect_dcerpc_cn_bind_nak(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
5089 * Nothing after the common header other than an authentication
5092 dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr, FALSE,
5098 * Nothing after the common header, not even an authentication
5103 dissect_dcerpc_cn_rts(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
5107 /* might as well dissect the auth info */
5108 dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr, FALSE,
5116 * DCERPC dissector for connection oriented calls over packet-oriented
5120 dissect_dcerpc_cn_pk(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5122 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
5125 * Only one PDU per transport packet, and only one transport
5128 decode_data->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
5129 if (!dissect_dcerpc_cn(tvb, 0, pinfo, tree, FALSE, NULL)) {
5131 * It wasn't a DCERPC PDU.
5143 * DCERPC dissector for connection oriented calls over byte-stream
5145 * we need to distinguish here between SMB and non-TCP (more in the future?)
5146 * to be able to know what kind of private_data structure to expect.
5149 dissect_dcerpc_cn_bs_body(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
5151 volatile int offset = 0;
5153 volatile int dcerpc_pdus = 0;
5154 volatile gboolean ret = FALSE;
5157 * There may be multiple PDUs per transport packet; keep
5160 while (tvb_reported_length_remaining(tvb, offset) != 0) {
5163 if (dissect_dcerpc_cn(tvb, offset, pinfo, tree,
5164 dcerpc_cn_desegment, &pdu_len)) {
5167 } CATCH_NONFATAL_ERRORS {
5169 * Somebody threw an exception that means that there
5170 * was a problem dissecting the payload; that means
5171 * that a dissector was found, so we don't need to
5172 * dissect the payload as data or update the protocol
5175 * Just show the exception and then continue dissecting
5178 show_exception(tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
5180 * Presumably it looked enough like a DCE RPC PDU that we
5181 * dissected enough of it to throw an exception.
5186 if (dcerpc_pdus == 0) {
5187 gboolean try_desegment = FALSE;
5188 if (dcerpc_cn_desegment && pinfo->can_desegment &&
5189 !tvb_bytes_exist(tvb, offset, sizeof(e_dce_cn_common_hdr_t))) {
5190 /* look for a previous occurrence of the DCE-RPC protocol */
5191 wmem_list_frame_t *cur;
5192 cur = wmem_list_frame_prev(wmem_list_tail(pinfo->layers));
5193 while (cur != NULL) {
5194 if (proto_dcerpc == (gint)GPOINTER_TO_UINT(wmem_list_frame_data(cur))) {
5195 try_desegment = TRUE;
5198 cur = wmem_list_frame_prev(cur);
5202 if (try_desegment) {
5203 /* It didn't look like DCE-RPC but we already had one DCE-RPC
5204 * layer in this packet and what we have is short. Assume that
5205 * it was just too short to tell and ask the TCP layer for more
5207 pinfo->desegment_offset = offset;
5208 pinfo->desegment_len = (guint32)(sizeof(e_dce_cn_common_hdr_t) - tvb_reported_length_remaining(tvb, offset));
5210 /* Really not DCE-RPC */
5216 * Well, we've seen at least one DCERPC PDU.
5220 /* if we had more than one Req/Resp in this PDU change the protocol column */
5221 /* this will formerly contain the last interface name, which may not be the same for all Req/Resp */
5222 if (dcerpc_pdus >= 2)
5223 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "%u*DCERPC", dcerpc_pdus);
5227 * Desegmentation required - bail now, but give the user a hint that desegmentation might be done later.
5229 proto_tree_add_uint_format(tree, hf_dcerpc_cn_deseg_req, tvb, offset,
5231 tvb_reported_length_remaining(tvb, offset),
5232 "[DCE RPC: %u byte%s left, desegmentation might follow]",
5233 tvb_reported_length_remaining(tvb, offset),
5234 plurality(tvb_reported_length_remaining(tvb, offset), "", "s"));
5239 * Step to the next PDU.
5247 dissect_dcerpc_cn_bs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5249 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
5251 decode_data->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
5252 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
5256 get_dcerpc_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb,
5257 int offset _U_, void *data _U_)
5262 /* XXX: why does htis not take offset into account? */
5263 tvb_memcpy(tvb, (guint8 *)drep, 4, sizeof(drep));
5264 frag_len = dcerpc_tvb_get_ntohs(tvb, 8, drep);
5270 dissect_dcerpc_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
5273 dissect_dcerpc_cn(tvb, 0, pinfo, tree,
5274 /* Desegment is already handled by TCP, don't confuse it */
5281 dissect_dcerpc_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
5283 dcerpc_decode_as_data* decode_data;
5285 if (!is_dcerpc(tvb, 0, pinfo))
5288 decode_data = dcerpc_get_decode_data(pinfo);
5289 decode_data->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
5291 tcp_dissect_pdus(tvb, pinfo, tree, dcerpc_cn_desegment, 10, get_dcerpc_pdu_len, dissect_dcerpc_pdu, data);
5296 dissect_dcerpc_cn_smbpipe(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5298 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
5300 decode_data->dcetransporttype = DCE_CN_TRANSPORT_SMBPIPE;
5301 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
5305 dissect_dcerpc_cn_smb2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5307 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
5309 decode_data->dcetransporttype = DCE_CN_TRANSPORT_SMBPIPE;
5310 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
5316 dissect_dcerpc_dg_auth(tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
5317 e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
5319 proto_tree *auth_tree = NULL;
5320 guint8 protection_level;
5323 * Initially set "*auth_level_p" to -1 to indicate that we haven't
5324 * yet seen any authentication level information.
5326 if (auth_level_p != NULL)
5330 * The authentication information is at the *end* of the PDU; in
5331 * request and response PDUs, the request and response stub data
5334 * If the full packet is here, and there's data past the end of the
5335 * packet body, then dissect the auth info.
5337 offset += hdr->frag_len;
5338 if (tvb_reported_length_remaining(tvb, offset) > 0) {
5339 switch (hdr->auth_proto) {
5341 case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
5342 auth_tree = proto_tree_add_subtree(dcerpc_tree, tvb, offset, -1, ett_dcerpc_krb5_auth_verf, NULL, "Kerberos authentication verifier");
5343 protection_level = tvb_get_guint8(tvb, offset);
5344 if (auth_level_p != NULL)
5345 *auth_level_p = protection_level;
5346 proto_tree_add_uint(auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
5348 proto_tree_add_item(auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, ENC_BIG_ENDIAN);
5350 if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
5351 offset += 6; /* 6 bytes of padding */
5353 offset += 2; /* 2 bytes of padding */
5354 proto_tree_add_item(auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, ENC_NA);
5359 proto_tree_add_item(dcerpc_tree, hf_dcerpc_authentication_verifier, tvb, offset, -1, ENC_NA);
5366 dissect_dcerpc_dg_cancel_ack(tvbuff_t *tvb, int offset, packet_info *pinfo,
5367 proto_tree *dcerpc_tree,
5368 e_dce_dg_common_hdr_t *hdr)
5372 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5373 hdr->drep, hf_dcerpc_dg_cancel_vers,
5379 /* The only version we know about */
5380 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5381 hdr->drep, hf_dcerpc_dg_cancel_id,
5383 /*offset = */dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
5384 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
5391 dissect_dcerpc_dg_cancel(tvbuff_t *tvb, int offset, packet_info *pinfo,
5392 proto_tree *dcerpc_tree,
5393 e_dce_dg_common_hdr_t *hdr)
5397 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5398 hdr->drep, hf_dcerpc_dg_cancel_vers,
5404 /* The only version we know about */
5405 /*offset = */dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5406 hdr->drep, hf_dcerpc_dg_cancel_id,
5408 /* XXX - are NDR Booleans 32 bits? */
5410 /* XXX - the RPC reference in chapter: "the cancel PDU" doesn't mention
5411 the accepting_cancels field (it's only in the cancel_ack PDU)! */
5412 /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
5413 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
5420 dissect_dcerpc_dg_fack(tvbuff_t *tvb, int offset, packet_info *pinfo,
5421 proto_tree *dcerpc_tree,
5422 e_dce_dg_common_hdr_t *hdr)
5429 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
5430 hdr->drep, hf_dcerpc_dg_fack_vers,
5437 case 0: /* The only version documented in the DCE RPC 1.1 spec */
5438 case 1: /* This appears to be the same */
5439 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
5440 hdr->drep, hf_dcerpc_dg_fack_window_size,
5442 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5443 hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
5445 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5446 hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
5448 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
5449 hdr->drep, hf_dcerpc_dg_fack_serial_num,
5451 col_append_fstr(pinfo->cinfo, COL_INFO, " serial: %u",
5453 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
5454 hdr->drep, hf_dcerpc_dg_fack_selack_len,
5456 for (i = 0; i < selack_len; i++) {
5457 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5458 hdr->drep, hf_dcerpc_dg_fack_selack,
5467 dissect_dcerpc_dg_reject_fault(tvbuff_t *tvb, int offset, packet_info *pinfo,
5468 proto_tree *dcerpc_tree,
5469 e_dce_dg_common_hdr_t *hdr)
5473 /*offset = */dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5474 hdr->drep, hf_dcerpc_dg_status,
5477 col_append_fstr (pinfo->cinfo, COL_INFO,
5479 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
5483 dissect_dcerpc_dg_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
5484 proto_tree *dcerpc_tree, proto_tree *tree,
5485 e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
5487 int length, reported_length, stub_length;
5488 gboolean save_fragmented;
5489 fragment_head *fd_head;
5492 proto_item *parent_pi;
5494 col_append_fstr(pinfo->cinfo, COL_INFO, " opnum: %u len: %u",
5495 di->call_data->opnum, hdr->frag_len );
5497 length = tvb_reported_length_remaining(tvb, offset);
5498 reported_length = tvb_reported_length_remaining(tvb, offset);
5499 stub_length = hdr->frag_len;
5500 if (length > stub_length)
5501 length = stub_length;
5502 if (reported_length > stub_length)
5503 reported_length = stub_length;
5505 save_fragmented = pinfo->fragmented;
5507 /* If we don't have reassembly enabled, or this packet contains
5508 the entire PDU, or if this is a short frame (or a frame
5509 not reassembled at a lower layer) that doesn't include all
5510 the data in the fragment, just call the handoff directly if
5511 this is the first fragment or the PDU isn't fragmented. */
5512 if ( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
5513 !tvb_bytes_exist(tvb, offset, stub_length) ) {
5514 if (hdr->frag_num == 0) {
5517 /* First fragment, possibly the only fragment */
5520 * XXX - authentication info?
5522 pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
5523 next_tvb = tvb_new_subset(tvb, offset, length,
5525 dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb,
5526 next_tvb, hdr->drep, di, NULL);
5528 /* PDU is fragmented and this isn't the first fragment */
5530 proto_tree_add_item(dcerpc_tree, hf_dcerpc_fragment_data, tvb, offset, stub_length, ENC_NA);
5534 /* Reassembly is enabled, the PDU is fragmented, and
5535 we have all the data in the fragment; the first two
5536 of those mean we should attempt reassembly, and the
5537 third means we can attempt reassembly. */
5539 proto_tree_add_item(dcerpc_tree, hf_dcerpc_fragment_data, tvb, offset, stub_length, ENC_NA);
5542 fd_head = fragment_add_seq(&dcerpc_cl_reassembly_table,
5544 pinfo, hdr->seqnum, (void *)hdr,
5545 hdr->frag_num, stub_length,
5546 !(hdr->flags1 & PFCL1_LASTFRAG), 0);
5547 if (fd_head != NULL) {
5548 /* We completed reassembly... */
5549 if (pinfo->fd->num == fd_head->reassembled_in) {
5550 /* ...and this is the reassembled RPC PDU */
5551 next_tvb = tvb_new_chain(tvb, fd_head->tvb_data);
5552 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
5553 show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
5554 tree, pinfo, next_tvb, &pi);
5557 * XXX - authentication info?
5559 pinfo->fragmented = FALSE;
5560 dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb,
5561 next_tvb, hdr->drep, di, NULL);
5563 /* ...and this isn't the reassembled RPC PDU */
5564 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
5565 tvb, 0, 0, fd_head->reassembled_in);
5566 PROTO_ITEM_SET_GENERATED(pi);
5567 parent_pi = proto_tree_get_parent(dcerpc_tree);
5568 if (parent_pi != NULL) {
5569 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
5571 col_append_fstr(pinfo->cinfo, COL_INFO,
5572 " [DCE/RPC fragment, reas: #%u]", fd_head->reassembled_in);
5576 pinfo->fragmented = save_fragmented;
5580 dissect_dcerpc_dg_rqst(tvbuff_t *tvb, int offset, packet_info *pinfo,
5581 proto_tree *dcerpc_tree, proto_tree *tree,
5582 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
5585 dcerpc_call_value *value;
5586 dcerpc_matched_key matched_key, *new_matched_key;
5588 proto_item *parent_pi;
5590 if (!(pinfo->fd->flags.visited)) {
5591 dcerpc_call_value *call_value;
5592 dcerpc_dg_call_key *call_key;
5594 call_key = (dcerpc_dg_call_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_dg_call_key));
5595 call_key->conv = conv;
5596 call_key->seqnum = hdr->seqnum;
5597 call_key->act_id = hdr->act_id;
5599 call_value = (dcerpc_call_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_call_value));
5600 call_value->uuid = hdr->if_id;
5601 call_value->ver = hdr->if_ver;
5602 call_value->object_uuid = hdr->obj_id;
5603 call_value->opnum = hdr->opnum;
5604 call_value->req_frame = pinfo->fd->num;
5605 call_value->req_time = pinfo->fd->abs_ts;
5606 call_value->rep_frame = 0;
5607 call_value->max_ptr = 0;
5608 call_value->se_data = NULL;
5609 call_value->private_data = NULL;
5610 call_value->pol = NULL;
5611 /* NDR64 is not available on dg transports ?*/
5612 call_value->flags = 0;
5614 g_hash_table_insert(dcerpc_dg_calls, call_key, call_value);
5616 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof(dcerpc_matched_key));
5617 new_matched_key->frame = pinfo->fd->num;
5618 new_matched_key->call_id = hdr->seqnum;
5619 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
5622 matched_key.frame = pinfo->fd->num;
5623 matched_key.call_id = hdr->seqnum;
5624 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
5626 value = wmem_new(wmem_packet_scope(), dcerpc_call_value);
5627 value->uuid = hdr->if_id;
5628 value->ver = hdr->if_ver;
5629 value->object_uuid = hdr->obj_id;
5630 value->opnum = hdr->opnum;
5631 value->req_frame = pinfo->fd->num;
5632 value->rep_frame = 0;
5634 value->se_data = NULL;
5635 value->private_data = NULL;
5638 di = wmem_new0(wmem_packet_scope(), dcerpc_info);
5639 di->dcerpc_procedure_name = "";
5641 di->call_id = hdr->seqnum;
5642 di->transport_salt = -1;
5643 di->ptype = PDU_REQ;
5644 di->call_data = value;
5646 if (value->rep_frame != 0) {
5647 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
5648 tvb, 0, 0, value->rep_frame);
5649 PROTO_ITEM_SET_GENERATED(pi);
5650 parent_pi = proto_tree_get_parent(dcerpc_tree);
5651 if (parent_pi != NULL) {
5652 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
5655 dissect_dcerpc_dg_stub(tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
5659 dissect_dcerpc_dg_resp(tvbuff_t *tvb, int offset, packet_info *pinfo,
5660 proto_tree *dcerpc_tree, proto_tree *tree,
5661 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
5664 dcerpc_call_value *value;
5665 dcerpc_matched_key matched_key, *new_matched_key;
5667 proto_item *parent_pi;
5669 if (!(pinfo->fd->flags.visited)) {
5670 dcerpc_call_value *call_value;
5671 dcerpc_dg_call_key call_key;
5673 call_key.conv = conv;
5674 call_key.seqnum = hdr->seqnum;
5675 call_key.act_id = hdr->act_id;
5677 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_dg_calls, &call_key))) {
5678 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
5679 new_matched_key->frame = pinfo->fd->num;
5680 new_matched_key->call_id = hdr->seqnum;
5681 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
5682 if (call_value->rep_frame == 0) {
5683 call_value->rep_frame = pinfo->fd->num;
5688 matched_key.frame = pinfo->fd->num;
5689 matched_key.call_id = hdr->seqnum;
5690 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
5692 value = wmem_new0(wmem_packet_scope(), dcerpc_call_value);
5693 value->uuid = hdr->if_id;
5694 value->ver = hdr->if_ver;
5695 value->object_uuid = hdr->obj_id;
5696 value->opnum = hdr->opnum;
5697 value->rep_frame = pinfo->fd->num;
5700 di = wmem_new0(wmem_packet_scope(), dcerpc_info);
5701 di->dcerpc_procedure_name = "";
5703 di->transport_salt = -1;
5704 di->ptype = PDU_RESP;
5705 di->call_data = value;
5707 if (value->req_frame != 0) {
5709 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
5710 tvb, 0, 0, value->req_frame);
5711 PROTO_ITEM_SET_GENERATED(pi);
5712 parent_pi = proto_tree_get_parent(dcerpc_tree);
5713 if (parent_pi != NULL) {
5714 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
5716 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
5717 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
5718 PROTO_ITEM_SET_GENERATED(pi);
5720 proto_tree_add_expert(dcerpc_tree, pinfo, &ei_dcerpc_no_request_found, tvb, 0, 0);
5722 dissect_dcerpc_dg_stub(tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
5726 dissect_dcerpc_dg_ping_ack(tvbuff_t *tvb, int offset, packet_info *pinfo,
5727 proto_tree *dcerpc_tree,
5728 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
5730 proto_item *parent_pi;
5731 /* if (!(pinfo->fd->flags.visited)) {*/
5732 dcerpc_call_value *call_value;
5733 dcerpc_dg_call_key call_key;
5735 call_key.conv = conv;
5736 call_key.seqnum = hdr->seqnum;
5737 call_key.act_id = hdr->act_id;
5739 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_dg_calls, &call_key))) {
5743 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
5744 tvb, 0, 0, call_value->req_frame);
5745 PROTO_ITEM_SET_GENERATED(pi);
5746 parent_pi = proto_tree_get_parent(dcerpc_tree);
5747 if (parent_pi != NULL) {
5748 proto_item_append_text(parent_pi, ", [Req: #%u]", call_value->req_frame);
5751 col_append_fstr(pinfo->cinfo, COL_INFO, " [req: #%u]", call_value->req_frame);
5753 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &call_value->req_time);
5754 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
5755 PROTO_ITEM_SET_GENERATED(pi);
5761 * DCERPC dissector for connectionless calls
5764 dissect_dcerpc_dg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5766 proto_item *ti = NULL;
5767 proto_item *tf = NULL;
5768 proto_tree *dcerpc_tree = NULL;
5769 proto_tree *drep_tree = NULL;
5770 e_dce_dg_common_hdr_t hdr;
5772 conversation_t *conv;
5775 const char *uuid_name = NULL;
5776 static const int * hdr_flags1[] = {
5777 &hf_dcerpc_dg_flags1_rsrvd_80,
5778 &hf_dcerpc_dg_flags1_broadcast,
5779 &hf_dcerpc_dg_flags1_idempotent,
5780 &hf_dcerpc_dg_flags1_maybe,
5781 &hf_dcerpc_dg_flags1_nofack,
5782 &hf_dcerpc_dg_flags1_frag,
5783 &hf_dcerpc_dg_flags1_last_frag,
5784 &hf_dcerpc_dg_flags1_rsrvd_01,
5788 static const int * hdr_flags2[] = {
5789 &hf_dcerpc_dg_flags2_rsrvd_80,
5790 &hf_dcerpc_dg_flags2_rsrvd_40,
5791 &hf_dcerpc_dg_flags2_rsrvd_20,
5792 &hf_dcerpc_dg_flags2_rsrvd_10,
5793 &hf_dcerpc_dg_flags2_rsrvd_08,
5794 &hf_dcerpc_dg_flags2_rsrvd_04,
5795 &hf_dcerpc_dg_flags2_cancel_pending,
5796 &hf_dcerpc_dg_flags2_rsrvd_01,
5801 * Check if this looks like a CL DCERPC call. All dg packets
5802 * have an 80 byte header on them. Which starts with
5803 * version (4), pkt_type.
5805 if (tvb_reported_length(tvb) < sizeof (hdr)) {
5809 /* Version must be 4 */
5810 hdr.rpc_ver = tvb_get_guint8(tvb, offset++);
5811 if (hdr.rpc_ver != 4)
5814 /* Type must be <= 19 or it's not DCE/RPC */
5815 hdr.ptype = tvb_get_guint8(tvb, offset++);
5819 /* flags1 has bit 1 and 8 as reserved so if any of them are set, it is
5820 probably not a DCE/RPC packet
5822 hdr.flags1 = tvb_get_guint8(tvb, offset++);
5823 if (hdr.flags1&0x81)
5826 /* flags2 has all bits except bit 2 as reserved so if any of them are set
5827 it is probably not DCE/RPC.
5829 hdr.flags2 = tvb_get_guint8(tvb, offset++);
5830 if (hdr.flags2&0xfd)
5834 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCERPC");
5835 col_add_str(pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
5837 tvb_memcpy(tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
5838 offset += (int)sizeof (hdr.drep);
5839 hdr.serial_hi = tvb_get_guint8(tvb, offset++);
5840 dcerpc_tvb_get_uuid(tvb, offset, hdr.drep, &hdr.obj_id);
5842 dcerpc_tvb_get_uuid(tvb, offset, hdr.drep, &hdr.if_id);
5844 dcerpc_tvb_get_uuid(tvb, offset, hdr.drep, &hdr.act_id);
5846 hdr.server_boot = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
5848 hdr.if_ver = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
5850 hdr.seqnum = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
5852 hdr.opnum = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5854 hdr.ihint = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5856 hdr.ahint = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5858 hdr.frag_len = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5860 hdr.frag_num = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5862 hdr.auth_proto = tvb_get_guint8(tvb, offset++);
5863 hdr.serial_lo = tvb_get_guint8(tvb, offset++);
5866 ti = proto_tree_add_item(tree, proto_dcerpc, tvb, 0, -1, ENC_NA);
5868 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
5869 proto_item_append_text(ti, " %s, Seq: %u, Serial: %u, Frag: %u, FragLen: %u",
5870 val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"),
5871 hdr.seqnum, hdr.serial_hi*256+hdr.serial_lo,
5872 hdr.frag_num, hdr.frag_len);
5877 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
5880 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
5883 proto_tree_add_bitmask_value(dcerpc_tree, tvb, offset, hf_dcerpc_dg_flags1,
5884 ett_dcerpc_dg_flags1, hdr_flags1, hdr.flags1);
5887 proto_tree_add_bitmask_value(dcerpc_tree, tvb, offset, hf_dcerpc_dg_flags2,
5888 ett_dcerpc_dg_flags2, hdr_flags2, hdr.flags2);
5892 tf = proto_tree_add_bytes(dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
5893 drep_tree = proto_item_add_subtree(tf, ett_dcerpc_drep);
5895 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
5896 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
5897 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
5898 proto_item_append_text(tf, " (Order: %s, Char: %s, Float: %s)",
5899 val_to_str_const(hdr.drep[0] >> 4, drep_byteorder_vals, "Unknown"),
5900 val_to_str_const(hdr.drep[0] & 0x0f, drep_character_vals, "Unknown"),
5901 val_to_str_const(hdr.drep[1], drep_fp_vals, "Unknown"));
5904 offset += (int)sizeof (hdr.drep);
5907 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
5911 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
5912 offset, 16, (e_guid_t *) &hdr.obj_id, "Object UUID: %s",
5913 guid_to_str(wmem_packet_scope(), (e_guid_t *) &hdr.obj_id));
5918 uuid_str = guid_to_str(wmem_packet_scope(), (e_guid_t*)&hdr.if_id);
5919 uuid_name = guids_get_uuid_name(&hdr.if_id);
5921 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
5922 offset, 16, (e_guid_t *) &hdr.if_id, "Interface: %s UUID: %s", uuid_name, uuid_str);
5924 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
5925 offset, 16, (e_guid_t *) &hdr.if_id, "Interface UUID: %s", uuid_str);
5931 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
5932 offset, 16, (e_guid_t *) &hdr.act_id, "Activity: %s",
5933 guid_to_str(wmem_packet_scope(), (e_guid_t *) &hdr.act_id));
5938 nstime_t server_boot;
5940 server_boot.secs = hdr.server_boot;
5941 server_boot.nsecs = 0;
5943 if (hdr.server_boot == 0)
5944 proto_tree_add_time_format_value(dcerpc_tree, hf_dcerpc_dg_server_boot,
5945 tvb, offset, 4, &server_boot,
5948 proto_tree_add_time(dcerpc_tree, hf_dcerpc_dg_server_boot,
5949 tvb, offset, 4, &server_boot);
5954 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
5958 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
5959 col_append_fstr(pinfo->cinfo, COL_INFO, ": seq: %u", hdr.seqnum);
5960 col_append_fstr(pinfo->cinfo, COL_DCE_CALL, "%u", hdr.seqnum);
5964 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
5968 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
5972 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
5976 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
5980 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
5981 if (hdr.flags1 & PFCL1_FRAG) {
5982 /* Fragmented - put the fragment number into the Info column */
5983 col_append_fstr(pinfo->cinfo, COL_INFO, " frag: %u",
5989 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
5993 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
5994 if (hdr.flags1 & PFCL1_FRAG) {
5995 /* Fragmented - put the serial number into the Info column */
5996 col_append_fstr(pinfo->cinfo, COL_INFO, " serial: %u",
5997 (hdr.serial_hi << 8) | hdr.serial_lo);
6003 * XXX - for Kerberos, we get a protection level; if it's
6004 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
6007 dissect_dcerpc_dg_auth(tvb, offset, dcerpc_tree, &hdr,
6012 * keeping track of the conversation shouldn't really be necessary
6013 * for connectionless packets, because everything we need to know
6014 * to dissect is in the header for each packet. Unfortunately,
6015 * Microsoft's implementation is buggy and often puts the
6016 * completely wrong if_id in the header. go figure. So, keep
6017 * track of the seqnum and use that if possible. Note: that's not
6018 * completely correct. It should really be done based on both the
6019 * activity_id and seqnum. I haven't seen anywhere that it would
6020 * make a difference, but for future reference...
6022 conv = find_or_create_conversation(pinfo);
6025 * Packet type specific stuff is next.
6028 switch (hdr.ptype) {
6030 case PDU_CANCEL_ACK:
6031 /* Body is optional */
6032 /* XXX - we assume "frag_len" is the length of the body */
6033 if (hdr.frag_len != 0)
6034 dissect_dcerpc_dg_cancel_ack(tvb, offset, pinfo, dcerpc_tree, &hdr);
6039 * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
6040 * but in at least one capture none of the Cl_cancel PDUs had a
6043 /* XXX - we assume "frag_len" is the length of the body */
6044 if (hdr.frag_len != 0)
6045 dissect_dcerpc_dg_cancel(tvb, offset, pinfo, dcerpc_tree, &hdr);
6049 /* Body is optional; if present, it's the same as PDU_FACK */
6050 /* XXX - we assume "frag_len" is the length of the body */
6051 if (hdr.frag_len != 0)
6052 dissect_dcerpc_dg_fack(tvb, offset, pinfo, dcerpc_tree, &hdr);
6056 /* Body is optional */
6057 /* XXX - we assume "frag_len" is the length of the body */
6058 if (hdr.frag_len != 0)
6059 dissect_dcerpc_dg_fack(tvb, offset, pinfo, dcerpc_tree, &hdr);
6064 dissect_dcerpc_dg_reject_fault(tvb, offset, pinfo, dcerpc_tree, &hdr);
6068 dissect_dcerpc_dg_rqst(tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
6072 dissect_dcerpc_dg_resp(tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
6075 /* these requests have no body */
6078 dissect_dcerpc_dg_ping_ack(tvb, offset, pinfo, dcerpc_tree, &hdr, conv);
6089 dcerpc_init_protocol(void)
6091 /* structures and data for BIND */
6092 dcerpc_binds = g_hash_table_new(dcerpc_bind_hash, dcerpc_bind_equal);
6094 /* structures and data for CALL */
6095 dcerpc_cn_calls = g_hash_table_new(dcerpc_cn_call_hash, dcerpc_cn_call_equal);
6096 dcerpc_dg_calls = g_hash_table_new(dcerpc_dg_call_hash, dcerpc_dg_call_equal);
6098 /* structure and data for MATCHED */
6099 dcerpc_matched = g_hash_table_new(dcerpc_matched_hash, dcerpc_matched_equal);
6100 decode_dcerpc_inject_bindings();
6104 dcerpc_cleanup_protocol(void)
6106 g_hash_table_destroy(dcerpc_binds);
6107 g_hash_table_destroy(dcerpc_cn_calls);
6108 g_hash_table_destroy(dcerpc_dg_calls);
6109 g_hash_table_destroy(dcerpc_matched);
6113 proto_register_dcerpc(void)
6115 static hf_register_info hf[] = {
6116 { &hf_dcerpc_request_in,
6117 { "Request in frame", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE,
6118 NULL, 0, "This packet is a response to the packet with this number", HFILL }},
6119 { &hf_dcerpc_response_in,
6120 { "Response in frame", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
6121 NULL, 0, "This packet will be responded in the packet with this number", HFILL }},
6122 { &hf_dcerpc_referent_id32,
6123 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
6124 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
6125 { &hf_dcerpc_referent_id64,
6126 { "Referent ID", "dcerpc.referent_id", FT_UINT64, BASE_HEX,
6127 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
6129 { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6130 { &hf_dcerpc_ver_minor,
6131 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6132 { &hf_dcerpc_packet_type,
6133 { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS(pckt_vals), 0x0, NULL, HFILL }},
6134 { &hf_dcerpc_cn_flags,
6135 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6136 { &hf_dcerpc_cn_flags_first_frag,
6137 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_FIRST_FRAG, NULL, HFILL }},
6138 { &hf_dcerpc_cn_flags_last_frag,
6139 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_LAST_FRAG, NULL, HFILL }},
6140 { &hf_dcerpc_cn_flags_cancel_pending,
6141 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_PENDING_CANCEL, NULL, HFILL }},
6142 { &hf_dcerpc_cn_flags_reserved,
6143 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_RESERVED_1, NULL, HFILL }},
6144 { &hf_dcerpc_cn_flags_mpx,
6145 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_CONC_MPX, NULL, HFILL }},
6146 { &hf_dcerpc_cn_flags_dne,
6147 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_DID_NOT_EXECUTE, NULL, HFILL }},
6148 { &hf_dcerpc_cn_flags_maybe,
6149 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_MAYBE, NULL, HFILL }},
6150 { &hf_dcerpc_cn_flags_object,
6151 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_OBJECT_UUID, NULL, HFILL }},
6153 { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6154 { &hf_dcerpc_drep_byteorder,
6155 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS(drep_byteorder_vals), 0x0, NULL, HFILL }},
6156 { &hf_dcerpc_ndr_padding,
6157 { "NDR-Padding", "dcerpc.ndr_padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6158 { &hf_dcerpc_drep_character,
6159 { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS(drep_character_vals), 0x0, NULL, HFILL }},
6160 { &hf_dcerpc_drep_fp,
6161 { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS(drep_fp_vals), 0x0, NULL, HFILL }},
6162 { &hf_dcerpc_cn_frag_len,
6163 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6164 { &hf_dcerpc_cn_auth_len,
6165 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6166 { &hf_dcerpc_cn_call_id,
6167 { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6168 { &hf_dcerpc_cn_max_xmit,
6169 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6170 { &hf_dcerpc_cn_max_recv,
6171 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6172 { &hf_dcerpc_cn_assoc_group,
6173 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6174 { &hf_dcerpc_cn_num_ctx_items,
6175 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6176 { &hf_dcerpc_cn_ctx_item,
6177 { "Ctx Item", "dcerpc.cn_ctx_item", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6178 { &hf_dcerpc_cn_ctx_id,
6179 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6180 { &hf_dcerpc_cn_num_trans_items,
6181 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6182 { &hf_dcerpc_cn_bind_abstract_syntax,
6183 { "Abstract Syntax", "dcerpc.cn_bind_abstract_syntax", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6184 { &hf_dcerpc_cn_bind_if_id,
6185 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6186 { &hf_dcerpc_cn_bind_if_ver,
6187 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6188 { &hf_dcerpc_cn_bind_if_ver_minor,
6189 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6190 { &hf_dcerpc_cn_bind_trans_syntax,
6191 { "Transfer Syntax", "dcerpc.cn_bind_trans", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6192 { &hf_dcerpc_cn_bind_trans_id,
6193 { "ID", "dcerpc.cn_bind_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6194 { &hf_dcerpc_cn_bind_trans_ver,
6195 { "ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6196 { &hf_dcerpc_cn_bind_trans_btfn_01, /* [MS-RPCE] 2.2.2.14 */
6197 { "Security Context Multiplexing Supported", "dcerpc.cn_bind_trans_btfn.01", FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x01, NULL, HFILL }},
6198 { &hf_dcerpc_cn_bind_trans_btfn_02,
6199 { "Keep Connection On Orphan Supported", "dcerpc.cn_bind_trans_btfn.02", FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x02, NULL, HFILL }},
6200 { &hf_dcerpc_cn_alloc_hint,
6201 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6202 { &hf_dcerpc_cn_sec_addr_len,
6203 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6204 { &hf_dcerpc_cn_sec_addr,
6205 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6206 { &hf_dcerpc_cn_num_results,
6207 { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6208 { &hf_dcerpc_cn_ack_result,
6209 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, NULL, HFILL }},
6210 { &hf_dcerpc_cn_ack_reason,
6211 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, NULL, HFILL }},
6212 { &hf_dcerpc_cn_ack_trans_id,
6213 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6214 { &hf_dcerpc_cn_ack_trans_ver,
6215 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6216 { &hf_dcerpc_cn_ack_btfn,
6217 { "Bind Time Feature Negotiation Bitmask", "dcerpc.cn_ack_btfn", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6218 { &hf_dcerpc_cn_reject_reason,
6219 { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, NULL, HFILL }},
6220 { &hf_dcerpc_cn_num_protocols,
6221 { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6222 { &hf_dcerpc_cn_protocol_ver_major,
6223 { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6224 { &hf_dcerpc_cn_protocol_ver_minor,
6225 { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6226 { &hf_dcerpc_cn_cancel_count,
6227 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6228 { &hf_dcerpc_cn_status,
6229 { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, NULL, HFILL }},
6230 { &hf_dcerpc_cn_deseg_req,
6231 { "Desegmentation Required", "dcerpc.cn_deseg_req", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6232 { &hf_dcerpc_auth_type,
6233 { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS(authn_protocol_vals), 0x0, NULL, HFILL }},
6234 { &hf_dcerpc_auth_level,
6235 { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, NULL, HFILL }},
6236 { &hf_dcerpc_auth_pad_len,
6237 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6238 { &hf_dcerpc_auth_rsrvd,
6239 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6240 { &hf_dcerpc_auth_ctx_id,
6241 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6242 { &hf_dcerpc_dg_flags1,
6243 { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6244 { &hf_dcerpc_dg_flags1_rsrvd_01,
6245 { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_RESERVED_01, NULL, HFILL }},
6246 { &hf_dcerpc_dg_flags1_last_frag,
6247 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_LASTFRAG, NULL, HFILL }},
6248 { &hf_dcerpc_dg_flags1_frag,
6249 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_FRAG, NULL, HFILL }},
6250 { &hf_dcerpc_dg_flags1_nofack,
6251 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_NOFACK, NULL, HFILL }},
6252 { &hf_dcerpc_dg_flags1_maybe,
6253 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_MAYBE, NULL, HFILL }},
6254 { &hf_dcerpc_dg_flags1_idempotent,
6255 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_IDEMPOTENT, NULL, HFILL }},
6256 { &hf_dcerpc_dg_flags1_broadcast,
6257 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_BROADCAST, NULL, HFILL }},
6258 { &hf_dcerpc_dg_flags1_rsrvd_80,
6259 { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_RESERVED_80, NULL, HFILL }},
6260 { &hf_dcerpc_dg_flags2,
6261 { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6262 { &hf_dcerpc_dg_flags2_rsrvd_01,
6263 { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_01, NULL, HFILL }},
6264 { &hf_dcerpc_dg_flags2_cancel_pending,
6265 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_CANCEL_PENDING, NULL, HFILL }},
6266 { &hf_dcerpc_dg_flags2_rsrvd_04,
6267 { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_04, NULL, HFILL }},
6268 { &hf_dcerpc_dg_flags2_rsrvd_08,
6269 { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_08, NULL, HFILL }},
6270 { &hf_dcerpc_dg_flags2_rsrvd_10,
6271 { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_10, NULL, HFILL }},
6272 { &hf_dcerpc_dg_flags2_rsrvd_20,
6273 { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_20, NULL, HFILL }},
6274 { &hf_dcerpc_dg_flags2_rsrvd_40,
6275 { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_40, NULL, HFILL }},
6276 { &hf_dcerpc_dg_flags2_rsrvd_80,
6277 { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_80, NULL, HFILL }},
6278 { &hf_dcerpc_dg_serial_lo,
6279 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6280 { &hf_dcerpc_dg_serial_hi,
6281 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6282 { &hf_dcerpc_dg_ahint,
6283 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6284 { &hf_dcerpc_dg_ihint,
6285 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6286 { &hf_dcerpc_dg_frag_len,
6287 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6288 { &hf_dcerpc_dg_frag_num,
6289 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6290 { &hf_dcerpc_dg_auth_proto,
6291 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS(authn_protocol_vals), 0x0, NULL, HFILL }},
6292 { &hf_dcerpc_dg_seqnum,
6293 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6294 { &hf_dcerpc_dg_server_boot,
6295 { "Server boot time", "dcerpc.dg_server_boot", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0, NULL, HFILL }},
6296 { &hf_dcerpc_dg_if_ver,
6297 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6298 { &hf_dcerpc_krb5_av_prot_level,
6299 { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, NULL, HFILL }},
6300 { &hf_dcerpc_krb5_av_key_vers_num,
6301 { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6302 { &hf_dcerpc_krb5_av_key_auth_verifier,
6303 { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6304 { &hf_dcerpc_obj_id,
6305 { "Object", "dcerpc.obj_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6306 { &hf_dcerpc_dg_if_id,
6307 { "Interface", "dcerpc.dg_if_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6308 { &hf_dcerpc_dg_act_id,
6309 { "Activity", "dcerpc.dg_act_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6311 { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6313 { &hf_dcerpc_dg_cancel_vers,
6314 { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6316 { &hf_dcerpc_dg_cancel_id,
6317 { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6319 { &hf_dcerpc_dg_server_accepting_cancels,
6320 { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6322 { &hf_dcerpc_dg_fack_vers,
6323 { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6325 { &hf_dcerpc_dg_fack_window_size,
6326 { "Window Size", "dcerpc.fack_window_size", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6328 { &hf_dcerpc_dg_fack_max_tsdu,
6329 { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6331 { &hf_dcerpc_dg_fack_max_frag_size,
6332 { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6334 { &hf_dcerpc_dg_fack_serial_num,
6335 { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6337 { &hf_dcerpc_dg_fack_selack_len,
6338 { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6340 { &hf_dcerpc_dg_fack_selack,
6341 { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6343 { &hf_dcerpc_dg_status,
6344 { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, NULL, HFILL }},
6346 { &hf_dcerpc_array_max_count,
6347 { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
6349 { &hf_dcerpc_array_offset,
6350 { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
6352 { &hf_dcerpc_array_actual_count,
6353 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
6356 { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6358 { &hf_dcerpc_null_pointer,
6359 { "NULL Pointer", "dcerpc.null_pointer", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6361 { &hf_dcerpc_fragments,
6362 { "Reassembled DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
6363 NULL, 0x0, "DCE/RPC Fragments", HFILL }},
6365 { &hf_dcerpc_fragment,
6366 { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM, BASE_NONE,
6367 NULL, 0x0, NULL, HFILL }},
6369 { &hf_dcerpc_fragment_overlap,
6370 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE,
6371 NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
6373 { &hf_dcerpc_fragment_overlap_conflict,
6374 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE,
6375 NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
6377 { &hf_dcerpc_fragment_multiple_tails,
6378 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE,
6379 NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
6381 { &hf_dcerpc_fragment_too_long_fragment,
6382 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE,
6383 NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
6385 { &hf_dcerpc_fragment_error,
6386 { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE,
6387 NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
6389 { &hf_dcerpc_fragment_count,
6390 { "Fragment count", "dcerpc.fragment.count", FT_UINT32, BASE_DEC,
6391 NULL, 0x0, NULL, HFILL }},
6394 { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE,
6395 NULL, 0, "Time between Request and Response for DCE-RPC calls", HFILL }},
6397 { &hf_dcerpc_reassembled_in,
6398 { "Reassembled PDU in frame", "dcerpc.reassembled_in", FT_FRAMENUM, BASE_NONE,
6399 NULL, 0x0, "The DCE/RPC PDU is completely reassembled in the packet with this number", HFILL }},
6401 { &hf_dcerpc_reassembled_length,
6402 { "Reassembled DCE/RPC length", "dcerpc.reassembled.length", FT_UINT32, BASE_DEC,
6403 NULL, 0x0, "The total length of the reassembled payload", HFILL }},
6405 { &hf_dcerpc_unknown_if_id,
6406 { "Unknown DCERPC interface id", "dcerpc.unknown_if_id", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6408 { &hf_dcerpc_cn_rts_flags,
6409 { "RTS Flags", "dcerpc.cn_rts_flags", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6410 { &hf_dcerpc_cn_rts_flags_none,
6411 {"None", "dcerpc.cn_rts_flags.none", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_NONE, NULL, HFILL }},
6412 { &hf_dcerpc_cn_rts_flags_ping,
6413 { "Ping", "dcerpc.cn_rts.flags.ping", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_PING, NULL, HFILL }},
6414 { &hf_dcerpc_cn_rts_flags_other_cmd,
6415 { "Other Cmd", "dcerpc.cn_rts_flags.other_cmd", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_OTHER_CMD, NULL, HFILL }},
6416 { &hf_dcerpc_cn_rts_flags_recycle_channel,
6417 { "Recycle Channel", "dcerpc.cn_rts_flags.recycle_channel", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_RECYCLE_CHANNEL, NULL, HFILL }},
6418 { &hf_dcerpc_cn_rts_flags_in_channel,
6419 { "In Channel", "dcerpc.cn_rts_flags.in_channel", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_IN_CHANNEL, NULL, HFILL }},
6420 { &hf_dcerpc_cn_rts_flags_out_channel,
6421 { "Out Channel", "dcerpc.cn_rts_flags.out_channel", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_OUT_CHANNEL, NULL, HFILL }},
6422 { &hf_dcerpc_cn_rts_flags_eof,
6423 { "EOF", "dcerpc.cn_rts_flags.eof", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_EOF, NULL, HFILL }},
6424 { &hf_dcerpc_cn_rts_commands_nb,
6425 { "RTS Number of Commands", "dcerpc.cn_rts_commands_nb", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6426 { &hf_dcerpc_cn_rts_command,
6427 { "RTS Command", "dcerpc.cn_rts_command", FT_UINT32, BASE_HEX, VALS(rts_command_vals), 0x0, NULL, HFILL }},
6428 { &hf_dcerpc_cn_rts_command_receivewindowsize,
6429 {"Receive Window Size", "dcerpc.cn_rts_command.receivewindowsize", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6430 { &hf_dcerpc_cn_rts_command_fack_bytesreceived,
6431 {"Bytes Received", "dcerpc.cn_rts_command.fack.bytesreceived", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6432 { &hf_dcerpc_cn_rts_command_fack_availablewindow,
6433 {"Available Window", "dcerpc.cn_rts_command.fack.availablewindow", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6434 { &hf_dcerpc_cn_rts_command_fack_channelcookie,
6435 {"Channel Cookie", "dcerpc.cn_rts_command.fack.channelcookie", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6436 { &hf_dcerpc_cn_rts_command_connectiontimeout,
6437 {"Connection Timeout", "dcerpc.cn_rts_command.connectiontimeout", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6438 { &hf_dcerpc_cn_rts_command_cookie,
6439 {"Cookie", "dcerpc.cn_rts_command.cookie", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6440 { &hf_dcerpc_cn_rts_command_channellifetime,
6441 {"Channel Lifetime", "dcerpc.cn_rts_command.channellifetime", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6442 { &hf_dcerpc_cn_rts_command_clientkeepalive,
6443 {"Client Keepalive", "dcerpc.cn_rts_command.clientkeepalive", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6444 { &hf_dcerpc_cn_rts_command_version,
6445 {"Version", "dcerpc.cn_rts_command.version", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6446 { &hf_dcerpc_cn_rts_command_conformancecount,
6447 {"Conformance Count", "dcerpc.cn_rts_command.padding.conformancecount", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6448 { &hf_dcerpc_cn_rts_command_padding,
6449 { "Padding", "dcerpc.cn_rts_command.padding.padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
6450 { &hf_dcerpc_cn_rts_command_addrtype,
6451 { "Address Type", "dcerpc.cn_rts_command.addrtype", FT_UINT32, BASE_DEC, VALS(rts_addresstype_vals), 0x0, NULL, HFILL }},
6452 { &hf_dcerpc_cn_rts_command_associationgroupid,
6453 {"Association Group ID", "dcerpc.cn_rts_command.associationgroupid", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6454 { &hf_dcerpc_cn_rts_command_forwarddestination,
6455 {"Forward Destination", "dcerpc.cn_rts_command.forwarddestination", FT_UINT32, BASE_DEC, VALS(rts_forward_destination_vals), 0x0, NULL, HFILL }},
6456 { &hf_dcerpc_cn_rts_command_pingtrafficsentnotify,
6457 {"Ping Traffic Sent Notify", "dcerpc.cn_rts_command.pingtrafficsentnotify", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6458 /* Generated from convert_proto_tree_add_text.pl */
6459 { &hf_dcerpc_duplicate_ptr, { "duplicate PTR", "dcerpc.duplicate_ptr", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6460 { &hf_dcerpc_encrypted_stub_data, { "Encrypted stub data", "dcerpc.encrypted_stub_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6461 { &hf_dcerpc_decrypted_stub_data, { "Decrypted stub data", "dcerpc.decrypted_stub_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6462 { &hf_dcerpc_stub_data, { "Stub data", "dcerpc.stub_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6463 { &hf_dcerpc_auth_padding, { "Auth Padding", "dcerpc.auth_padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6464 { &hf_dcerpc_auth_verifier, { "Auth Verifier", "dcerpc.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6465 { &hf_dcerpc_auth_credentials, { "Auth Credentials", "dcerpc.auth_credentials", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6466 { &hf_dcerpc_fault_stub_data, { "Fault stub data", "dcerpc.fault_stub_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6467 { &hf_dcerpc_fragment_data, { "Fragment data", "dcerpc.fragment_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6468 { &hf_dcerpc_cmd_client_ipv4, { "RTS Client address", "dcerpc.cmd_client_ipv4", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6469 { &hf_dcerpc_cmd_client_ipv6, { "RTS Client address", "dcerpc.cmd_client_ipv6", FT_IPv6, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6470 { &hf_dcerpc_authentication_verifier, { "Authentication verifier", "dcerpc.authentication_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6472 static gint *ett[] = {
6474 &ett_dcerpc_cn_flags,
6476 &ett_dcerpc_cn_iface,
6477 &ett_dcerpc_cn_trans_syntax,
6478 &ett_dcerpc_cn_trans_btfn,
6479 &ett_dcerpc_cn_rts_flags,
6480 &ett_dcerpc_cn_rts_command,
6481 &ett_dcerpc_cn_rts_pdu,
6483 &ett_dcerpc_dg_flags1,
6484 &ett_dcerpc_dg_flags2,
6485 &ett_dcerpc_pointer_data,
6487 &ett_dcerpc_fragments,
6488 &ett_dcerpc_fragment,
6489 &ett_dcerpc_krb5_auth_verf,
6492 static ei_register_info ei[] = {
6493 { &ei_dcerpc_fragment, { "dcerpc.fragment", PI_REASSEMBLE, PI_CHAT, "%s fragment", EXPFILL }},
6494 { &ei_dcerpc_fragment_reassembled, { "dcerpc.fragment_reassembled", PI_REASSEMBLE, PI_CHAT, "%s fragment, reassembled", EXPFILL }},
6495 { &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 }},
6496 { &ei_dcerpc_no_request_found, { "dcerpc.no_request_found", PI_SEQUENCE, PI_NOTE, "No request to this DCE/RPC call found", EXPFILL }},
6497 { &ei_dcerpc_cn_status, { "dcerpc.cn_status.expert", PI_RESPONSE_CODE, PI_NOTE, "Fault: %s", EXPFILL }},
6498 { &ei_dcerpc_fragment_multiple, { "dcerpc.fragment_multiple", PI_SEQUENCE, PI_CHAT, "Multiple DCE/RPC fragments/PDU's in one packet", EXPFILL }},
6499 { &ei_dcerpc_context_change, { "dcerpc.context_change", PI_SEQUENCE, PI_CHAT, "Context change: %s", EXPFILL }},
6500 { &ei_dcerpc_bind_not_acknowledged, { "dcerpc.bind_not_acknowledged", PI_SEQUENCE, PI_WARN, "Bind not acknowledged", EXPFILL }},
6501 { &ei_dcerpc_verifier_unavailable, { "dcerpc.verifier_unavailable", PI_UNDECODED, PI_WARN, NULL, EXPFILL }},
6502 { &ei_dcerpc_invalid_pdu_authentication_attempt, { "dcerpc.invalid_pdu_authentication_attempt", PI_UNDECODED, PI_WARN, NULL, EXPFILL }},
6503 /* Generated from convert_proto_tree_add_text.pl */
6504 { &ei_dcerpc_long_frame, { "dcerpc.long_frame", PI_PROTOCOL, PI_WARN, "Long frame", EXPFILL }},
6505 { &ei_dcerpc_cn_rts_command, { "dcerpc.cn_rts_command.unknown", PI_PROTOCOL, PI_WARN, "unknown RTS command number", EXPFILL }},
6508 /* Decode As handling */
6509 static build_valid_func dcerpc_da_build_value[1] = {dcerpc_value};
6510 static decode_as_value_t dcerpc_da_values = {dcerpc_prompt, 1, dcerpc_da_build_value};
6511 static decode_as_t dcerpc_da = {"dcerpc", "DCE-RPC",
6512 /* XXX - DCE/RPC doesn't have a true (sub)dissector table, so
6513 provide a "fake" one to fit the Decode As algorithm */
6515 1, 0, &dcerpc_da_values, NULL, NULL,
6516 dcerpc_populate_list, decode_dcerpc_binding_reset, dcerpc_decode_as_change, dcerpc_decode_as_free};
6518 module_t *dcerpc_module;
6519 expert_module_t* expert_dcerpc;
6521 proto_dcerpc = proto_register_protocol("Distributed Computing Environment / Remote Procedure Call (DCE/RPC)", "DCERPC", "dcerpc");
6522 proto_register_field_array(proto_dcerpc, hf, array_length(hf));
6523 proto_register_subtree_array(ett, array_length(ett));
6524 expert_dcerpc = expert_register_protocol(proto_dcerpc);
6525 expert_register_field_array(expert_dcerpc, ei, array_length(ei));
6527 register_init_routine(dcerpc_init_protocol);
6528 register_cleanup_routine(dcerpc_cleanup_protocol);
6529 dcerpc_module = prefs_register_protocol(proto_dcerpc, NULL);
6530 prefs_register_bool_preference(dcerpc_module,
6532 "Reassemble DCE/RPC messages spanning multiple TCP segments",
6533 "Whether the DCE/RPC dissector should reassemble messages"
6534 " spanning multiple TCP segments."
6535 " To use this option, you must also enable"
6536 " \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
6537 &dcerpc_cn_desegment);
6538 prefs_register_bool_preference(dcerpc_module,
6539 "reassemble_dcerpc",
6540 "Reassemble DCE/RPC fragments",
6541 "Whether the DCE/RPC dissector should reassemble fragmented DCE/RPC PDUs",
6542 &dcerpc_reassemble);
6543 register_init_routine(dcerpc_reassemble_init);
6544 dcerpc_uuids = g_hash_table_new(dcerpc_uuid_hash, dcerpc_uuid_equal);
6545 dcerpc_tap = register_tap("dcerpc");
6547 register_decode_as(&dcerpc_da);
6549 register_srt_table(proto_dcerpc, NULL, 1, dcerpcstat_packet, dcerpcstat_init, dcerpcstat_param);
6553 proto_reg_handoff_dcerpc(void)
6555 heur_dissector_add("tcp", dissect_dcerpc_tcp, "DCE/RPC over TCP", "dcerpc_tcp", proto_dcerpc, HEURISTIC_ENABLE);
6556 heur_dissector_add("netbios", dissect_dcerpc_cn_pk, "DCE/RPC over NetBios", "dcerpc_netbios", proto_dcerpc, HEURISTIC_ENABLE);
6557 heur_dissector_add("udp", dissect_dcerpc_dg, "DCE/RPC over UDP", "dcerpc_udp", proto_dcerpc, HEURISTIC_ENABLE);
6558 heur_dissector_add("smb_transact", dissect_dcerpc_cn_smbpipe, "DCE/RPC over SMB", "dcerpc_smb_transact", proto_dcerpc, HEURISTIC_ENABLE);
6559 heur_dissector_add("smb2_heur_subdissectors", dissect_dcerpc_cn_smb2, "DCE/RPC over SMB2", "dcerpc_smb2", proto_dcerpc, HEURISTIC_ENABLE);
6560 heur_dissector_add("http", dissect_dcerpc_cn_bs, "DCE/RPC over HTTP", "dcerpc_http", proto_dcerpc, HEURISTIC_ENABLE);
6561 dcerpc_smb_init(proto_dcerpc);
6563 guids_add_uuid(&uuid_data_repr_proto, "32bit NDR");
6564 guids_add_uuid(&uuid_ndr64, "64bit NDR");
6565 guids_add_uuid(&uuid_bind_time_feature_nego_00, "bind time feature negotiation");
6566 guids_add_uuid(&uuid_bind_time_feature_nego_01, "bind time feature negotiation");
6567 guids_add_uuid(&uuid_bind_time_feature_nego_02, "bind time feature negotiation");
6568 guids_add_uuid(&uuid_bind_time_feature_nego_03, "bind time feature negotiation");
6569 guids_add_uuid(&uuid_asyncemsmdb, "async MAPI");
6573 * Editor modelines - http://www.wireshark.org/tools/modelines.html
6578 * indent-tabs-mode: nil
6581 * vi: set shiftwidth=4 tabstop=8 expandtab:
6582 * :indentSize=4:tabSize=8:noTabs=true: