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/expert.h>
39 #include <epan/addr_resolv.h>
40 #include <epan/show_exception.h>
41 #include <epan/decode_as.h>
42 #include "packet-tcp.h"
43 #include "packet-dcerpc.h"
44 #include "packet-dcerpc-nt.h"
46 void proto_register_dcerpc(void);
47 void proto_reg_handoff_dcerpc(void);
49 static int dcerpc_tap = -1;
51 /* 32bit Network Data Representation, see DCE/RPC Appendix I */
52 static e_uuid_t uuid_data_repr_proto = { 0x8a885d04, 0x1ceb, 0x11c9,
53 { 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60 } };
55 /* 64bit Network Data Representation, introduced in Windows Server 2008 */
56 static e_uuid_t uuid_ndr64 = { 0x71710533, 0xbeba, 0x4937,
57 { 0x83, 0x19, 0xb5, 0xdb, 0xef, 0x9c, 0xcc, 0x36 } };
59 /* Bind Time Feature Negotiation, see [MS-RPCE] 3.3.1.5.3 */
60 static e_uuid_t uuid_bind_time_feature_nego_00 = { 0x6cb71c2c, 0x9812, 0x4540, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
61 static e_uuid_t uuid_bind_time_feature_nego_01 = { 0x6cb71c2c, 0x9812, 0x4540, { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
62 static e_uuid_t uuid_bind_time_feature_nego_02 = { 0x6cb71c2c, 0x9812, 0x4540, { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
63 static e_uuid_t uuid_bind_time_feature_nego_03 = { 0x6cb71c2c, 0x9812, 0x4540, { 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
65 /* see [MS-OXRPC] Appendix A: Full IDL, http://msdn.microsoft.com/en-us/library/ee217991%28v=exchg.80%29.aspx */
66 static e_uuid_t uuid_asyncemsmdb = { 0x5261574a, 0x4572, 0x206e,
67 { 0xb2, 0x68, 0x6b, 0x19, 0x92, 0x13, 0xb4, 0xe4 } };
69 static const value_string pckt_vals[] = {
70 { PDU_REQ, "Request"},
72 { PDU_RESP, "Response"},
73 { PDU_FAULT, "Fault"},
74 { PDU_WORKING, "Working"},
75 { PDU_NOCALL, "Nocall"},
76 { PDU_REJECT, "Reject"},
78 { PDU_CL_CANCEL, "Cl_cancel"},
80 { PDU_CANCEL_ACK, "Cancel_ack"},
82 { PDU_BIND_ACK, "Bind_ack"},
83 { PDU_BIND_NAK, "Bind_nak"},
84 { PDU_ALTER, "Alter_context"},
85 { PDU_ALTER_ACK, "Alter_context_resp"},
86 { PDU_AUTH3, "AUTH3"},
87 { PDU_SHUTDOWN, "Shutdown"},
88 { PDU_CO_CANCEL, "Co_cancel"},
89 { PDU_ORPHANED, "Orphaned"},
90 { PDU_RTS, "RPC-over-HTTP RTS"},
94 static const value_string drep_byteorder_vals[] = {
96 { 1, "Little-endian" },
100 static const value_string drep_character_vals[] = {
106 #define DCE_RPC_DREP_FP_IEEE 0
107 #define DCE_RPC_DREP_FP_VAX 1
108 #define DCE_RPC_DREP_FP_CRAY 2
109 #define DCE_RPC_DREP_FP_IBM 3
111 static const value_string drep_fp_vals[] = {
112 { DCE_RPC_DREP_FP_IEEE, "IEEE" },
113 { DCE_RPC_DREP_FP_VAX, "VAX" },
114 { DCE_RPC_DREP_FP_CRAY, "Cray" },
115 { DCE_RPC_DREP_FP_IBM, "IBM" },
120 * Authentication services.
122 static const value_string authn_protocol_vals[] = {
123 { DCE_C_RPC_AUTHN_PROTOCOL_NONE, "None" },
124 { DCE_C_RPC_AUTHN_PROTOCOL_KRB5, "Kerberos 5" },
125 { DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO, "SPNEGO" },
126 { DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP, "NTLMSSP" },
127 { DCE_C_RPC_AUTHN_PROTOCOL_GSS_SCHANNEL, "SCHANNEL SSP" },
128 { DCE_C_RPC_AUTHN_PROTOCOL_GSS_KERBEROS, "Kerberos SSP" },
129 { DCE_C_RPC_AUTHN_PROTOCOL_DPA,
130 "Distributed Password Authentication SSP"},
131 { DCE_C_RPC_AUTHN_PROTOCOL_MSN, "MSN SSP"},
132 { DCE_C_RPC_AUTHN_PROTOCOL_DIGEST, "Digest SSP"},
133 { DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN, "NETLOGON Secure Channel" },
134 { DCE_C_RPC_AUTHN_PROTOCOL_MQ, "MSMQ SSP"},
141 static const value_string authn_level_vals[] = {
142 { DCE_C_AUTHN_LEVEL_NONE, "None" },
143 { DCE_C_AUTHN_LEVEL_CONNECT, "Connect" },
144 { DCE_C_AUTHN_LEVEL_CALL, "Call" },
145 { DCE_C_AUTHN_LEVEL_PKT, "Packet" },
146 { DCE_C_AUTHN_LEVEL_PKT_INTEGRITY, "Packet integrity" },
147 { DCE_C_AUTHN_LEVEL_PKT_PRIVACY, "Packet privacy" },
152 * Flag bits in first flag field in connectionless PDU header.
154 #define PFCL1_RESERVED_01 0x01 /* Reserved for use by implementations */
155 #define PFCL1_LASTFRAG 0x02 /* If set, the PDU is the last
156 * fragment of a multi-PDU
158 #define PFCL1_FRAG 0x04 /* If set, the PDU is a fragment of
159 a multi-PDU transmission */
160 #define PFCL1_NOFACK 0x08 /* If set, the receiver is not
161 * requested to send a `fack' PDU
162 * for the fragment */
163 #define PFCL1_MAYBE 0x10 /* If set, the PDU is for a `maybe'
165 #define PFCL1_IDEMPOTENT 0x20 /* If set, the PDU is for an idempotent
167 #define PFCL1_BROADCAST 0x40 /* If set, the PDU is for a broadcast
169 #define PFCL1_RESERVED_80 0x80 /* Reserved for use by implementations */
172 * Flag bits in second flag field in connectionless PDU header.
174 #define PFCL2_RESERVED_01 0x01 /* Reserved for use by implementations */
175 #define PFCL2_CANCEL_PENDING 0x02 /* Cancel pending at the call end */
176 #define PFCL2_RESERVED_04 0x04 /* Reserved for future use */
177 #define PFCL2_RESERVED_08 0x08 /* Reserved for future use */
178 #define PFCL2_RESERVED_10 0x10 /* Reserved for future use */
179 #define PFCL2_RESERVED_20 0x20 /* Reserved for future use */
180 #define PFCL2_RESERVED_40 0x40 /* Reserved for future use */
181 #define PFCL2_RESERVED_80 0x80 /* Reserved for future use */
184 * Flag bits in connection-oriented PDU header.
186 #define PFC_FIRST_FRAG 0x01 /* First fragment */
187 #define PFC_LAST_FRAG 0x02 /* Last fragment */
188 #define PFC_PENDING_CANCEL 0x04 /* Cancel was pending at sender */
189 #define PFC_RESERVED_1 0x08
190 #define PFC_CONC_MPX 0x10 /* supports concurrent multiplexing
191 * of a single connection. */
192 #define PFC_DID_NOT_EXECUTE 0x20 /* only meaningful on `fault' packet;
193 * if true, guaranteed call did not
195 #define PFC_MAYBE 0x40 /* `maybe' call semantics requested */
196 #define PFC_OBJECT_UUID 0x80 /* if true, a non-nil object UUID
197 * was specified in the handle, and
198 * is present in the optional object
199 * field. If false, the object field
203 * Tests whether a connection-oriented PDU is fragmented; returns TRUE if
204 * it's not fragmented (i.e., this is both the first *and* last fragment),
205 * and FALSE otherwise.
207 #define PFC_NOT_FRAGMENTED(hdr) \
208 ((hdr->flags&(PFC_FIRST_FRAG|PFC_LAST_FRAG)) == (PFC_FIRST_FRAG|PFC_LAST_FRAG))
211 * Presentation context negotiation result.
213 static const value_string p_cont_result_vals[] = {
215 { 1, "User rejection" },
216 { 2, "Provider rejection" },
217 { 3, "Negotiate ACK" }, /* [MS-RPCE] 2.2.2.4 */
222 * Presentation context negotiation rejection reasons.
224 static const value_string p_provider_reason_vals[] = {
225 { 0, "Reason not specified" },
226 { 1, "Abstract syntax not supported" },
227 { 2, "Proposed transfer syntaxes not supported" },
228 { 3, "Local limit exceeded" },
235 #define REASON_NOT_SPECIFIED 0
236 #define TEMPORARY_CONGESTION 1
237 #define LOCAL_LIMIT_EXCEEDED 2
238 #define CALLED_PADDR_UNKNOWN 3 /* not used */
239 #define PROTOCOL_VERSION_NOT_SUPPORTED 4
240 #define DEFAULT_CONTEXT_NOT_SUPPORTED 5 /* not used */
241 #define USER_DATA_NOT_READABLE 6 /* not used */
242 #define NO_PSAP_AVAILABLE 7 /* not used */
243 #define AUTH_TYPE_NOT_RECOGNIZED 8 /* [MS-RPCE] 2.2.2.5 */
244 #define INVALID_CHECKSUM 9 /* [MS-RPCE] 2.2.2.5 */
246 static const value_string reject_reason_vals[] = {
247 { REASON_NOT_SPECIFIED, "Reason not specified" },
248 { TEMPORARY_CONGESTION, "Temporary congestion" },
249 { LOCAL_LIMIT_EXCEEDED, "Local limit exceeded" },
250 { CALLED_PADDR_UNKNOWN, "Called paddr unknown" },
251 { PROTOCOL_VERSION_NOT_SUPPORTED, "Protocol version not supported" },
252 { DEFAULT_CONTEXT_NOT_SUPPORTED, "Default context not supported" },
253 { USER_DATA_NOT_READABLE, "User data not readable" },
254 { NO_PSAP_AVAILABLE, "No PSAP available" },
255 { AUTH_TYPE_NOT_RECOGNIZED, "Authentication type not recognized" },
256 { INVALID_CHECKSUM, "Invalid checksum" },
261 * Reject status codes.
263 static const value_string reject_status_vals[] = {
264 { 0, "Stub-defined exception" },
265 { 0x00000001, "nca_s_fault_other" },
266 { 0x00000005, "nca_s_fault_access_denied" },
267 { 0x000006f7, "nca_s_fault_ndr" },
268 { 0x000006d8, "nca_s_fault_cant_perform" },
269 { 0x1c000001, "nca_s_fault_int_div_by_zero" },
270 { 0x1c000002, "nca_s_fault_addr_error" },
271 { 0x1c000003, "nca_s_fault_fp_div_zero" },
272 { 0x1c000004, "nca_s_fault_fp_underflow" },
273 { 0x1c000005, "nca_s_fault_fp_overflow" },
274 { 0x1c000006, "nca_s_fault_invalid_tag" },
275 { 0x1c000007, "nca_s_fault_invalid_bound" },
276 { 0x1c000008, "nca_rpc_version_mismatch" },
277 { 0x1c000009, "nca_unspec_reject" },
278 { 0x1c00000a, "nca_s_bad_actid" },
279 { 0x1c00000b, "nca_who_are_you_failed" },
280 { 0x1c00000c, "nca_manager_not_entered" },
281 { 0x1c00000d, "nca_s_fault_cancel" },
282 { 0x1c00000e, "nca_s_fault_ill_inst" },
283 { 0x1c00000f, "nca_s_fault_fp_error" },
284 { 0x1c000010, "nca_s_fault_int_overflow" },
285 { 0x1c000014, "nca_s_fault_pipe_empty" },
286 { 0x1c000015, "nca_s_fault_pipe_closed" },
287 { 0x1c000016, "nca_s_fault_pipe_order" },
288 { 0x1c000017, "nca_s_fault_pipe_discipline" },
289 { 0x1c000018, "nca_s_fault_pipe_comm_error" },
290 { 0x1c000019, "nca_s_fault_pipe_memory" },
291 { 0x1c00001a, "nca_s_fault_context_mismatch" },
292 { 0x1c00001b, "nca_s_fault_remote_no_memory" },
293 { 0x1c00001c, "nca_invalid_pres_context_id" },
294 { 0x1c00001d, "nca_unsupported_authn_level" },
295 { 0x1c00001f, "nca_invalid_checksum" },
296 { 0x1c000020, "nca_invalid_crc" },
297 { 0x1c000021, "ncs_s_fault_user_defined" },
298 { 0x1c000022, "nca_s_fault_tx_open_failed" },
299 { 0x1c000023, "nca_s_fault_codeset_conv_error" },
300 { 0x1c000024, "nca_s_fault_object_not_found" },
301 { 0x1c000025, "nca_s_fault_no_client_stub" },
302 { 0x1c010002, "nca_op_rng_error" },
303 { 0x1c010003, "nca_unk_if"},
304 { 0x1c010006, "nca_wrong_boot_time" },
305 { 0x1c010009, "nca_s_you_crashed" },
306 { 0x1c01000b, "nca_proto_error" },
307 { 0x1c010013, "nca_out_args_too_big" },
308 { 0x1c010014, "nca_server_too_busy" },
309 { 0x1c010017, "nca_unsupported_type" },
310 /* MS Windows specific values
311 * see: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/system_error_codes__1700-3999_.asp
312 * and: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/seccrypto/security/common_hresult_values.asp
313 * and: http://www.megos.ch/support/doserrors.txt
315 * XXX - we might need a way to dynamically add entries here, as higher layer protocols use these values too,
316 * at least MS protocols (like DCOM) do it that way ... */
317 { 0x80004001, "E_NOTIMPL" },
318 { 0x80004003, "E_POINTER" },
319 { 0x80004004, "E_ABORT" },
320 { 0x8000FFFF, "E_UNEXPECTED" },
321 { 0x80010105, "RPC_E_SERVERFAULT" },
322 { 0x80010108, "RPC_E_DISCONNECTED" },
323 { 0x80010113, "RPC_E_INVALID_IPID" },
324 { 0x8001011F, "RPC_E_TIMEOUT" },
325 { 0x80020003, "DISP_E_MEMBERNOTFOUND" },
326 { 0x80020006, "DISP_E_UNKNOWNNAME" },
327 { 0x8002000E, "DISP_E_BADPARAMCOUNT" },
328 { 0x8004CB00, "CBA_E_MALFORMED" },
329 { 0x8004CB01, "CBA_E_UNKNOWNOBJECT" },
330 { 0x8004CB05, "CBA_E_INVALIDID" },
331 { 0x8004CB09, "CBA_E_INVALIDCOOKIE" },
332 { 0x8004CB0B, "CBA_E_QOSTYPEUNSUPPORTED" },
333 { 0x8004CB0C, "CBA_E_QOSVALUEUNSUPPORTED" },
334 { 0x8004CB0F, "CBA_E_NOTAPPLICABLE" },
335 { 0x8004CB12, "CBA_E_LIMITVIOLATION" },
336 { 0x8004CB13, "CBA_E_QOSTYPENOTAPPLICABLE" },
337 { 0x8004CB18, "CBA_E_OUTOFPARTNERACCOS" },
338 { 0x8004CB1C, "CBA_E_FLAGUNSUPPORTED" },
339 { 0x8004CB23, "CBA_E_FRAMECOUNTUNSUPPORTED" },
340 { 0x8004CB25, "CBA_E_MODECHANGE" },
341 { 0x8007000E, "E_OUTOFMEMORY" },
342 { 0x80070057, "E_INVALIDARG" },
343 { 0x800706d1, "RPC_S_PROCNUM_OUT_OF_RANGE" },
344 { 0x80070776, "OR_INVALID_OXID" },
352 #define RTS_FLAG_NONE 0x0000
353 #define RTS_FLAG_PING 0x0001
354 #define RTS_FLAG_OTHER_CMD 0x0002
355 #define RTS_FLAG_RECYCLE_CHANNEL 0x0004
356 #define RTS_FLAG_IN_CHANNEL 0x0008
357 #define RTS_FLAG_OUT_CHANNEL 0x0010
358 #define RTS_FLAG_EOF 0x0020
359 #define RTS_FLAG_ECHO 0x0040
365 #define RTS_CMD_RECEIVEWINDOWSIZE 0x0
366 #define RTS_CMD_FLOWCONTROLACK 0x1
367 #define RTS_CMD_CONNECTIONTIMEOUT 0x2
368 #define RTS_CMD_COOKIE 0x3
369 #define RTS_CMD_CHANNELLIFETIME 0x4
370 #define RTS_CMD_CLIENTKEEPALIVE 0x5
371 #define RTS_CMD_VERSION 0x6
372 #define RTS_CMD_EMPTY 0x7
373 #define RTS_CMD_PADDING 0x8
374 #define RTS_CMD_NEGATIVEANCE 0x9
375 #define RTS_CMD_ANCE 0xA
376 #define RTS_CMD_CLIENTADDRESS 0xB
377 #define RTS_CMD_ASSOCIATIONGROUPID 0xC
378 #define RTS_CMD_DESTINATION 0xD
379 #define RTS_CMD_PINGTRAFFICSENTNOTIFY 0xE
381 static const value_string rts_command_vals[] = {
382 { RTS_CMD_RECEIVEWINDOWSIZE, "ReceiveWindowSize" },
383 { RTS_CMD_FLOWCONTROLACK, "FlowControlAck" },
384 { RTS_CMD_CONNECTIONTIMEOUT, "ConnectionTimeOut" },
385 { RTS_CMD_COOKIE, "Cookie" },
386 { RTS_CMD_CHANNELLIFETIME, "ChannelLifetime" },
387 { RTS_CMD_CLIENTKEEPALIVE, "ClientKeepalive" },
388 { RTS_CMD_VERSION, "Version" },
389 { RTS_CMD_EMPTY, "Empty" },
390 { RTS_CMD_PADDING, "Padding" },
391 { RTS_CMD_NEGATIVEANCE, "NegativeANCE" },
392 { RTS_CMD_ANCE, "ANCE" },
393 { RTS_CMD_CLIENTADDRESS, "ClientAddress" },
394 { RTS_CMD_ASSOCIATIONGROUPID, "AssociationGroupId" },
395 { RTS_CMD_DESTINATION, "Destination" },
396 { RTS_CMD_PINGTRAFFICSENTNOTIFY, "PingTrafficSentNotify" },
401 * RTS client address type
406 static const value_string rts_addresstype_vals[] = {
407 { RTS_IPV4, "IPV4" },
408 { RTS_IPV6, "IPV6" },
413 * RTS Forward destination
416 static const value_string rts_forward_destination_vals[] = {
418 { 0x1, "FDInProxy" },
420 { 0x3, "FDOutProxy" },
424 /* we need to keep track of what transport were used, ie what handle we came
425 * in through so we know what kind of pinfo->dce_smb_fid was passed to us.
427 /* Value of -1 is reserved for "not DCE packet" in packet_info.dcetransporttype. */
428 #define DCE_TRANSPORT_UNKNOWN 0
429 #define DCE_CN_TRANSPORT_SMBPIPE 1
432 static int proto_dcerpc = -1;
435 static int hf_dcerpc_request_in = -1;
436 static int hf_dcerpc_time = -1;
437 static int hf_dcerpc_response_in = -1;
438 static int hf_dcerpc_ver = -1;
439 static int hf_dcerpc_ver_minor = -1;
440 static int hf_dcerpc_packet_type = -1;
441 static int hf_dcerpc_cn_flags = -1;
442 static int hf_dcerpc_cn_flags_first_frag = -1;
443 static int hf_dcerpc_cn_flags_last_frag = -1;
444 static int hf_dcerpc_cn_flags_cancel_pending = -1;
445 static int hf_dcerpc_cn_flags_reserved = -1;
446 static int hf_dcerpc_cn_flags_mpx = -1;
447 static int hf_dcerpc_cn_flags_dne = -1;
448 static int hf_dcerpc_cn_flags_maybe = -1;
449 static int hf_dcerpc_cn_flags_object = -1;
450 static int hf_dcerpc_drep = -1;
451 int hf_dcerpc_drep_byteorder = -1;
452 static int hf_dcerpc_drep_character = -1;
453 static int hf_dcerpc_drep_fp = -1;
454 static int hf_dcerpc_cn_frag_len = -1;
455 static int hf_dcerpc_cn_auth_len = -1;
456 static int hf_dcerpc_cn_call_id = -1;
457 static int hf_dcerpc_cn_max_xmit = -1;
458 static int hf_dcerpc_cn_max_recv = -1;
459 static int hf_dcerpc_cn_assoc_group = -1;
460 static int hf_dcerpc_cn_num_ctx_items = -1;
461 static int hf_dcerpc_cn_ctx_item = -1;
462 static int hf_dcerpc_cn_ctx_id = -1;
463 static int hf_dcerpc_cn_num_trans_items = -1;
464 static int hf_dcerpc_cn_bind_abstract_syntax = -1;
465 static int hf_dcerpc_cn_bind_if_id = -1;
466 static int hf_dcerpc_cn_bind_if_ver = -1;
467 static int hf_dcerpc_cn_bind_if_ver_minor = -1;
468 static int hf_dcerpc_cn_bind_trans_syntax = -1;
469 static int hf_dcerpc_cn_bind_trans_id = -1;
470 static int hf_dcerpc_cn_bind_trans_ver = -1;
471 static int hf_dcerpc_cn_bind_trans_btfn_01 = -1;
472 static int hf_dcerpc_cn_bind_trans_btfn_02 = -1;
473 static int hf_dcerpc_cn_alloc_hint = -1;
474 static int hf_dcerpc_cn_sec_addr_len = -1;
475 static int hf_dcerpc_cn_sec_addr = -1;
476 static int hf_dcerpc_cn_num_results = -1;
477 static int hf_dcerpc_cn_ack_result = -1;
478 static int hf_dcerpc_cn_ack_reason = -1;
479 static int hf_dcerpc_cn_ack_trans_id = -1;
480 static int hf_dcerpc_cn_ack_trans_ver = -1;
481 static int hf_dcerpc_cn_ack_btfn = -1;
482 static int hf_dcerpc_cn_reject_reason = -1;
483 static int hf_dcerpc_cn_num_protocols = -1;
484 static int hf_dcerpc_cn_protocol_ver_major = -1;
485 static int hf_dcerpc_cn_protocol_ver_minor = -1;
486 static int hf_dcerpc_cn_cancel_count = -1;
487 static int hf_dcerpc_cn_status = -1;
488 static int hf_dcerpc_cn_deseg_req = -1;
489 static int hf_dcerpc_cn_rts_flags = -1;
490 static int hf_dcerpc_cn_rts_flags_none = -1;
491 static int hf_dcerpc_cn_rts_flags_ping = -1;
492 static int hf_dcerpc_cn_rts_flags_other_cmd = -1;
493 static int hf_dcerpc_cn_rts_flags_recycle_channel = -1;
494 static int hf_dcerpc_cn_rts_flags_in_channel = -1;
495 static int hf_dcerpc_cn_rts_flags_out_channel = -1;
496 static int hf_dcerpc_cn_rts_flags_eof = -1;
497 static int hf_dcerpc_cn_rts_commands_nb = -1;
498 static int hf_dcerpc_cn_rts_command = -1;
499 static int hf_dcerpc_cn_rts_command_receivewindowsize = -1;
500 static int hf_dcerpc_cn_rts_command_fack_bytesreceived = -1;
501 static int hf_dcerpc_cn_rts_command_fack_availablewindow = -1;
502 static int hf_dcerpc_cn_rts_command_fack_channelcookie = -1;
503 static int hf_dcerpc_cn_rts_command_connectiontimeout = -1;
504 static int hf_dcerpc_cn_rts_command_cookie = -1;
505 static int hf_dcerpc_cn_rts_command_channellifetime = -1;
506 static int hf_dcerpc_cn_rts_command_clientkeepalive = -1;
507 static int hf_dcerpc_cn_rts_command_version = -1;
508 static int hf_dcerpc_cn_rts_command_conformancecount = -1;
509 static int hf_dcerpc_cn_rts_command_padding = -1;
510 static int hf_dcerpc_cn_rts_command_addrtype = -1;
511 static int hf_dcerpc_cn_rts_command_associationgroupid = -1;
512 static int hf_dcerpc_cn_rts_command_forwarddestination = -1;
513 static int hf_dcerpc_cn_rts_command_pingtrafficsentnotify = -1;
514 static int hf_dcerpc_auth_type = -1;
515 static int hf_dcerpc_auth_level = -1;
516 static int hf_dcerpc_auth_pad_len = -1;
517 static int hf_dcerpc_auth_rsrvd = -1;
518 static int hf_dcerpc_auth_ctx_id = -1;
519 static int hf_dcerpc_dg_flags1 = -1;
520 static int hf_dcerpc_dg_flags1_rsrvd_01 = -1;
521 static int hf_dcerpc_dg_flags1_last_frag = -1;
522 static int hf_dcerpc_dg_flags1_frag = -1;
523 static int hf_dcerpc_dg_flags1_nofack = -1;
524 static int hf_dcerpc_dg_flags1_maybe = -1;
525 static int hf_dcerpc_dg_flags1_idempotent = -1;
526 static int hf_dcerpc_dg_flags1_broadcast = -1;
527 static int hf_dcerpc_dg_flags1_rsrvd_80 = -1;
528 static int hf_dcerpc_dg_flags2 = -1;
529 static int hf_dcerpc_dg_flags2_rsrvd_01 = -1;
530 static int hf_dcerpc_dg_flags2_cancel_pending = -1;
531 static int hf_dcerpc_dg_flags2_rsrvd_04 = -1;
532 static int hf_dcerpc_dg_flags2_rsrvd_08 = -1;
533 static int hf_dcerpc_dg_flags2_rsrvd_10 = -1;
534 static int hf_dcerpc_dg_flags2_rsrvd_20 = -1;
535 static int hf_dcerpc_dg_flags2_rsrvd_40 = -1;
536 static int hf_dcerpc_dg_flags2_rsrvd_80 = -1;
537 static int hf_dcerpc_dg_serial_hi = -1;
538 static int hf_dcerpc_obj_id = -1;
539 static int hf_dcerpc_dg_if_id = -1;
540 static int hf_dcerpc_dg_act_id = -1;
541 static int hf_dcerpc_dg_serial_lo = -1;
542 static int hf_dcerpc_dg_ahint = -1;
543 static int hf_dcerpc_dg_ihint = -1;
544 static int hf_dcerpc_dg_frag_len = -1;
545 static int hf_dcerpc_dg_frag_num = -1;
546 static int hf_dcerpc_dg_auth_proto = -1;
547 static int hf_dcerpc_opnum = -1;
548 static int hf_dcerpc_dg_seqnum = -1;
549 static int hf_dcerpc_dg_server_boot = -1;
550 static int hf_dcerpc_dg_if_ver = -1;
551 static int hf_dcerpc_krb5_av_prot_level = -1;
552 static int hf_dcerpc_krb5_av_key_vers_num = -1;
553 static int hf_dcerpc_krb5_av_key_auth_verifier = -1;
554 static int hf_dcerpc_dg_cancel_vers = -1;
555 static int hf_dcerpc_dg_cancel_id = -1;
556 static int hf_dcerpc_dg_server_accepting_cancels = -1;
557 static int hf_dcerpc_dg_fack_vers = -1;
558 static int hf_dcerpc_dg_fack_window_size = -1;
559 static int hf_dcerpc_dg_fack_max_tsdu = -1;
560 static int hf_dcerpc_dg_fack_max_frag_size = -1;
561 static int hf_dcerpc_dg_fack_serial_num = -1;
562 static int hf_dcerpc_dg_fack_selack_len = -1;
563 static int hf_dcerpc_dg_fack_selack = -1;
564 static int hf_dcerpc_dg_status = -1;
565 static int hf_dcerpc_array_max_count = -1;
566 static int hf_dcerpc_array_offset = -1;
567 static int hf_dcerpc_array_actual_count = -1;
568 static int hf_dcerpc_op = -1;
569 static int hf_dcerpc_referent_id32 = -1;
570 static int hf_dcerpc_referent_id64 = -1;
571 static int hf_dcerpc_fragments = -1;
572 static int hf_dcerpc_fragment = -1;
573 static int hf_dcerpc_fragment_overlap = -1;
574 static int hf_dcerpc_fragment_overlap_conflict = -1;
575 static int hf_dcerpc_fragment_multiple_tails = -1;
576 static int hf_dcerpc_fragment_too_long_fragment = -1;
577 static int hf_dcerpc_fragment_error = -1;
578 static int hf_dcerpc_fragment_count = -1;
579 static int hf_dcerpc_reassembled_in = -1;
580 static int hf_dcerpc_reassembled_length = -1;
581 static int hf_dcerpc_unknown_if_id = -1;
583 static gint ett_dcerpc = -1;
584 static gint ett_dcerpc_cn_flags = -1;
585 static gint ett_dcerpc_cn_ctx = -1;
586 static gint ett_dcerpc_cn_iface = -1;
587 static gint ett_dcerpc_cn_trans_syntax = -1;
588 static gint ett_dcerpc_cn_trans_btfn = -1;
589 static gint ett_dcerpc_cn_rts_flags = -1;
590 static gint ett_dcerpc_cn_rts_command = -1;
591 static gint ett_dcerpc_cn_rts_pdu = -1;
592 static gint ett_dcerpc_drep = -1;
593 static gint ett_dcerpc_dg_flags1 = -1;
594 static gint ett_dcerpc_dg_flags2 = -1;
595 static gint ett_dcerpc_pointer_data = -1;
596 static gint ett_dcerpc_string = -1;
597 static gint ett_dcerpc_fragments = -1;
598 static gint ett_dcerpc_fragment = -1;
599 static gint ett_dcerpc_krb5_auth_verf = -1;
601 static expert_field ei_dcerpc_fragment_multiple = EI_INIT;
602 static expert_field ei_dcerpc_cn_status = EI_INIT;
603 static expert_field ei_dcerpc_fragment_reassembled = EI_INIT;
604 static expert_field ei_dcerpc_fragment = EI_INIT;
605 static expert_field ei_dcerpc_no_request_found = EI_INIT;
606 static expert_field ei_dcerpc_context_change = EI_INIT;
607 static expert_field ei_dcerpc_cn_ctx_id_no_bind = EI_INIT;
608 static expert_field ei_dcerpc_bind_not_acknowledged = EI_INIT;
609 static expert_field ei_dcerpc_verifier_unavailable = EI_INIT;
610 static expert_field ei_dcerpc_invalid_pdu_authentication_attempt = EI_INIT;
612 static GSList *decode_dcerpc_bindings = NULL;
614 * To keep track of ctx_id mappings.
616 * Every time we see a bind call we update this table.
617 * Note that we always specify a SMB FID. For non-SMB transports this
620 static GHashTable *dcerpc_binds = NULL;
622 typedef struct _dcerpc_bind_key {
623 conversation_t *conv;
625 guint64 transport_salt;
628 typedef struct _dcerpc_bind_value {
634 /* Extra data for DCERPC handling and tracking of context ids */
635 typedef struct _dcerpc_decode_as_data {
636 guint16 dcectxid; /**< Context ID (DCERPC-specific) */
637 int dcetransporttype; /**< Transport type
638 * Value -1 means "not a DCERPC packet"
640 guint64 dcetransportsalt; /**< fid: if transporttype==DCE_CN_TRANSPORT_SMBPIPE */
641 } dcerpc_decode_as_data;
643 static dcerpc_decode_as_data*
644 dcerpc_get_decode_data(packet_info* pinfo)
646 dcerpc_decode_as_data* data = (dcerpc_decode_as_data*)p_get_proto_data(pinfo->pool, pinfo, proto_dcerpc, 0);
649 data = wmem_new0(pinfo->pool, dcerpc_decode_as_data);
650 data->dcetransporttype = -1;
651 p_add_proto_data(pinfo->pool, pinfo, proto_dcerpc, 0, data);
658 * Registers a conversation/UUID binding association, so that
659 * we can invoke the proper sub-dissector for a given DCERPC
662 * @param binding all values needed to create and bind a new conversation
664 * @return Pointer to newly-added UUID/conversation binding.
666 static struct _dcerpc_bind_value *
667 dcerpc_add_conv_to_bind_table(decode_dcerpc_bind_values_t *binding)
669 dcerpc_bind_value *bind_value;
670 dcerpc_bind_key *key;
671 conversation_t *conv;
673 conv = find_conversation(
683 conv = conversation_new(
693 bind_value = (dcerpc_bind_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_value));
694 bind_value->uuid = binding->uuid;
695 bind_value->ver = binding->ver;
696 /* For now, assume all DCE/RPC we pick from "decode as" is using
697 standard ndr and not ndr64.
698 We should make this selectable from the dialog in the future
700 bind_value->transport = uuid_data_repr_proto;
702 key = (dcerpc_bind_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_key));
704 key->ctx_id = binding->ctx_id;
705 key->transport_salt = binding->transport_salt;
707 /* add this entry to the bind table */
708 g_hash_table_insert(dcerpc_binds, key, bind_value);
714 /* inject one of our bindings into the dcerpc binding table */
716 decode_dcerpc_inject_binding(gpointer data, gpointer user_data _U_)
718 dcerpc_add_conv_to_bind_table((decode_dcerpc_bind_values_t *) data);
721 /* inject all of our bindings into the dcerpc binding table */
723 decode_dcerpc_inject_bindings(void) {
724 g_slist_foreach(decode_dcerpc_bindings, decode_dcerpc_inject_binding, NULL /* user_data */);
729 decode_dcerpc_binding_free(void *binding_in)
731 decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t *)binding_in;
733 g_free((void *) binding->addr_a.data);
734 g_free((void *) binding->addr_b.data);
736 g_string_free(binding->ifname, TRUE);
741 dcerpc_decode_as_free(gpointer value)
743 decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t *)value;
745 decode_dcerpc_binding_free(binding);
748 /* removes all bindings */
750 decode_dcerpc_reset_all(void)
752 decode_dcerpc_bind_values_t *binding;
754 while (decode_dcerpc_bindings) {
755 binding = (decode_dcerpc_bind_values_t *)decode_dcerpc_bindings->data;
757 decode_dcerpc_binding_free(binding);
758 decode_dcerpc_bindings = g_slist_remove(
759 decode_dcerpc_bindings,
760 decode_dcerpc_bindings->data);
766 decode_dcerpc_add_show_list(decode_add_show_list_func func, gpointer user_data)
768 g_slist_foreach(decode_dcerpc_bindings, func, user_data);
772 dcerpc_prompt(packet_info *pinfo, gchar* result)
774 GString *str = g_string_new("Replace binding between:\r\n"),
775 *address_str = g_string_new("");
776 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
778 switch (pinfo->ptype) {
780 g_string_append(address_str, "Address: ToBeDone TCP port");
783 g_string_append(address_str, "Address: ToBeDone UDP port");
786 g_string_append(address_str, "Address: ToBeDone Unknown port type");
789 g_string_append_printf(str, "%s: %u\r\n", address_str->str, pinfo->srcport);
790 g_string_append(str, "&\r\n");
791 g_string_append_printf(str, "%s: %u\r\n", address_str->str, pinfo->destport);
792 g_string_append_printf(str, "&\r\nContext ID: %u\r\n", decode_data->dcectxid);
793 g_string_append_printf(str, "&\r\nSMB FID: %"G_GINT64_MODIFIER"u\r\n",
794 dcerpc_get_transport_salt(pinfo));
795 g_string_append(str, "with:\r\n");
797 g_strlcpy(result, str->str, MAX_DECODE_AS_PROMPT_LEN);
798 g_string_free(str, TRUE);
799 g_string_free(address_str, TRUE);
803 dcerpc_value(packet_info *pinfo)
805 decode_dcerpc_bind_values_t *binding;
806 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
809 binding = g_new(decode_dcerpc_bind_values_t,1);
810 COPY_ADDRESS(&binding->addr_a, &pinfo->src);
811 COPY_ADDRESS(&binding->addr_b, &pinfo->dst);
812 binding->ptype = pinfo->ptype;
813 binding->port_a = pinfo->srcport;
814 binding->port_b = pinfo->destport;
815 binding->ctx_id = decode_data->dcectxid;
816 binding->transport_salt = dcerpc_get_transport_salt(pinfo);
817 binding->ifname = NULL;
818 /*binding->uuid = NULL;*/
824 struct dcerpc_decode_as_populate
826 decode_as_add_to_list_func add_to_list;
831 decode_dcerpc_add_to_list(gpointer key, gpointer value, gpointer user_data)
833 struct dcerpc_decode_as_populate* populate = (struct dcerpc_decode_as_populate*)user_data;
835 /*dcerpc_uuid_key *k = key;*/
836 dcerpc_uuid_value *v = (dcerpc_uuid_value *)value;
838 if (strcmp(v->name, "(none)"))
839 populate->add_to_list("DCE-RPC", v->name, key, populate->ui_element);
843 dcerpc_populate_list(const gchar *table_name _U_, decode_as_add_to_list_func add_to_list, gpointer ui_element)
845 struct dcerpc_decode_as_populate populate;
847 populate.add_to_list = add_to_list;
848 populate.ui_element = ui_element;
850 g_hash_table_foreach(dcerpc_uuids, decode_dcerpc_add_to_list, &populate);
853 /* compare two bindings (except the interface related things, e.g. uuid) */
855 decode_dcerpc_binding_cmp(gconstpointer a, gconstpointer b)
857 const decode_dcerpc_bind_values_t *binding_a = (const decode_dcerpc_bind_values_t *)a;
858 const decode_dcerpc_bind_values_t *binding_b = (const decode_dcerpc_bind_values_t *)b;
861 /* don't compare uuid and ver! */
863 ADDRESSES_EQUAL(&binding_a->addr_a, &binding_b->addr_a) &&
864 ADDRESSES_EQUAL(&binding_a->addr_b, &binding_b->addr_b) &&
865 binding_a->ptype == binding_b->ptype &&
866 binding_a->port_a == binding_b->port_a &&
867 binding_a->port_b == binding_b->port_b &&
868 binding_a->ctx_id == binding_b->ctx_id &&
869 binding_a->transport_salt == binding_b->transport_salt)
879 /* remove a binding (looking the same way as the given one) */
881 decode_dcerpc_binding_reset(const char *name _U_, const gpointer pattern)
883 decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t*)pattern;
885 decode_dcerpc_bind_values_t *old_binding;
887 /* find the old binding (if it exists) */
888 le = g_slist_find_custom(decode_dcerpc_bindings,
890 decode_dcerpc_binding_cmp);
894 old_binding = (decode_dcerpc_bind_values_t *)le->data;
896 decode_dcerpc_bindings = g_slist_remove(decode_dcerpc_bindings, le->data);
898 g_free((void *) old_binding->addr_a.data);
899 g_free((void *) old_binding->addr_b.data);
900 g_string_free(old_binding->ifname, TRUE);
906 dcerpc_decode_as_change(const char *name, const gpointer pattern, gpointer handle, gchar* list_name)
908 decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t*)pattern;
909 decode_dcerpc_bind_values_t *stored_binding;
910 dcerpc_uuid_key *key = *((dcerpc_uuid_key**)handle);
913 binding->ifname = g_string_new(list_name);
914 binding->uuid = key->uuid;
915 binding->ver = key->ver;
917 /* remove a probably existing old binding */
918 decode_dcerpc_binding_reset(name, binding);
920 /* clone the new binding and append it to the list */
921 stored_binding = g_new(decode_dcerpc_bind_values_t,1);
922 *stored_binding = *binding;
923 COPY_ADDRESS(&stored_binding->addr_a, &binding->addr_a);
924 COPY_ADDRESS(&stored_binding->addr_b, &binding->addr_b);
925 stored_binding->ifname = g_string_new(binding->ifname->str);
927 decode_dcerpc_bindings = g_slist_append (decode_dcerpc_bindings, stored_binding);
932 static const fragment_items dcerpc_frag_items = {
933 &ett_dcerpc_fragments,
934 &ett_dcerpc_fragment,
936 &hf_dcerpc_fragments,
938 &hf_dcerpc_fragment_overlap,
939 &hf_dcerpc_fragment_overlap_conflict,
940 &hf_dcerpc_fragment_multiple_tails,
941 &hf_dcerpc_fragment_too_long_fragment,
942 &hf_dcerpc_fragment_error,
943 &hf_dcerpc_fragment_count,
945 &hf_dcerpc_reassembled_length,
946 /* Reassembled data field */
951 /* list of hooks to be called when init_protocols is done */
952 GHookList dcerpc_hooks_init_protos;
954 /* try to desegment big DCE/RPC packets over TCP? */
955 static gboolean dcerpc_cn_desegment = TRUE;
957 /* reassemble DCE/RPC fragments */
958 /* reassembly of cl dcerpc fragments will not work for the case where ONE frame
959 might contain multiple dcerpc fragments for different PDUs.
960 this case would be so unusual/weird so if you got captures like that:
963 reassembly of co dcerpc fragments will not work for the case where TCP/SMB frames
964 are coming in out of sequence, but that will hurt in a lot of other places as well.
966 static gboolean dcerpc_reassemble = TRUE;
967 static reassembly_table dcerpc_co_reassembly_table;
968 static reassembly_table dcerpc_cl_reassembly_table;
970 typedef struct _dcerpc_fragment_key {
975 } dcerpc_fragment_key;
978 dcerpc_fragment_hash(gconstpointer k)
980 const dcerpc_fragment_key* key = (const dcerpc_fragment_key*) k;
986 hash_val += key->act_id.Data1;
987 hash_val += key->act_id.Data2 << 16;
988 hash_val += key->act_id.Data3;
994 dcerpc_fragment_equal(gconstpointer k1, gconstpointer k2)
996 const dcerpc_fragment_key* key1 = (const dcerpc_fragment_key*) k1;
997 const dcerpc_fragment_key* key2 = (const dcerpc_fragment_key*) k2;
999 /*key.id is the first item to compare since item is most
1000 likely to differ between sessions, thus shortcircuiting
1001 the comparison of addresses.
1003 return (((key1->id == key2->id)
1004 && (ADDRESSES_EQUAL(&key1->src, &key2->src))
1005 && (ADDRESSES_EQUAL(&key1->dst, &key2->dst))
1006 && (memcmp (&key1->act_id, &key2->act_id, sizeof (e_uuid_t)) == 0))
1010 /* allocate a persistent dcerpc fragment key to insert in the hash */
1012 dcerpc_fragment_temporary_key(const packet_info *pinfo, const guint32 id,
1015 dcerpc_fragment_key *key = g_slice_new(dcerpc_fragment_key);
1016 e_dce_dg_common_hdr_t *hdr = (e_dce_dg_common_hdr_t *)data;
1018 key->src = pinfo->src;
1019 key->dst = pinfo->dst;
1021 key->act_id = hdr->act_id;
1026 /* allocate a persistent dcerpc fragment key to insert in the hash */
1028 dcerpc_fragment_persistent_key(const packet_info *pinfo, const guint32 id,
1031 dcerpc_fragment_key *key = g_slice_new(dcerpc_fragment_key);
1032 e_dce_dg_common_hdr_t *hdr = (e_dce_dg_common_hdr_t *)data;
1034 COPY_ADDRESS(&key->src, &pinfo->src);
1035 COPY_ADDRESS(&key->dst, &pinfo->dst);
1037 key->act_id = hdr->act_id;
1043 dcerpc_fragment_free_temporary_key(gpointer ptr)
1045 dcerpc_fragment_key *key = (dcerpc_fragment_key *)ptr;
1048 g_slice_free(dcerpc_fragment_key, key);
1052 dcerpc_fragment_free_persistent_key(gpointer ptr)
1054 dcerpc_fragment_key *key = (dcerpc_fragment_key *)ptr;
1058 * Free up the copies of the addresses from the old key.
1060 g_free((gpointer)key->src.data);
1061 g_free((gpointer)key->dst.data);
1063 g_slice_free(dcerpc_fragment_key, key);
1067 static const reassembly_table_functions dcerpc_cl_reassembly_table_functions = {
1068 dcerpc_fragment_hash,
1069 dcerpc_fragment_equal,
1070 dcerpc_fragment_temporary_key,
1071 dcerpc_fragment_persistent_key,
1072 dcerpc_fragment_free_temporary_key,
1073 dcerpc_fragment_free_persistent_key
1077 dcerpc_reassemble_init(void)
1080 * XXX - addresses_ports_reassembly_table_functions?
1081 * Or can a single connection-oriented DCE RPC session persist
1082 * over multiple transport layer connections?
1084 reassembly_table_init(&dcerpc_co_reassembly_table,
1085 &addresses_reassembly_table_functions);
1086 reassembly_table_init(&dcerpc_cl_reassembly_table,
1087 &dcerpc_cl_reassembly_table_functions);
1091 * Authentication subdissectors. Used to dissect authentication blobs in
1092 * DCERPC binds, requests and responses.
1095 typedef struct _dcerpc_auth_subdissector {
1098 dcerpc_auth_subdissector_fns auth_fns;
1099 } dcerpc_auth_subdissector;
1101 static GSList *dcerpc_auth_subdissector_list;
1103 static dcerpc_auth_subdissector_fns *get_auth_subdissector_fns(
1104 guint8 auth_level, guint8 auth_type)
1109 for (i = 0; (data = g_slist_nth_data(dcerpc_auth_subdissector_list, i)); i++) {
1110 dcerpc_auth_subdissector *asd = (dcerpc_auth_subdissector *)data;
1112 if ((asd->auth_level == auth_level) &&
1113 (asd->auth_type == auth_type))
1114 return &asd->auth_fns;
1120 void register_dcerpc_auth_subdissector(guint8 auth_level, guint8 auth_type,
1121 dcerpc_auth_subdissector_fns *fns)
1123 dcerpc_auth_subdissector *d;
1125 if (get_auth_subdissector_fns(auth_level, auth_type))
1128 d = (dcerpc_auth_subdissector *)g_malloc(sizeof(dcerpc_auth_subdissector));
1130 d->auth_level = auth_level;
1131 d->auth_type = auth_type;
1132 memcpy(&d->auth_fns, fns, sizeof(dcerpc_auth_subdissector_fns));
1134 dcerpc_auth_subdissector_list = g_slist_append(dcerpc_auth_subdissector_list, d);
1137 /* Hand off verifier data to a registered dissector */
1139 static void dissect_auth_verf(tvbuff_t *auth_tvb, packet_info *pinfo,
1141 dcerpc_auth_subdissector_fns *auth_fns,
1142 e_dce_cn_common_hdr_t *hdr,
1143 dcerpc_auth_info *auth_info)
1145 dcerpc_dissect_fnct_t *volatile fn = NULL;
1146 /* XXX - "stub" a fake DCERPC INFO STRUCTURE
1147 If a dcerpc_info is really needed, update
1148 the call stacks to include it
1150 FAKE_DCERPC_INFO_STRUCTURE
1152 switch (hdr->ptype) {
1155 fn = auth_fns->bind_fn;
1159 fn = auth_fns->bind_ack_fn;
1162 fn = auth_fns->auth3_fn;
1165 fn = auth_fns->req_verf_fn;
1168 fn = auth_fns->resp_verf_fn;
1172 /* Don't know how to handle authentication data in this
1174 proto_tree_add_expert_format(tree, pinfo, &ei_dcerpc_invalid_pdu_authentication_attempt,
1176 "Don't know how to dissect authentication data for %s pdu type",
1177 val_to_str(hdr->ptype, pckt_vals, "Unknown (%u)"));
1183 fn(auth_tvb, 0, pinfo, tree, &di, hdr->drep);
1185 proto_tree_add_expert_format(tree, pinfo, &ei_dcerpc_verifier_unavailable,
1186 auth_tvb, 0, hdr->auth_len,
1187 "%s Verifier unavailable",
1188 val_to_str(auth_info->auth_type,
1189 authn_protocol_vals,
1194 /* Hand off payload data to a registered dissector */
1196 static tvbuff_t *decode_encrypted_data(tvbuff_t *data_tvb,
1199 dcerpc_auth_subdissector_fns *auth_fns,
1200 gboolean is_request,
1201 dcerpc_auth_info *auth_info)
1203 dcerpc_decode_data_fnct_t *fn;
1206 fn = auth_fns->req_data_fn;
1208 fn = auth_fns->resp_data_fn;
1211 return fn(data_tvb, auth_tvb, 0, pinfo, auth_info);
1220 /* the registered subdissectors */
1221 GHashTable *dcerpc_uuids = NULL;
1224 dcerpc_uuid_equal(gconstpointer k1, gconstpointer k2)
1226 const dcerpc_uuid_key *key1 = (const dcerpc_uuid_key *)k1;
1227 const dcerpc_uuid_key *key2 = (const dcerpc_uuid_key *)k2;
1228 return ((memcmp(&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
1229 && (key1->ver == key2->ver));
1233 dcerpc_uuid_hash(gconstpointer k)
1235 const dcerpc_uuid_key *key = (const dcerpc_uuid_key *)k;
1236 /* This isn't perfect, but the Data1 part of these is almost always
1238 return key->uuid.Data1;
1242 dcerpc_init_uuid(int proto, int ett, e_uuid_t *uuid, guint16 ver,
1243 dcerpc_sub_dissector *procs, int opnum_hf)
1245 dcerpc_uuid_key *key = (dcerpc_uuid_key *)g_malloc(sizeof (*key));
1246 dcerpc_uuid_value *value = (dcerpc_uuid_value *)g_malloc(sizeof (*value));
1247 header_field_info *hf_info;
1248 module_t *samr_module;
1249 const char *filter_name = proto_get_protocol_filter_name(proto);
1254 value->proto = find_protocol_by_id(proto);
1255 value->proto_id = proto;
1257 value->name = proto_get_protocol_short_name(value->proto);
1258 value->procs = procs;
1259 value->opnum_hf = opnum_hf;
1261 g_hash_table_insert(dcerpc_uuids, key, value);
1263 hf_info = proto_registrar_get_nth(opnum_hf);
1264 hf_info->strings = value_string_from_subdissectors(procs);
1266 /* add this GUID to the global name resolving */
1267 guids_add_uuid(uuid, proto_get_protocol_short_name(value->proto));
1269 /* Register the samr.nt_password preference as obsolete */
1270 /* This should be in packet-dcerpc-samr.c */
1271 if (strcmp(filter_name, "samr") == 0) {
1272 samr_module = prefs_register_protocol(proto, NULL);
1273 prefs_register_obsolete_preference(samr_module, "nt_password");
1277 /* Function to find the name of a registered protocol
1278 * or NULL if the protocol/version is not known to wireshark.
1281 dcerpc_get_proto_name(e_uuid_t *uuid, guint16 ver)
1283 dcerpc_uuid_key key;
1284 dcerpc_uuid_value *sub_proto;
1288 if (!(sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key))) {
1291 return sub_proto->name;
1294 /* Function to find the opnum hf-field of a registered protocol
1295 * or -1 if the protocol/version is not known to wireshark.
1298 dcerpc_get_proto_hf_opnum(e_uuid_t *uuid, guint16 ver)
1300 dcerpc_uuid_key key;
1301 dcerpc_uuid_value *sub_proto;
1305 if (!(sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key))) {
1308 return sub_proto->opnum_hf;
1311 /* Create a value_string consisting of DCERPC opnum and name from a
1312 subdissector array. */
1314 value_string *value_string_from_subdissectors(dcerpc_sub_dissector *sd)
1316 value_string *vs = NULL;
1321 for (i = 0; sd[i].name; i++) {
1323 vs[i].value = sd[i].num;
1324 vs[i].strptr = sd[i].name;
1330 vs = (value_string *)wmem_alloc(wmem_epan_scope(), (num_sd + 1) * sizeof(value_string));
1334 vs[num_sd].value = 0;
1335 vs[num_sd].strptr = NULL;
1340 /* Function to find the subdissector table of a registered protocol
1341 * or NULL if the protocol/version is not known to wireshark.
1343 dcerpc_sub_dissector *
1344 dcerpc_get_proto_sub_dissector(e_uuid_t *uuid, guint16 ver)
1346 dcerpc_uuid_key key;
1347 dcerpc_uuid_value *sub_proto;
1351 if (!(sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key))) {
1354 return sub_proto->procs;
1360 dcerpc_bind_equal(gconstpointer k1, gconstpointer k2)
1362 const dcerpc_bind_key *key1 = (const dcerpc_bind_key *)k1;
1363 const dcerpc_bind_key *key2 = (const dcerpc_bind_key *)k2;
1364 return ((key1->conv == key2->conv)
1365 && (key1->ctx_id == key2->ctx_id)
1366 && (key1->transport_salt == key2->transport_salt));
1370 dcerpc_bind_hash(gconstpointer k)
1372 const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
1375 hash = GPOINTER_TO_UINT(key->conv);
1376 hash += key->ctx_id;
1377 /* sizeof(guint) might be smaller than sizeof(guint64) */
1378 hash += (guint)key->transport_salt;
1379 hash += (guint)(key->transport_salt << sizeof(guint));
1385 * To keep track of callid mappings. Should really use some generic
1386 * conversation support instead.
1388 static GHashTable *dcerpc_cn_calls = NULL;
1389 static GHashTable *dcerpc_dg_calls = NULL;
1391 typedef struct _dcerpc_cn_call_key {
1392 conversation_t *conv;
1394 guint64 transport_salt;
1395 } dcerpc_cn_call_key;
1397 typedef struct _dcerpc_dg_call_key {
1398 conversation_t *conv;
1401 } dcerpc_dg_call_key;
1405 dcerpc_cn_call_equal(gconstpointer k1, gconstpointer k2)
1407 const dcerpc_cn_call_key *key1 = (const dcerpc_cn_call_key *)k1;
1408 const dcerpc_cn_call_key *key2 = (const dcerpc_cn_call_key *)k2;
1409 return ((key1->conv == key2->conv)
1410 && (key1->call_id == key2->call_id)
1411 && (key1->transport_salt == key2->transport_salt));
1415 dcerpc_dg_call_equal(gconstpointer k1, gconstpointer k2)
1417 const dcerpc_dg_call_key *key1 = (const dcerpc_dg_call_key *)k1;
1418 const dcerpc_dg_call_key *key2 = (const dcerpc_dg_call_key *)k2;
1419 return ((key1->conv == key2->conv)
1420 && (key1->seqnum == key2->seqnum)
1421 && ((memcmp(&key1->act_id, &key2->act_id, sizeof (e_uuid_t)) == 0)));
1425 dcerpc_cn_call_hash(gconstpointer k)
1427 const dcerpc_cn_call_key *key = (const dcerpc_cn_call_key *)k;
1430 hash = GPOINTER_TO_UINT(key->conv);
1431 hash += key->call_id;
1432 /* sizeof(guint) might be smaller than sizeof(guint64) */
1433 hash += (guint)key->transport_salt;
1434 hash += (guint)(key->transport_salt << sizeof(guint));
1440 dcerpc_dg_call_hash(gconstpointer k)
1442 const dcerpc_dg_call_key *key = (const dcerpc_dg_call_key *)k;
1443 return (GPOINTER_TO_UINT(key->conv) + key->seqnum + key->act_id.Data1
1444 + (key->act_id.Data2 << 16) + key->act_id.Data3
1445 + (key->act_id.Data4[0] << 24) + (key->act_id.Data4[1] << 16)
1446 + (key->act_id.Data4[2] << 8) + (key->act_id.Data4[3] << 0)
1447 + (key->act_id.Data4[4] << 24) + (key->act_id.Data4[5] << 16)
1448 + (key->act_id.Data4[6] << 8) + (key->act_id.Data4[7] << 0));
1451 /* to keep track of matched calls/responses
1452 this one uses the same value struct as calls, but the key is the frame id
1453 and call id; there can be more than one call in a frame.
1455 XXX - why not just use the same keys as are used for calls?
1458 static GHashTable *dcerpc_matched = NULL;
1460 typedef struct _dcerpc_matched_key {
1463 } dcerpc_matched_key;
1466 dcerpc_matched_equal(gconstpointer k1, gconstpointer k2)
1468 const dcerpc_matched_key *key1 = (const dcerpc_matched_key *)k1;
1469 const dcerpc_matched_key *key2 = (const dcerpc_matched_key *)k2;
1470 return ((key1->frame == key2->frame)
1471 && (key1->call_id == key2->call_id));
1475 dcerpc_matched_hash(gconstpointer k)
1477 const dcerpc_matched_key *key = (const dcerpc_matched_key *)k;
1484 * Utility functions. Modeled after packet-rpc.c
1488 dissect_dcerpc_uint8(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1489 proto_tree *tree, guint8 *drep,
1490 int hfindex, guint8 *pdata)
1494 data = tvb_get_guint8(tvb, offset);
1495 if (tree && hfindex != -1) {
1496 proto_tree_add_item(tree, hfindex, tvb, offset, 1, DREP_ENC_INTEGER(drep));
1504 dissect_dcerpc_uint16(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1505 proto_tree *tree, guint8 *drep,
1506 int hfindex, guint16 *pdata)
1510 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1511 ? tvb_get_letohs(tvb, offset)
1512 : tvb_get_ntohs(tvb, offset));
1514 if (tree && hfindex != -1) {
1515 proto_tree_add_item(tree, hfindex, tvb, offset, 2, DREP_ENC_INTEGER(drep));
1523 dissect_dcerpc_uint32(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1524 proto_tree *tree, guint8 *drep,
1525 int hfindex, guint32 *pdata)
1529 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1530 ? tvb_get_letohl(tvb, offset)
1531 : tvb_get_ntohl(tvb, offset));
1533 if (tree && hfindex != -1) {
1534 proto_tree_add_item(tree, hfindex, tvb, offset, 4, DREP_ENC_INTEGER(drep));
1541 /* handles 32 bit unix time_t */
1543 dissect_dcerpc_time_t(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1544 proto_tree *tree, guint8 *drep,
1545 int hfindex, guint32 *pdata)
1550 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1551 ? tvb_get_letohl(tvb, offset)
1552 : tvb_get_ntohl(tvb, offset));
1556 if (tree && hfindex != -1) {
1557 if (data == 0xffffffff) {
1558 /* special case, no time specified */
1559 proto_tree_add_time_format_value(tree, hfindex, tvb, offset, 4, &tv, "No time specified");
1561 proto_tree_add_time(tree, hfindex, tvb, offset, 4, &tv);
1571 dissect_dcerpc_uint64(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1572 proto_tree *tree, dcerpc_info *di, guint8 *drep,
1573 int hfindex, guint64 *pdata)
1577 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1578 ? tvb_get_letoh64(tvb, offset)
1579 : tvb_get_ntoh64(tvb, offset));
1581 if (tree && hfindex != -1) {
1582 header_field_info *hfinfo;
1584 /* This might be a field that is either 32bit, in NDR or
1585 64 bits in NDR64. So we must be careful and call the right
1588 hfinfo = proto_registrar_get_nth(hfindex);
1590 switch (hfinfo->type) {
1592 proto_tree_add_uint64(tree, hfindex, tvb, offset, 8, data);
1595 proto_tree_add_int64(tree, hfindex, tvb, offset, 8, data);
1598 /* The value is truncated to 32bits. 64bit values have only been
1599 seen on fuzz-tested files */
1600 DISSECTOR_ASSERT((di->call_data->flags & DCERPC_IS_NDR64) || (data <= G_MAXUINT32));
1601 proto_tree_add_uint(tree, hfindex, tvb, offset, 8, (guint32)data);
1611 dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1612 proto_tree *tree, guint8 *drep,
1613 int hfindex, gfloat *pdata)
1619 case(DCE_RPC_DREP_FP_IEEE):
1620 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1621 ? tvb_get_letohieee_float(tvb, offset)
1622 : tvb_get_ntohieee_float(tvb, offset));
1623 if (tree && hfindex != -1) {
1624 proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
1627 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
1628 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1629 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
1631 /* ToBeDone: non IEEE floating formats */
1632 /* Set data to a negative infinity value */
1634 if (tree && hfindex != -1) {
1635 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep[1]);
1645 dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1646 proto_tree *tree, guint8 *drep,
1647 int hfindex, gdouble *pdata)
1653 case(DCE_RPC_DREP_FP_IEEE):
1654 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1655 ? tvb_get_letohieee_double(tvb, offset)
1656 : tvb_get_ntohieee_double(tvb, offset));
1657 if (tree && hfindex != -1) {
1658 proto_tree_add_double(tree, hfindex, tvb, offset, 8, data);
1661 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
1662 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1663 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
1665 /* ToBeDone: non IEEE double formats */
1666 /* Set data to a negative infinity value */
1667 data = -G_MAXDOUBLE;
1668 if (tree && hfindex != -1) {
1669 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep[1]);
1679 dissect_dcerpc_uuid_t(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1680 proto_tree *tree, guint8 *drep,
1681 int hfindex, e_uuid_t *pdata)
1686 if (drep[0] & DREP_LITTLE_ENDIAN) {
1687 tvb_get_letohguid(tvb, offset, (e_guid_t *) &uuid);
1689 tvb_get_ntohguid(tvb, offset, (e_guid_t *) &uuid);
1691 if (tree && hfindex != -1) {
1692 proto_tree_add_guid(tree, hfindex, tvb, offset, 16, (e_guid_t *) &uuid);
1702 * a couple simpler things
1705 dcerpc_tvb_get_ntohs(tvbuff_t *tvb, gint offset, guint8 *drep)
1707 if (drep[0] & DREP_LITTLE_ENDIAN) {
1708 return tvb_get_letohs(tvb, offset);
1710 return tvb_get_ntohs(tvb, offset);
1715 dcerpc_tvb_get_ntohl(tvbuff_t *tvb, gint offset, guint8 *drep)
1717 if (drep[0] & DREP_LITTLE_ENDIAN) {
1718 return tvb_get_letohl(tvb, offset);
1720 return tvb_get_ntohl(tvb, offset);
1725 dcerpc_tvb_get_uuid(tvbuff_t *tvb, gint offset, guint8 *drep, e_uuid_t *uuid)
1727 if (drep[0] & DREP_LITTLE_ENDIAN) {
1728 tvb_get_letohguid(tvb, offset, (e_guid_t *) uuid);
1730 tvb_get_ntohguid(tvb, offset, (e_guid_t *) uuid);
1736 /* function to dissect a unidimensional conformant array */
1738 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1739 proto_tree *tree, dcerpc_info *di, guint8 *drep,
1740 dcerpc_dissect_fnct_t *fnct)
1744 int conformance_size = 4;
1746 if (di->call_data->flags & DCERPC_IS_NDR64) {
1747 conformance_size = 8;
1750 if (di->conformant_run) {
1753 /* conformant run, just dissect the max_count header */
1754 old_offset = offset;
1755 di->conformant_run = 0;
1756 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1757 hf_dcerpc_array_max_count, &val);
1758 di->array_max_count = (gint32)val;
1759 di->array_max_count_offset = offset-conformance_size;
1760 di->conformant_run = 1;
1761 di->conformant_eaten = offset-old_offset;
1763 /* we don't remember where in the bytestream this field was */
1764 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, conformance_size, di->array_max_count);
1766 /* real run, dissect the elements */
1767 for (i=0; i<di->array_max_count; i++) {
1768 offset = (*fnct)(tvb, offset, pinfo, tree, di, drep);
1775 /* function to dissect a unidimensional conformant and varying array
1776 * depending on the dissection function passed as a parameter,
1777 * content of the array will be dissected as a block or byte by byte
1780 dissect_ndr_ucvarray_core(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1781 proto_tree *tree, dcerpc_info *di, guint8 *drep,
1782 dcerpc_dissect_fnct_t *fnct_bytes,
1783 dcerpc_dissect_fnct_blk_t *fnct_block)
1787 int conformance_size = 4;
1789 if (di->call_data->flags & DCERPC_IS_NDR64) {
1790 conformance_size = 8;
1793 if (di->conformant_run) {
1796 /* conformant run, just dissect the max_count header */
1797 old_offset = offset;
1798 di->conformant_run = 0;
1799 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1800 hf_dcerpc_array_max_count, &val);
1801 DISSECTOR_ASSERT(val <= G_MAXUINT32);
1802 di->array_max_count = (guint32)val;
1803 di->array_max_count_offset = offset-conformance_size;
1804 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1805 hf_dcerpc_array_offset, &val);
1806 DISSECTOR_ASSERT(val <= G_MAXUINT32);
1807 di->array_offset = (guint32)val;
1808 di->array_offset_offset = offset-conformance_size;
1809 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1810 hf_dcerpc_array_actual_count, &val);
1811 DISSECTOR_ASSERT(val <= G_MAXUINT32);
1812 di->array_actual_count = (guint32)val;
1813 di->array_actual_count_offset = offset-conformance_size;
1814 di->conformant_run = 1;
1815 di->conformant_eaten = offset-old_offset;
1817 /* we don't remember where in the bytestream these fields were */
1818 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, conformance_size, di->array_max_count);
1819 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, conformance_size, di->array_offset);
1820 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, conformance_size, di->array_actual_count);
1822 /* real run, dissect the elements */
1824 offset = (*fnct_block)(tvb, offset, di->array_actual_count, pinfo, tree, drep);
1826 for (i=0 ;i<di->array_actual_count; i++) {
1827 old_offset = offset;
1828 offset = (*fnct_bytes)(tvb, offset, pinfo, tree, di, drep);
1829 if (offset <= old_offset)
1830 THROW(ReportedBoundsError);
1839 dissect_ndr_ucvarray_block(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1840 proto_tree *tree, dcerpc_info *di, guint8 *drep,
1841 dcerpc_dissect_fnct_blk_t *fnct)
1843 return dissect_ndr_ucvarray_core(tvb, offset, pinfo, tree, di, drep, NULL, fnct);
1847 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1848 proto_tree *tree, dcerpc_info *di, guint8 *drep,
1849 dcerpc_dissect_fnct_t *fnct)
1851 return dissect_ndr_ucvarray_core(tvb, offset, pinfo, tree, di, drep, fnct, NULL);
1853 /* function to dissect a unidimensional varying array */
1855 dissect_ndr_uvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1856 proto_tree *tree, dcerpc_info *di, guint8 *drep,
1857 dcerpc_dissect_fnct_t *fnct)
1861 int conformance_size = 4;
1863 if (di->call_data->flags & DCERPC_IS_NDR64) {
1864 conformance_size = 8;
1867 if (di->conformant_run) {
1870 /* conformant run, just dissect the max_count header */
1871 old_offset = offset;
1872 di->conformant_run = 0;
1873 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1874 hf_dcerpc_array_offset, &val);
1875 DISSECTOR_ASSERT(val <= G_MAXUINT32);
1876 di->array_offset = (guint32)val;
1877 di->array_offset_offset = offset-conformance_size;
1878 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1879 hf_dcerpc_array_actual_count, &val);
1880 DISSECTOR_ASSERT(val <= G_MAXUINT32);
1881 di->array_actual_count = (guint32)val;
1882 di->array_actual_count_offset = offset-conformance_size;
1883 di->conformant_run = 1;
1884 di->conformant_eaten = offset-old_offset;
1886 /* we don't remember where in the bytestream these fields were */
1887 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, conformance_size, di->array_offset);
1888 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, conformance_size, di->array_actual_count);
1890 /* real run, dissect the elements */
1891 for (i=0; i<di->array_actual_count; i++) {
1892 offset = (*fnct)(tvb, offset, pinfo, tree, di, drep);
1899 /* Dissect an string of bytes. This corresponds to
1900 IDL of the form '[string] byte *foo'.
1902 It can also be used for a conformant varying array of bytes if
1903 the contents of the array should be shown as a big blob, rather
1904 than showing each byte as an individual element.
1906 XXX - which of those is really the IDL type for, for example,
1907 the encrypted data in some MAPI packets? (Microsoft hasn't
1910 XXX - does this need to do all the conformant array stuff that
1911 "dissect_ndr_ucvarray()" does? These are presumably for strings
1912 that are conformant and varying - they're stored like conformant
1913 varying arrays of bytes. */
1915 dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo,
1916 proto_tree *tree, dcerpc_info *di, guint8 *drep)
1920 if (di->conformant_run) {
1921 /* just a run to handle conformant arrays, no scalars to dissect */
1925 /* NDR array header */
1927 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1928 hf_dcerpc_array_max_count, NULL);
1930 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1931 hf_dcerpc_array_offset, NULL);
1933 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1934 hf_dcerpc_array_actual_count, &len);
1936 DISSECTOR_ASSERT(len <= G_MAXUINT32);
1938 proto_tree_add_item(tree, di->hf_index, tvb, offset, (guint32)len,
1942 offset += (guint32)len;
1947 /* For dissecting arrays that are to be interpreted as strings. */
1949 /* Dissect an NDR conformant varying string of elements.
1950 The length of each element is given by the 'size_is' parameter;
1951 the elements are assumed to be characters or wide characters.
1953 XXX - does this need to do all the conformant array stuff that
1954 "dissect_ndr_ucvarray()" does? */
1956 dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1957 proto_tree *tree, dcerpc_info *di, guint8 *drep, int size_is,
1958 int hfindex, gboolean add_subtree, char **data)
1960 header_field_info *hfinfo;
1961 proto_item *string_item;
1962 proto_tree *string_tree;
1967 /* Make sure this really is a string field. */
1968 hfinfo = proto_registrar_get_nth(hfindex);
1969 DISSECTOR_ASSERT(hfinfo->type == FT_STRING);
1971 if (di->conformant_run) {
1972 /* just a run to handle conformant arrays, no scalars to dissect */
1977 string_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_dcerpc_string, &string_item,
1978 proto_registrar_get_name(hfindex));
1984 /* NDR array header */
1986 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
1987 hf_dcerpc_array_max_count, NULL);
1989 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
1990 hf_dcerpc_array_offset, NULL);
1992 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
1993 hf_dcerpc_array_actual_count, &len);
1995 /* The value is truncated to 32bits. 64bit values have only been
1996 seen on fuzztested files */
1997 buffer_len = size_is * (guint32)len;
2000 if (!di->no_align && (offset % size_is))
2001 offset += size_is - (offset % size_is);
2004 * "tvb_get_string_enc()" throws an exception if the entire string
2005 * isn't in the tvbuff. If the length is bogus, this should
2006 * keep us from trying to allocate an immensely large buffer.
2007 * (It won't help if the length is *valid* but immensely large,
2008 * but that's another matter; in any case, that would happen only
2009 * if we had an immensely large tvbuff....)
2011 * XXX - so why are we doing tvb_ensure_bytes_exist()?
2013 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
2014 if (size_is == sizeof(guint16)) {
2016 * Assume little-endian UTF-16.
2018 * XXX - is this always little-endian?
2020 s = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, buffer_len,
2021 ENC_UTF_16|ENC_LITTLE_ENDIAN);
2024 * XXX - what if size_is is neither 1 nor 2?
2026 s = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, buffer_len,
2027 DREP_ENC_CHAR(drep));
2029 if (tree && buffer_len)
2030 proto_tree_add_string(string_tree, hfindex, tvb, offset,
2033 if (string_item != NULL)
2034 proto_item_append_text(string_item, ": %s", s);
2039 offset += buffer_len;
2041 proto_item_set_end(string_item, tvb, offset);
2047 dissect_ndr_cstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2048 proto_tree *tree, dcerpc_info *di, guint8 *drep, int size_is,
2049 int hfindex, gboolean add_subtree, char **data)
2051 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep, size_is, hfindex, add_subtree, data);
2054 /* Dissect an conformant varying string of chars.
2055 This corresponds to IDL of the form '[string] char *foo'.
2057 XXX - at least according to the DCE RPC 1.1 spec, a string has
2058 a null terminator, which isn't necessary as a terminator for
2059 the transfer language (as there's a length), but is presumably
2060 there for the benefit of null-terminated-string languages
2061 such as C. Is this ever used for purely counted strings?
2062 (Not that it matters if it is.) */
2064 dissect_ndr_char_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2065 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2067 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep,
2068 sizeof(guint8), di->hf_index,
2072 /* Dissect a conformant varying string of wchars (wide characters).
2073 This corresponds to IDL of the form '[string] wchar *foo'
2075 XXX - at least according to the DCE RPC 1.1 spec, a string has
2076 a null terminator, which isn't necessary as a terminator for
2077 the transfer language (as there's a length), but is presumably
2078 there for the benefit of null-terminated-string languages
2079 such as C. Is this ever used for purely counted strings?
2080 (Not that it matters if it is.) */
2082 dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2083 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2085 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep,
2086 sizeof(guint16), di->hf_index,
2090 /* This function is aimed for PIDL usage and dissects a UNIQUE pointer to
2094 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)
2097 gint levels = CB_STR_ITEM_LEVELS(param);
2099 offset = dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep,
2103 if (!di->conformant_run) {
2104 /* Append string to COL_INFO */
2105 if (param & PIDL_SET_COL_INFO) {
2106 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", s);
2108 /* Save string to dcv->private_data */
2109 if ((param & PIDL_STR_SAVE)
2110 && (!pinfo->fd->flags.visited)) {
2111 dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2112 dcv->private_data = wmem_strdup(wmem_file_scope(), s);
2114 /* Append string to upper-level proto_items */
2115 if ((levels > 0) && tree && s && s[0]) {
2116 proto_item_append_text(tree, ": %s", s);
2117 tree = tree->parent;
2120 proto_item_append_text(tree, ": %s", s);
2121 tree = tree->parent;
2123 while (levels > 0) {
2124 proto_item_append_text(tree, " %s", s);
2125 tree = tree->parent;
2136 /* Dissect an NDR varying string of elements.
2137 The length of each element is given by the 'size_is' parameter;
2138 the elements are assumed to be characters or wide characters.
2141 dissect_ndr_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2142 proto_tree *tree, dcerpc_info *di, guint8 *drep, int size_is,
2143 int hfindex, gboolean add_subtree, char **data)
2145 header_field_info *hfinfo;
2146 proto_item *string_item;
2147 proto_tree *string_tree;
2152 /* Make sure this really is a string field. */
2153 hfinfo = proto_registrar_get_nth(hfindex);
2154 DISSECTOR_ASSERT(hfinfo->type == FT_STRING);
2156 if (di->conformant_run) {
2157 /* just a run to handle conformant arrays, no scalars to dissect */
2162 string_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_dcerpc_string, &string_item,
2163 proto_registrar_get_name(hfindex));
2169 /* NDR array header */
2170 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
2171 hf_dcerpc_array_offset, NULL);
2173 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
2174 hf_dcerpc_array_actual_count, &len);
2176 DISSECTOR_ASSERT(len <= G_MAXUINT32);
2177 buffer_len = size_is * (guint32)len;
2180 if (!di->no_align && (offset % size_is))
2181 offset += size_is - (offset % size_is);
2184 * "tvb_get_string_enc()" throws an exception if the entire string
2185 * isn't in the tvbuff. If the length is bogus, this should
2186 * keep us from trying to allocate an immensely large buffer.
2187 * (It won't help if the length is *valid* but immensely large,
2188 * but that's another matter; in any case, that would happen only
2189 * if we had an immensely large tvbuff....)
2191 * XXX - so why are we doing tvb_ensure_bytes_exist()?
2193 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
2194 if (size_is == sizeof(guint16)) {
2196 * Assume little-endian UTF-16.
2198 * XXX - is this always little-endian?
2200 s = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, buffer_len,
2201 ENC_UTF_16|ENC_LITTLE_ENDIAN);
2204 * XXX - what if size_is is neither 1 nor 2?
2206 s = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, buffer_len,
2207 DREP_ENC_CHAR(drep));
2209 if (tree && buffer_len)
2210 proto_tree_add_string(string_tree, hfindex, tvb, offset,
2213 if (string_item != NULL)
2214 proto_item_append_text(string_item, ": %s", s);
2219 offset += buffer_len;
2221 proto_item_set_end(string_item, tvb, offset);
2226 /* Dissect an varying string of chars.
2227 This corresponds to IDL of the form '[string] char *foo'.
2229 XXX - at least according to the DCE RPC 1.1 spec, a string has
2230 a null terminator, which isn't necessary as a terminator for
2231 the transfer language (as there's a length), but is presumably
2232 there for the benefit of null-terminated-string languages
2233 such as C. Is this ever used for purely counted strings?
2234 (Not that it matters if it is.) */
2236 dissect_ndr_char_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2237 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2239 return dissect_ndr_vstring(tvb, offset, pinfo, tree, di, drep,
2240 sizeof(guint8), di->hf_index,
2244 /* Dissect a varying string of wchars (wide characters).
2245 This corresponds to IDL of the form '[string] wchar *foo'
2247 XXX - at least according to the DCE RPC 1.1 spec, a string has
2248 a null terminator, which isn't necessary as a terminator for
2249 the transfer language (as there's a length), but is presumably
2250 there for the benefit of null-terminated-string languages
2251 such as C. Is this ever used for purely counted strings?
2252 (Not that it matters if it is.) */
2254 dissect_ndr_wchar_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2255 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2257 return dissect_ndr_vstring(tvb, offset, pinfo, tree, di, drep,
2258 sizeof(guint16), di->hf_index,
2263 /* ndr pointer handling */
2264 /* list of pointers encountered so far */
2265 static GSList *ndr_pointer_list = NULL;
2267 /* position where in the list to insert newly encountered pointers */
2268 static int ndr_pointer_list_pos = 0;
2270 /* Boolean controlling whether pointers are top-level or embedded */
2271 static gboolean pointers_are_top_level = TRUE;
2273 /* as a kludge, we represent all embedded reference pointers as id == -1
2274 hoping that his will not collide with any non-ref pointers */
2275 typedef struct ndr_pointer_data {
2277 proto_item *item; /* proto_item for pointer */
2278 proto_tree *tree; /* subtree of above item */
2279 dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
2281 dcerpc_callback_fnct_t *callback;
2282 void *callback_args;
2283 } ndr_pointer_data_t;
2286 init_ndr_pointer_list(dcerpc_info *di)
2288 di->conformant_run = 0;
2290 while (ndr_pointer_list) {
2291 ndr_pointer_data_t *npd = (ndr_pointer_data_t *)g_slist_nth_data(ndr_pointer_list, 0);
2292 ndr_pointer_list = g_slist_remove(ndr_pointer_list, npd);
2296 ndr_pointer_list = NULL;
2297 ndr_pointer_list_pos = 0;
2298 pointers_are_top_level = TRUE;
2302 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, dcerpc_info *di, guint8 *drep)
2304 int found_new_pointer;
2313 found_new_pointer = 0;
2314 len = g_slist_length(ndr_pointer_list);
2315 for (i=next_pointer; i<len; i++) {
2316 ndr_pointer_data_t *tnpd = (ndr_pointer_data_t *)g_slist_nth_data(ndr_pointer_list, i);
2318 dcerpc_dissect_fnct_t *fnct;
2321 found_new_pointer = 1;
2324 ndr_pointer_list_pos = i+1;
2325 di->hf_index = tnpd->hf_index;
2326 /* first a run to handle any conformant
2328 di->conformant_run = 1;
2329 di->conformant_eaten = 0;
2330 old_offset = offset;
2331 offset = (*(fnct))(tvb, offset, pinfo, NULL, di, drep);
2333 DISSECTOR_ASSERT((offset-old_offset) == di->conformant_eaten);
2334 /* This is to check for any bugs in the dissectors.
2336 * Basically, the NDR representation will store all
2337 * arrays in two blocks, one block with the dimension
2338 * description, like size, number of elements and such,
2339 * and another block that contains the actual data stored
2341 * If the array is embedded directly inside another,
2342 * encapsulating aggregate type, like a union or struct,
2343 * then these two blocks will be stored at different places
2344 * in the bytestream, with other data between the blocks.
2346 * For this reason, all pointers to types (both aggregate
2347 * and scalar, for simplicity no distinction is made)
2348 * will have its dissector called twice.
2349 * The dissector will first be called with conformant_run == 1
2350 * in which mode the dissector MUST NOT consume any data from
2351 * the tvbuff (i.e. may not dissect anything) except the
2352 * initial control block for arrays.
2353 * The second time the dissector is called, with
2354 * conformant_run == 0, all other data for the type will be
2357 * All dissect_ndr_<type> dissectors are already prepared
2358 * for this and knows when it should eat data from the tvb
2359 * and when not to, so implementors of dissectors will
2360 * normally not need to worry about this or even know about
2361 * it. However, if a dissector for an aggregate type calls
2362 * a subdissector from outside packet-dcerpc.c, such as
2363 * the dissector in packet-smb.c for NT Security Descriptors
2364 * as an example, then it is VERY important to encapsulate
2365 * this call to an external subdissector with the appropriate
2366 * test for conformant_run, i.e. it will need something like
2368 * dcerpc_info *di (received as function parameter)
2370 * if (di->conformant_run) {
2374 * to make sure it makes the right thing.
2375 * This assert will signal when someone has forgotten to
2376 * make the dissector aware of this requirement.
2379 /* now we dissect the actual pointer */
2380 di->conformant_run = 0;
2381 old_offset = offset;
2382 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, di, drep);
2384 tnpd->callback(pinfo, tnpd->tree, tnpd->item, di, tvb, old_offset, offset, tnpd->callback_args);
2385 proto_item_set_len(tnpd->item, offset - old_offset);
2389 } while (found_new_pointer);
2396 add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
2397 dcerpc_info *di, dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index,
2398 dcerpc_callback_fnct_t *callback, void *callback_args)
2400 ndr_pointer_data_t *npd;
2402 /* check if this pointer is valid */
2403 if (id != 0xffffffff) {
2404 dcerpc_call_value *value;
2406 value = di->call_data;
2408 if (di->ptype == PDU_REQ) {
2409 if (!(pinfo->fd->flags.visited)) {
2410 if (id > value->max_ptr) {
2411 value->max_ptr = id;
2415 /* if we haven't seen the request bail out since we can't
2416 know whether this is the first non-NULL instance
2418 if (value->req_frame == 0) {
2419 /* XXX THROW EXCEPTION */
2422 /* We saw this one in the request frame, nothing to
2424 if (id <= value->max_ptr) {
2430 npd = (ndr_pointer_data_t *)g_malloc(sizeof(ndr_pointer_data_t));
2435 npd->hf_index = hf_index;
2436 npd->callback = callback;
2437 npd->callback_args = callback_args;
2438 ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
2439 ndr_pointer_list_pos);
2440 ndr_pointer_list_pos++;
2445 find_pointer_index(guint32 id)
2447 ndr_pointer_data_t *npd;
2450 len = g_slist_length(ndr_pointer_list);
2451 for (i=0; i<len; i++) {
2452 npd = (ndr_pointer_data_t *)g_slist_nth_data(ndr_pointer_list, i);
2454 if (npd->id == id) {
2463 /* This function dissects an NDR pointer and stores the callback for later
2464 * deferred dissection.
2466 * fnct is the callback function for when we have reached this object in
2469 * type is what type of pointer.
2471 * this is text is what text we should put in any created tree node.
2473 * hf_index is what hf value we want to pass to the callback function when
2474 * it is called, the callback can later pick this one up from di->hf_index.
2476 * callback is executed after the pointer has been dereferenced.
2478 * callback_args is passed as an argument to the callback function
2480 * See packet-dcerpc-samr.c for examples
2483 dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2484 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2485 int type, const char *text, int hf_index,
2486 dcerpc_callback_fnct_t *callback, void *callback_args)
2488 proto_tree *tr = NULL;
2489 gint start_offset = offset;
2490 int pointer_size = 4;
2492 if (di->conformant_run) {
2493 /* this call was only for dissecting the header for any
2494 embedded conformant array. we will not parse any
2495 pointers in this mode.
2499 if (di->call_data->flags & DCERPC_IS_NDR64) {
2504 /*TOP LEVEL REFERENCE POINTER*/
2505 if ( pointers_are_top_level
2506 && (type == NDR_POINTER_REF) ) {
2509 /* we must find out a nice way to do the length here */
2510 tr = proto_tree_add_subtree(tree, tvb, offset, 0,
2511 ett_dcerpc_pointer_data, &item, text);
2513 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
2514 hf_index, callback, callback_args);
2518 /*TOP LEVEL FULL POINTER*/
2519 if ( pointers_are_top_level
2520 && (type == NDR_POINTER_PTR) ) {
2525 /* get the referent id */
2526 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
2528 /* we got a NULL pointer */
2530 proto_tree_add_text(tree, tvb, offset-pointer_size,
2532 "(NULL pointer) %s",text);
2536 /* see if we have seen this pointer before
2537 The value is truncated to 32bits. 64bit values have only been
2538 seen on fuzz-tested files */
2539 idx = find_pointer_index((guint32)id);
2541 /* we have seen this pointer before */
2543 proto_tree_add_text(tree, tvb, offset-pointer_size,
2545 "(duplicate PTR) %s",text);
2550 tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
2551 pointer_size, ett_dcerpc_pointer_data, &item, text);
2552 if (di->call_data->flags & DCERPC_IS_NDR64) {
2553 proto_tree_add_uint64(tr, hf_dcerpc_referent_id64, tvb,
2554 offset-pointer_size, pointer_size, id);
2556 proto_tree_add_uint(tr, hf_dcerpc_referent_id32, tvb,
2557 offset-pointer_size, pointer_size, (guint32)id);
2559 add_pointer_to_list(pinfo, tr, item, di, fnct, (guint32)id, hf_index,
2560 callback, callback_args);
2563 /*TOP LEVEL UNIQUE POINTER*/
2564 if ( pointers_are_top_level
2565 && (type == NDR_POINTER_UNIQUE) ) {
2569 /* get the referent id */
2570 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
2572 /* we got a NULL pointer */
2574 proto_tree_add_text(tree, tvb, offset-pointer_size,
2576 "(NULL pointer) %s",text);
2581 tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
2583 ett_dcerpc_pointer_data, &item, text);
2584 if (di->call_data->flags & DCERPC_IS_NDR64) {
2585 proto_tree_add_uint64(tr, hf_dcerpc_referent_id64, tvb,
2586 offset-pointer_size, pointer_size, id);
2588 proto_tree_add_uint(tr, hf_dcerpc_referent_id32, tvb,
2589 offset-pointer_size, pointer_size, (guint32)id);
2591 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
2592 hf_index, callback, callback_args);
2596 /*EMBEDDED REFERENCE POINTER*/
2597 if ( (!pointers_are_top_level)
2598 && (type == NDR_POINTER_REF) ) {
2602 /* get the referent id */
2603 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
2606 tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
2608 ett_dcerpc_pointer_data,&item,text);
2609 if (di->call_data->flags & DCERPC_IS_NDR64) {
2610 proto_tree_add_uint64(tr, hf_dcerpc_referent_id64, tvb,
2611 offset-pointer_size, pointer_size, id);
2613 proto_tree_add_uint(tr, hf_dcerpc_referent_id32, tvb,
2614 offset-pointer_size, pointer_size, (guint32)id);
2616 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
2617 hf_index, callback, callback_args);
2621 /*EMBEDDED UNIQUE POINTER*/
2622 if ( (!pointers_are_top_level)
2623 && (type == NDR_POINTER_UNIQUE) ) {
2627 /* get the referent id */
2628 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
2630 /* we got a NULL pointer */
2632 proto_tree_add_text(tree, tvb, offset-pointer_size,
2634 "(NULL pointer) %s", text);
2639 tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
2641 ett_dcerpc_pointer_data,&item,text);
2642 if (di->call_data->flags & DCERPC_IS_NDR64) {
2643 proto_tree_add_uint64(tr, hf_dcerpc_referent_id64, tvb,
2644 offset-pointer_size, pointer_size, id);
2646 proto_tree_add_uint(tr, hf_dcerpc_referent_id32, tvb,
2647 offset-pointer_size, pointer_size, (guint32)id);
2649 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
2650 hf_index, callback, callback_args);
2654 /*EMBEDDED FULL POINTER*/
2655 if ( (!pointers_are_top_level)
2656 && (type == NDR_POINTER_PTR) ) {
2661 /* get the referent id */
2662 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
2664 /* we got a NULL pointer */
2666 proto_tree_add_text(tree, tvb, offset-pointer_size,
2668 "(NULL pointer) %s",text);
2672 /* see if we have seen this pointer before
2673 The value is truncated to 32bits. 64bit values have only been
2674 seen on fuzztested files */
2675 idx = find_pointer_index((guint32)id);
2677 /* we have seen this pointer before */
2679 proto_tree_add_text(tree, tvb, offset-pointer_size,
2681 "(duplicate PTR) %s",text);
2686 tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
2688 ett_dcerpc_pointer_data, &item, text);
2689 if (di->call_data->flags & DCERPC_IS_NDR64) {
2690 proto_tree_add_uint64(tr, hf_dcerpc_referent_id64, tvb,
2691 offset-pointer_size, pointer_size, id);
2693 proto_tree_add_uint(tr, hf_dcerpc_referent_id32, tvb,
2694 offset-pointer_size, pointer_size, (guint32)id);
2696 add_pointer_to_list(pinfo, tr, item, di, fnct, (guint32)id, hf_index,
2697 callback, callback_args);
2703 /* After each top level pointer we have dissected we have to
2704 dissect all deferrals before we move on to the next top level
2706 if (pointers_are_top_level == TRUE) {
2707 pointers_are_top_level = FALSE;
2708 offset = dissect_deferred_pointers(pinfo, tvb, offset, di, drep);
2709 pointers_are_top_level = TRUE;
2712 /* Set the length for the new subtree */
2714 proto_item_set_len(tr, offset-start_offset);
2720 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2721 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2722 int type, const char *text, int hf_index)
2724 return dissect_ndr_pointer_cb(
2725 tvb, offset, pinfo, tree, di, drep, fnct, type, text, hf_index,
2729 dissect_ndr_toplevel_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2730 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2731 int type, const char *text, int hf_index)
2735 pointers_are_top_level = TRUE;
2736 ret = dissect_ndr_pointer_cb(
2737 tvb, offset, pinfo, tree, di, drep, fnct, type, text, hf_index,
2742 dissect_ndr_embedded_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2743 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2744 int type, const char *text, int hf_index)
2748 pointers_are_top_level = FALSE;
2749 ret = dissect_ndr_pointer_cb(
2750 tvb, offset, pinfo, tree, di, drep, fnct, type, text, hf_index,
2756 show_stub_data(tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
2757 dcerpc_auth_info *auth_info, gboolean is_encrypted)
2759 int length, plain_length, auth_pad_len;
2760 guint auth_pad_offset;
2763 * We don't show stub data unless we have some in the tvbuff;
2764 * however, in the protocol tree, we show, as the number of
2765 * bytes, the reported number of bytes, not the number of bytes
2766 * that happen to be in the tvbuff.
2768 if (tvb_reported_length_remaining(tvb, offset) > 0) {
2769 auth_pad_len = auth_info?auth_info->auth_pad_len:0;
2770 length = tvb_reported_length_remaining(tvb, offset);
2772 /* if auth_pad_len is larger than length then we ignore auth_pad_len totally */
2773 plain_length = length - auth_pad_len;
2774 if (plain_length < 1) {
2775 plain_length = length;
2778 auth_pad_offset = offset + plain_length;
2780 if ((auth_info != NULL) &&
2781 (auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)) {
2783 proto_tree_add_text(dcerpc_tree, tvb, offset, length,
2784 "Encrypted stub data (%d byte%s)",
2785 length, plurality(length, "", "s"));
2786 /* is the padding is still inside the encrypted blob, don't display it explicit */
2789 proto_tree_add_text(dcerpc_tree, tvb, offset, plain_length,
2790 "Decrypted stub data (%d byte%s)",
2791 plain_length, plurality(plain_length, "", "s"));
2794 proto_tree_add_text(dcerpc_tree, tvb, offset, plain_length,
2795 "Stub data (%d byte%s)", plain_length,
2796 plurality(plain_length, "", "s"));
2798 /* If there is auth padding at the end of the stub, display it */
2799 if (auth_pad_len != 0) {
2800 proto_tree_add_text(dcerpc_tree, tvb, auth_pad_offset,
2802 "Auth Padding (%u byte%s)",
2804 plurality(auth_pad_len, "", "s"));
2810 dcerpc_try_handoff(packet_info *pinfo, proto_tree *tree,
2811 proto_tree *dcerpc_tree,
2812 tvbuff_t *volatile tvb, tvbuff_t *decrypted_tvb,
2813 guint8 *drep, dcerpc_info *info,
2814 dcerpc_auth_info *auth_info)
2816 volatile gint offset = 0;
2817 dcerpc_uuid_key key;
2818 dcerpc_uuid_value *sub_proto;
2819 proto_tree *volatile sub_tree = NULL;
2820 dcerpc_sub_dissector *proc;
2821 const gchar *name = NULL;
2822 const char *volatile saved_proto;
2823 guint length = 0, reported_length = 0;
2824 tvbuff_t *volatile stub_tvb;
2825 volatile guint auth_pad_len;
2826 volatile int auth_pad_offset;
2827 proto_item *sub_item = NULL;
2828 proto_item *pi, *hidden_item;
2830 dcerpc_dissect_fnct_t *volatile sub_dissect;
2832 key.uuid = info->call_data->uuid;
2833 key.ver = info->call_data->ver;
2835 if ((sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key)) == NULL
2836 || !proto_is_protocol_enabled(sub_proto->proto)) {
2838 * We don't have a dissector for this UUID, or the protocol
2839 * for that UUID is disabled.
2842 hidden_item = proto_tree_add_boolean(dcerpc_tree, hf_dcerpc_unknown_if_id,
2843 tvb, offset, 0, TRUE);
2844 PROTO_ITEM_SET_HIDDEN(hidden_item);
2845 col_append_fstr(pinfo->cinfo, COL_INFO, " %s V%u",
2846 guids_resolve_uuid_to_str(&info->call_data->uuid), info->call_data->ver);
2848 if (decrypted_tvb != NULL) {
2849 show_stub_data(decrypted_tvb, 0, dcerpc_tree, auth_info,
2852 show_stub_data(tvb, 0, dcerpc_tree, auth_info, TRUE);
2856 for (proc = sub_proto->procs; proc->name; proc++) {
2857 if (proc->num == info->call_data->opnum) {
2863 col_set_str(pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
2866 col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown operation %u %s",
2867 info->call_data->opnum,
2868 (info->ptype == PDU_REQ) ? "request" : "response");
2870 col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
2871 name, (info->ptype == PDU_REQ) ? "request" : "response");
2873 sub_dissect = (info->ptype == PDU_REQ) ?
2874 proc->dissect_rqst : proc->dissect_resp;
2877 sub_item = proto_tree_add_item(tree, sub_proto->proto_id,
2878 (decrypted_tvb != NULL)?decrypted_tvb:tvb,
2882 sub_tree = proto_item_add_subtree(sub_item, sub_proto->ett);
2884 proto_item_append_text(sub_item, ", unknown operation %u",
2885 info->call_data->opnum);
2887 proto_item_append_text(sub_item, ", %s", name);
2891 * Put the operation number into the tree along with
2892 * the operation's name.
2894 if (sub_proto->opnum_hf != -1)
2895 proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
2896 tvb, 0, 0, info->call_data->opnum,
2897 "Operation: %s (%u)",
2898 name ? name : "Unknown operation",
2899 info->call_data->opnum);
2901 proto_tree_add_uint_format_value(sub_tree, hf_dcerpc_op, tvb,
2902 0, 0, info->call_data->opnum,
2904 name ? name : "Unknown operation",
2905 info->call_data->opnum);
2907 if ((info->ptype == PDU_REQ) && (info->call_data->rep_frame != 0)) {
2908 pi = proto_tree_add_uint(sub_tree, hf_dcerpc_response_in,
2909 tvb, 0, 0, info->call_data->rep_frame);
2910 PROTO_ITEM_SET_GENERATED(pi);
2912 if ((info->ptype == PDU_RESP) && (info->call_data->req_frame != 0)) {
2913 pi = proto_tree_add_uint(sub_tree, hf_dcerpc_request_in,
2914 tvb, 0, 0, info->call_data->req_frame);
2915 PROTO_ITEM_SET_GENERATED(pi);
2919 if (decrypted_tvb != NULL) {
2920 /* Either there was no encryption or we successfully decrypted
2921 the encrypted payload. */
2923 /* We have a subdissector - call it. */
2924 saved_proto = pinfo->current_proto;
2925 pinfo->current_proto = sub_proto->name;
2927 init_ndr_pointer_list(info);
2929 length = tvb_captured_length(decrypted_tvb);
2930 reported_length = tvb_reported_length(decrypted_tvb);
2933 * Remove the authentication padding from the stub data.
2935 if ((auth_info != NULL) && (auth_info->auth_pad_len != 0)) {
2936 if (reported_length >= auth_info->auth_pad_len) {
2938 * OK, the padding length isn't so big that it
2939 * exceeds the stub length. Trim the reported
2940 * length of the tvbuff.
2942 reported_length -= auth_info->auth_pad_len;
2945 * If that exceeds the actual amount of data in
2946 * the tvbuff (which means we have at least one
2947 * byte of authentication padding in the tvbuff),
2948 * trim the actual amount.
2950 if (length > reported_length)
2951 length = reported_length;
2953 stub_tvb = tvb_new_subset(decrypted_tvb, 0, length, reported_length);
2954 auth_pad_len = auth_info->auth_pad_len;
2955 auth_pad_offset = reported_length;
2958 * The padding length exceeds the stub length.
2959 * Don't bother dissecting the stub, trim the padding
2960 * length to what's in the stub data, and show the
2961 * entire stub as authentication padding.
2964 auth_pad_len = reported_length;
2965 auth_pad_offset = 0;
2970 * No authentication padding.
2972 stub_tvb = decrypted_tvb;
2974 auth_pad_offset = 0;
2978 proto_item_set_len(sub_item, length);
2981 if (stub_tvb != NULL) {
2983 * Catch all exceptions other than BoundsError, so that even
2984 * if the stub data is bad, we still show the authentication
2987 * If we get BoundsError, it means the frame was cut short
2988 * by a snapshot length, so there's nothing more to
2989 * dissect; just re-throw that exception.
2994 offset = sub_dissect(stub_tvb, 0, pinfo, sub_tree,
2997 /* If we have a subdissector and it didn't dissect all
2998 data in the tvb, make a note of it. */
2999 remaining = tvb_reported_length_remaining(stub_tvb, offset);
3000 if (remaining > 0) {
3001 proto_tree_add_text(sub_tree, stub_tvb, offset,
3003 "[Long frame (%d byte%s)]",
3005 plurality(remaining, "", "s"));
3006 col_append_fstr(pinfo->cinfo, COL_INFO,
3007 "[Long frame (%d byte%s)]",
3009 plurality(remaining, "", "s"));
3012 } CATCH_NONFATAL_ERRORS {
3014 * Somebody threw an exception that means that there
3015 * was a problem dissecting the payload; that means
3016 * that a dissector was found, so we don't need to
3017 * dissect the payload as data or update the protocol
3020 * Just show the exception and then drive on to show
3021 * the authentication padding.
3023 show_exception(stub_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
3027 /* If there is auth padding at the end of the stub, display it */
3028 if (auth_pad_len != 0) {
3029 proto_tree_add_text(sub_tree, decrypted_tvb, auth_pad_offset,
3031 "Auth Padding (%u byte%s)",
3033 plurality(auth_pad_len, "", "s"));
3036 pinfo->current_proto = saved_proto;
3038 /* No subdissector - show it as stub data. */
3039 if (decrypted_tvb) {
3040 show_stub_data(decrypted_tvb, 0, sub_tree, auth_info, FALSE);
3042 show_stub_data(tvb, 0, sub_tree, auth_info, TRUE);
3046 show_stub_data(tvb, 0, sub_tree, auth_info, TRUE);
3048 tap_queue_packet(dcerpc_tap, pinfo, info);
3053 dissect_dcerpc_verifier(tvbuff_t *tvb, packet_info *pinfo,
3054 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
3055 dcerpc_auth_info *auth_info)
3059 auth_info->auth_data = NULL;
3061 if (auth_info->auth_size != 0) {
3062 dcerpc_auth_subdissector_fns *auth_fns;
3065 auth_offset = hdr->frag_len - hdr->auth_len;
3067 auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
3070 auth_info->auth_data = auth_tvb;
3072 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
3073 auth_info->auth_type))) {
3075 * Catch all bounds-error exceptions, so that even if the
3076 * verifier is bad or we don't have all of it, we still
3077 * show the stub data.
3080 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
3082 } CATCH_BOUNDS_ERRORS {
3083 show_exception(auth_tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
3086 proto_tree_add_text(dcerpc_tree, auth_tvb, 0, hdr->auth_len,
3091 return hdr->auth_len;
3095 dissect_dcerpc_cn_auth(tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
3096 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
3097 gboolean are_credentials, dcerpc_auth_info *auth_info)
3099 volatile int offset;
3102 * Initially set auth_level and auth_type to zero to indicate that we
3103 * haven't yet seen any authentication level information.
3105 auth_info->auth_level = 0;
3106 auth_info->auth_type = 0;
3107 auth_info->auth_size = 0;
3108 auth_info->auth_pad_len = 0;
3111 * The authentication information is at the *end* of the PDU; in
3112 * request and response PDUs, the request and response stub data
3115 * Is there any authentication data (i.e., is the authentication length
3116 * non-zero), and is the authentication length valid (i.e., is it, plus
3117 * 8 bytes for the type/level/pad length/reserved/context id, less than
3118 * or equal to the fragment length minus the starting offset of the
3123 && ((hdr->auth_len + 8) <= (hdr->frag_len - stub_offset))) {
3126 * Yes, there is authentication data, and the length is valid.
3127 * Do we have all the bytes of stub data?
3128 * (If not, we'd throw an exception dissecting *that*, so don't
3129 * bother trying to dissect the authentication information and
3130 * throwing another exception there.)
3132 offset = hdr->frag_len - (hdr->auth_len + 8);
3133 if (offset == 0 || tvb_offset_exists(tvb, offset - 1)) {
3135 * Either there's no stub data, or the last byte of the stub
3136 * data is present in the captured data, so we shouldn't
3137 * get a BoundsError dissecting the stub data.
3139 * Try dissecting the authentication data.
3140 * Catch all exceptions, so that even if the auth info is bad
3141 * or we don't have all of it, we still show the stuff we
3142 * dissect after this, such as stub data.
3145 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3146 hf_dcerpc_auth_type,
3147 &auth_info->auth_type);
3148 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3149 hf_dcerpc_auth_level,
3150 &auth_info->auth_level);
3152 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3153 hf_dcerpc_auth_pad_len,
3154 &auth_info->auth_pad_len);
3155 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3156 hf_dcerpc_auth_rsrvd, NULL);
3157 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3158 hf_dcerpc_auth_ctx_id, NULL);
3161 * Dissect the authentication data.
3163 if (are_credentials) {
3165 dcerpc_auth_subdissector_fns *auth_fns;
3167 auth_tvb = tvb_new_subset(tvb, offset,
3168 MIN(hdr->auth_len,tvb_reported_length_remaining(tvb, offset)),
3171 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
3172 auth_info->auth_type)))
3173 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
3176 proto_tree_add_text(dcerpc_tree, tvb, offset, hdr->auth_len,
3177 "Auth Credentials");
3180 /* Compute the size of the auth block. Note that this should not
3181 include auth padding, since when NTLMSSP encryption is used, the
3182 padding is actually inside the encrypted stub */
3183 auth_info->auth_size = hdr->auth_len + 8;
3184 } CATCH_BOUNDS_ERRORS {
3185 show_exception(tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
3192 /* We need to hash in the SMB fid number to generate a unique hash table
3193 * key as DCERPC over SMB allows several pipes over the same TCP/IP
3195 * We pass this function the transport type here to make sure we only look
3196 * at this function if it came across an SMB pipe.
3197 * Other transports might need to mix in their own extra multiplexing data
3198 * as well in the future.
3202 dcerpc_get_transport_salt(packet_info *pinfo)
3204 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
3206 switch (decode_data->dcetransporttype) {
3207 case DCE_CN_TRANSPORT_SMBPIPE:
3208 /* DCERPC over smb */
3209 return decode_data->dcetransportsalt;
3212 /* Some other transport... */
3217 dcerpc_set_transport_salt(guint64 dcetransportsalt, packet_info *pinfo)
3219 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
3221 decode_data->dcetransportsalt = dcetransportsalt;
3225 * Connection oriented packet types
3229 dissect_dcerpc_cn_bind(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3230 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
3232 conversation_t *conv = find_or_create_conversation(pinfo);
3233 guint8 num_ctx_items = 0;
3236 guint8 num_trans_items;
3241 guint16 if_ver, if_ver_minor;
3242 dcerpc_auth_info auth_info;
3244 const char *uuid_name = NULL;
3245 proto_item *iface_item = NULL;
3246 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
3248 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3249 hf_dcerpc_cn_max_xmit, NULL);
3251 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3252 hf_dcerpc_cn_max_recv, NULL);
3254 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3255 hf_dcerpc_cn_assoc_group, NULL);
3257 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3258 hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
3263 col_append_fstr(pinfo->cinfo, COL_INFO, ", %u context items:", num_ctx_items);
3265 for (i = 0; i < num_ctx_items; i++) {
3266 proto_item *ctx_item = NULL;
3267 proto_tree *ctx_tree = NULL, *iface_tree = NULL;
3268 gint ctx_offset = offset;
3270 dissect_dcerpc_uint16(tvb, offset, pinfo, NULL, hdr->drep,
3271 hf_dcerpc_cn_ctx_id, &ctx_id);
3273 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3274 /* (if we have multiple contexts, this might cause "decode as"
3275 * to behave unpredictably) */
3276 decode_data->dcectxid = ctx_id;
3279 ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_item,
3282 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
3285 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree, hdr->drep,
3286 hf_dcerpc_cn_ctx_id, &ctx_id);
3287 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, ctx_tree, hdr->drep,
3288 hf_dcerpc_cn_num_trans_items, &num_trans_items);
3291 proto_item_append_text(ctx_item, "[%u]: Context ID:%u", i+1, ctx_id);
3297 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &if_id);
3300 iface_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_abstract_syntax, tvb, offset, 0, ENC_NA);
3301 iface_tree = proto_item_add_subtree(iface_item, ett_dcerpc_cn_iface);
3303 uuid_str = guid_to_str(wmem_packet_scope(), (e_guid_t*)&if_id);
3304 uuid_name = guids_get_uuid_name(&if_id);
3306 proto_tree_add_guid_format(iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
3307 offset, 16, (e_guid_t *) &if_id, "Interface: %s UUID: %s", uuid_name, uuid_str);
3308 proto_item_append_text(iface_item, ": %s", uuid_name);
3309 proto_item_append_text(ctx_item, ", %s", uuid_name);
3311 proto_tree_add_guid_format(iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
3312 offset, 16, (e_guid_t *) &if_id, "Interface UUID: %s", uuid_str);
3313 proto_item_append_text(iface_item, ": %s", uuid_str);
3314 proto_item_append_text(ctx_item, ", %s", uuid_str);
3319 if (hdr->drep[0] & DREP_LITTLE_ENDIAN) {
3320 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
3321 hf_dcerpc_cn_bind_if_ver, &if_ver);
3322 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
3323 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
3325 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
3326 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
3327 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
3328 hf_dcerpc_cn_bind_if_ver, &if_ver);
3332 proto_item_append_text(iface_item, " V%u.%u", if_ver, if_ver_minor);
3333 proto_item_set_len(iface_item, 20);
3336 memset(&trans_id, 0, sizeof(trans_id));
3337 for (j = 0; j < num_trans_items; j++) {
3338 proto_tree *trans_tree = NULL;
3339 proto_item *trans_item = NULL;
3340 proto_item *uuid_item = NULL;
3342 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &trans_id);
3345 trans_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_trans_syntax, tvb, offset, 0, ENC_NA);
3346 trans_tree = proto_item_add_subtree(trans_item, ett_dcerpc_cn_trans_syntax);
3348 uuid_str = guid_to_str(wmem_packet_scope(), (e_guid_t *) &trans_id);
3349 uuid_name = guids_get_uuid_name(&trans_id);
3352 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);
3353 proto_item_append_text(trans_item, "[%u]: %s", j+1, uuid_name);
3354 proto_item_append_text(ctx_item, ", %s", uuid_name);
3356 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);
3357 proto_item_append_text(trans_item, "[%u]: %s", j+1, uuid_str);
3358 proto_item_append_text(ctx_item, ", %s", uuid_str);
3361 /* check for [MS-RPCE] 3.3.1.5.3 Bind Time Feature Negotiation */
3362 if (trans_id.Data1 == 0x6cb71c2c && trans_id.Data2 == 0x9812 && trans_id.Data3 == 0x4540) {
3363 proto_tree *uuid_tree = proto_item_add_subtree(uuid_item, ett_dcerpc_cn_trans_btfn);
3364 proto_tree_add_boolean(uuid_tree, hf_dcerpc_cn_bind_trans_btfn_01, tvb, offset+8, 1, trans_id.Data4[0]);
3365 proto_tree_add_boolean(uuid_tree, hf_dcerpc_cn_bind_trans_btfn_02, tvb, offset+8, 1, trans_id.Data4[0]);
3370 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, trans_tree, hdr->drep,
3371 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
3373 proto_item_set_len(trans_item, 20);
3374 proto_item_append_text(trans_item, " V%u", trans_ver);
3378 /* if this is the first time we've seen this packet, we need to
3379 update the dcerpc_binds table so that any later calls can
3380 match to the interface.
3381 XXX We assume that BINDs will NEVER be fragmented.
3383 if (!(pinfo->fd->flags.visited)) {
3384 dcerpc_bind_key *key;
3385 dcerpc_bind_value *value;
3387 key = (dcerpc_bind_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_key));
3389 key->ctx_id = ctx_id;
3390 key->transport_salt = dcerpc_get_transport_salt(pinfo);
3392 value = (dcerpc_bind_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_value));
3393 value->uuid = if_id;
3394 value->ver = if_ver;
3395 value->transport = trans_id;
3397 /* add this entry to the bind table */
3398 g_hash_table_insert(dcerpc_binds, key, value);
3402 col_append_fstr(pinfo->cinfo, COL_INFO, ",");
3403 col_append_fstr(pinfo->cinfo, COL_INFO, " %s V%u.%u (%s)",
3404 guids_resolve_uuid_to_str(&if_id), if_ver, if_ver_minor,
3405 guids_resolve_uuid_to_str(&trans_id));
3408 proto_item_set_len(ctx_item, offset - ctx_offset);
3413 * XXX - we should save the authentication type *if* we have
3414 * an authentication header, and associate it with an authentication
3415 * context, so subsequent PDUs can use that context.
3417 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
3421 dissect_dcerpc_cn_bind_ack(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3422 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
3424 guint16 max_xmit, max_recv;
3425 guint16 sec_addr_len;
3432 dcerpc_auth_info auth_info;
3433 const char *uuid_name = NULL;
3434 const char *result_str = NULL;
3436 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3437 hf_dcerpc_cn_max_xmit, &max_xmit);
3439 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3440 hf_dcerpc_cn_max_recv, &max_recv);
3442 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3443 hf_dcerpc_cn_assoc_group, NULL);
3445 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3446 hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
3447 if (sec_addr_len != 0) {
3448 proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
3449 sec_addr_len, ENC_ASCII|ENC_NA);
3450 offset += sec_addr_len;
3454 offset += 4 - offset % 4;
3457 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3458 hf_dcerpc_cn_num_results, &num_results);
3463 col_append_fstr(pinfo->cinfo, COL_INFO, ", max_xmit: %u max_recv: %u, %u results:",
3464 max_xmit, max_recv, num_results);
3466 for (i = 0; i < num_results; i++) {
3467 proto_tree *ctx_tree = NULL;
3468 proto_item *ctx_item = NULL;
3471 ctx_tree = proto_tree_add_subtree_format(dcerpc_tree, tvb, offset, 24, ett_dcerpc_cn_ctx, &ctx_item, "Ctx Item[%u]:", i+1);
3474 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree,
3475 hdr->drep, hf_dcerpc_cn_ack_result,
3478 /* [MS-RPCE] 3.3.1.5.3 check if this Ctx Item is the response to a Bind Time Feature Negotiation request */
3480 const int old_offset = offset;
3481 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree, hdr->drep, hf_dcerpc_cn_ack_btfn, &reason);
3482 proto_tree_add_boolean(ctx_tree, hf_dcerpc_cn_bind_trans_btfn_01, tvb, old_offset, 1, reason);
3483 proto_tree_add_boolean(ctx_tree, hf_dcerpc_cn_bind_trans_btfn_02, tvb, old_offset, 1, reason);
3484 } else if (result != 0) {
3485 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree,
3486 hdr->drep, hf_dcerpc_cn_ack_reason,
3490 * The reason for rejection isn't meaningful, and often isn't
3491 * set, when the syntax was accepted.
3496 result_str = val_to_str(result, p_cont_result_vals, "Unknown result (%u)");
3499 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &trans_id);
3500 uuid_name = guids_get_uuid_name(&trans_id);
3502 uuid_name = guid_to_str(wmem_packet_scope(), (e_guid_t *) &trans_id);
3504 proto_tree_add_guid_format(ctx_tree, hf_dcerpc_cn_ack_trans_id, tvb,
3505 offset, 16, (e_guid_t *) &trans_id, "Transfer Syntax: %s",
3507 proto_item_append_text(ctx_item, " %s, %s", result_str, uuid_name);
3511 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, ctx_tree, hdr->drep,
3512 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
3515 col_append_fstr(pinfo->cinfo, COL_INFO, ",");
3516 col_append_fstr(pinfo->cinfo, COL_INFO, " %s", result_str);
3520 * XXX - do we need to do anything with the authentication level
3521 * we get back from this?
3523 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
3527 dissect_dcerpc_cn_bind_nak(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3528 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
3531 guint8 num_protocols;
3534 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
3535 hdr->drep, hf_dcerpc_cn_reject_reason,
3538 col_append_fstr(pinfo->cinfo, COL_INFO, " reason: %s",
3539 val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
3541 if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
3542 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3543 hf_dcerpc_cn_num_protocols,
3546 for (i = 0; i < num_protocols; i++) {
3547 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
3548 hdr->drep, hf_dcerpc_cn_protocol_ver_major,
3550 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
3551 hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
3557 /* Return a string describing a DCE/RPC fragment as first, middle, or end
3560 #define PFC_FRAG_MASK 0x03
3563 fragment_type(guint8 flags)
3565 static const char* t[4] = {
3571 return t[flags & PFC_FRAG_MASK];
3574 /* Dissect stub data (payload) of a DCERPC packet. */
3577 dissect_dcerpc_cn_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
3578 proto_tree *dcerpc_tree, proto_tree *tree,
3579 e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
3580 dcerpc_auth_info *auth_info, guint32 alloc_hint _U_,
3583 gint length, reported_length;
3584 gboolean save_fragmented;
3585 fragment_head *fd_head = NULL;
3587 tvbuff_t *auth_tvb, *payload_tvb, *decrypted_tvb;
3589 proto_item *parent_pi;
3590 proto_item *dcerpc_tree_item;
3592 save_fragmented = pinfo->fragmented;
3594 length = tvb_reported_length_remaining(tvb, offset);
3595 reported_length = tvb_reported_length_remaining(tvb, offset);
3596 if (reported_length < 0 ||
3597 (guint32)reported_length < auth_info->auth_size) {
3598 /* We don't even have enough bytes for the authentication
3602 reported_length -= auth_info->auth_size;
3603 if (length > reported_length)
3604 length = reported_length;
3605 payload_tvb = tvb_new_subset(tvb, offset, length, reported_length);
3608 /*don't bother if we don't have the entire tvb */
3609 /*XXX we should really make sure we calculate auth_info->auth_data
3610 and use that one instead of this auth_tvb hack
3612 if (tvb_reported_length(tvb) == tvb_reported_length(tvb)) {
3613 if (tvb_reported_length_remaining(tvb, offset+length) > 8) {
3614 auth_tvb = tvb_new_subset_remaining(tvb, offset+length+8);
3618 /* Decrypt the PDU if it is encrypted */
3620 if (auth_info->auth_type &&
3621 (auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)) {
3623 * We know the authentication type, and the authentication
3624 * level is "Packet privacy", meaning the payload is
3625 * encrypted; attempt to decrypt it.
3627 dcerpc_auth_subdissector_fns *auth_fns;
3629 /* Start out assuming we won't succeed in decrypting. */
3630 decrypted_tvb = NULL;
3631 /* Schannel needs information into the footer (verifier) in order to setup decryption keys
3632 * so we call it in order to have a chance to decipher the data
3634 if (DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN == auth_info->auth_type) {
3635 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, auth_info);
3638 if ((auth_fns = get_auth_subdissector_fns(
3639 auth_info->auth_level, auth_info->auth_type))) {
3642 result = decode_encrypted_data(
3643 payload_tvb, auth_tvb, pinfo, auth_fns,
3644 hdr->ptype == PDU_REQ, auth_info);
3648 proto_tree_add_text(
3649 dcerpc_tree, payload_tvb, 0, -1,
3650 "Encrypted stub data (%d byte%s)",
3651 tvb_reported_length(payload_tvb),
3653 plurality(tvb_reported_length(payload_tvb), "", "s"));
3655 add_new_data_source(
3656 pinfo, result, "Decrypted stub data");
3659 decrypted_tvb = result;
3663 decrypted_tvb = payload_tvb;
3665 /* if this packet is not fragmented, just dissect it and exit */
3666 if (PFC_NOT_FRAGMENTED(hdr)) {
3667 pinfo->fragmented = FALSE;
3670 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
3671 hdr->drep, di, auth_info);
3673 pinfo->fragmented = save_fragmented;
3677 /* The packet is fragmented. */
3678 pinfo->fragmented = TRUE;
3680 /* debug output of essential fragment data. */
3681 /* leave it here for future debugging sessions */
3682 /*printf("DCE num:%u offset:%u frag_len:%u tvb_len:%u\n",
3683 pinfo->fd->num, offset, hdr->frag_len, tvb_reported_length(decrypted_tvb));*/
3685 /* if we are not doing reassembly and this is the first fragment
3686 then just dissect it and exit
3687 XXX - if we're not doing reassembly, can we decrypt an
3690 if ( (!dcerpc_reassemble) && (hdr->flags & PFC_FIRST_FRAG) ) {
3693 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
3694 hdr->drep, di, auth_info);
3696 expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment, "%s fragment", fragment_type(hdr->flags));
3698 pinfo->fragmented = save_fragmented;
3702 /* if we have already seen this packet, see if it was reassembled
3703 and if so dissect the full pdu.
3706 if (pinfo->fd->flags.visited) {
3707 fd_head = fragment_get_reassembled(&dcerpc_co_reassembly_table, frame);
3711 /* if we are not doing reassembly and it was neither a complete PDU
3712 nor the first fragment then there is nothing more we can do
3713 so we just have to exit
3715 if ( !dcerpc_reassemble || (tvb_captured_length(tvb) != tvb_reported_length(tvb)) )
3718 /* if we didn't get 'frame' we don't know where the PDU started and thus
3719 it is pointless to continue
3724 /* from now on we must attempt to reassemble the PDU
3727 /* if we get here we know it is the first time we see the packet
3728 and we also know it is only a fragment and not a full PDU,
3729 thus we must reassemble it.
3732 /* Do we have any non-encrypted data to reassemble? */
3733 if (decrypted_tvb == NULL) {
3734 /* No. We can't even try to reassemble. */
3738 /* defragmentation is a bit tricky, as there's no offset of the fragment
3739 * in the protocol data.
3741 * just use fragment_add_seq_next() and hope that TCP/SMB segments coming
3742 * in with the correct sequence.
3744 fd_head = fragment_add_seq_next(&dcerpc_co_reassembly_table,
3745 decrypted_tvb, 0, pinfo, frame, NULL,
3746 tvb_reported_length(decrypted_tvb),
3747 hdr->flags&PFC_LAST_FRAG ? FALSE : TRUE /* more_frags */);
3751 /* if reassembly is complete and this is the last fragment
3752 * (multiple fragments in one PDU are possible!)
3753 * dissect the full PDU
3755 if (fd_head && (fd_head->flags & FD_DEFRAGMENTED) ) {
3757 if ((pinfo->fd->num == fd_head->reassembled_in) && (hdr->flags & PFC_LAST_FRAG) ) {
3759 proto_item *frag_tree_item;
3761 next_tvb = tvb_new_chain((decrypted_tvb)?decrypted_tvb:payload_tvb,
3764 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3765 show_fragment_tree(fd_head, &dcerpc_frag_items,
3766 tree, pinfo, next_tvb, &frag_tree_item);
3767 /* the toplevel fragment subtree is now behind all desegmented data,
3768 * move it right behind the DCE/RPC tree */
3769 dcerpc_tree_item = proto_tree_get_parent(dcerpc_tree);
3770 if (frag_tree_item && dcerpc_tree_item) {
3771 proto_tree_move_item(tree, dcerpc_tree_item, frag_tree_item);
3774 pinfo->fragmented = FALSE;
3776 expert_add_info_format(pinfo, frag_tree_item, &ei_dcerpc_fragment_reassembled, "%s fragment, reassembled", fragment_type(hdr->flags));
3778 dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb,
3779 next_tvb, hdr->drep, di, auth_info);
3782 if (decrypted_tvb) {
3783 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
3784 decrypted_tvb, 0, 0, fd_head->reassembled_in);
3786 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
3787 payload_tvb, 0, 0, fd_head->reassembled_in);
3789 PROTO_ITEM_SET_GENERATED(pi);
3790 parent_pi = proto_tree_get_parent(dcerpc_tree);
3791 if (parent_pi != NULL) {
3792 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
3794 col_append_fstr(pinfo->cinfo, COL_INFO,
3795 " [DCE/RPC %s fragment, reas: #%u]", fragment_type(hdr->flags), fd_head->reassembled_in);
3796 expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment_reassembled, "%s fragment, reassembled in #%u", fragment_type(hdr->flags), fd_head->reassembled_in);
3799 /* Reassembly not complete - some fragments
3800 are missing. Just show the stub data. */
3801 expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment, "%s fragment", fragment_type(hdr->flags));
3803 if (decrypted_tvb) {
3804 show_stub_data(decrypted_tvb, 0, tree, auth_info, FALSE);
3806 show_stub_data(payload_tvb, 0, tree, auth_info, TRUE);
3810 pinfo->fragmented = save_fragmented;
3814 dissect_dcerpc_cn_rqst(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3815 proto_tree *dcerpc_tree, proto_tree *tree,
3816 e_dce_cn_common_hdr_t *hdr)
3818 conversation_t *conv;
3821 e_uuid_t obj_id = DCERPC_UUID_NULL;
3822 dcerpc_auth_info auth_info;
3825 proto_item *parent_pi;
3826 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
3828 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3829 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3831 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3832 hf_dcerpc_cn_ctx_id, &ctx_id);
3833 parent_pi = proto_tree_get_parent(dcerpc_tree);
3834 if (parent_pi != NULL) {
3835 proto_item_append_text(parent_pi, ", Ctx: %u", ctx_id);
3838 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3839 hf_dcerpc_opnum, &opnum);
3841 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3842 decode_data->dcectxid = ctx_id;
3844 col_append_fstr(pinfo->cinfo, COL_INFO, ", opnum: %u, Ctx: %u",
3847 if (hdr->flags & PFC_OBJECT_UUID) {
3848 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &obj_id);
3850 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
3851 offset, 16, (e_guid_t *) &obj_id, "Object UUID: %s",
3852 guid_to_str(wmem_packet_scope(), (e_guid_t *) &obj_id));
3858 * XXX - what if this was set when the connection was set up,
3859 * and we just have a security context?
3861 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3863 conv = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3864 pinfo->srcport, pinfo->destport, 0);
3866 show_stub_data(tvb, offset, dcerpc_tree, &auth_info, TRUE);
3868 dcerpc_matched_key matched_key, *new_matched_key;
3869 dcerpc_call_value *value;
3871 /* !!! we can NOT check flags.visited here since this will interact
3872 badly with when SMB handles (i.e. calls the subdissector)
3873 and desegmented pdu's .
3874 Instead we check if this pdu is already in the matched table or not
3876 matched_key.frame = pinfo->fd->num;
3877 matched_key.call_id = hdr->call_id;
3878 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
3880 dcerpc_bind_key bind_key;
3881 dcerpc_bind_value *bind_value;
3883 bind_key.conv = conv;
3884 bind_key.ctx_id = ctx_id;
3885 bind_key.transport_salt = dcerpc_get_transport_salt(pinfo);
3887 if ((bind_value = (dcerpc_bind_value *)g_hash_table_lookup(dcerpc_binds, &bind_key)) ) {
3888 if (!(hdr->flags&PFC_FIRST_FRAG)) {
3889 dcerpc_cn_call_key call_key;
3890 dcerpc_call_value *call_value;
3892 call_key.conv = conv;
3893 call_key.call_id = hdr->call_id;
3894 call_key.transport_salt = dcerpc_get_transport_salt(pinfo);
3895 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_cn_calls, &call_key))) {
3896 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
3897 *new_matched_key = matched_key;
3898 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
3902 dcerpc_cn_call_key *call_key;
3903 dcerpc_call_value *call_value;
3905 /* We found the binding and it is the first fragment
3906 (or a complete PDU) of a dcerpc pdu so just add
3907 the call to both the call table and the
3910 call_key = (dcerpc_cn_call_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_cn_call_key));
3911 call_key->conv = conv;
3912 call_key->call_id = hdr->call_id;
3913 call_key->transport_salt = dcerpc_get_transport_salt(pinfo);
3915 /* if there is already a matching call in the table
3916 remove it so it is replaced with the new one */
3917 if (g_hash_table_lookup(dcerpc_cn_calls, call_key)) {
3918 g_hash_table_remove(dcerpc_cn_calls, call_key);
3921 call_value = (dcerpc_call_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_call_value));
3922 call_value->uuid = bind_value->uuid;
3923 call_value->ver = bind_value->ver;
3924 call_value->object_uuid = obj_id;
3925 call_value->opnum = opnum;
3926 call_value->req_frame = pinfo->fd->num;
3927 call_value->req_time = pinfo->fd->abs_ts;
3928 call_value->rep_frame = 0;
3929 call_value->max_ptr = 0;
3930 call_value->se_data = NULL;
3931 call_value->private_data = NULL;
3932 call_value->pol = NULL;
3933 call_value->flags = 0;
3934 if (!memcmp(&bind_value->transport, &uuid_ndr64, sizeof(uuid_ndr64))) {
3935 call_value->flags |= DCERPC_IS_NDR64;
3938 g_hash_table_insert(dcerpc_cn_calls, call_key, call_value);
3940 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
3941 *new_matched_key = matched_key;
3942 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
3951 di = wmem_new0(wmem_packet_scope(), dcerpc_info);
3952 /* handoff this call */
3953 di->dcerpc_procedure_name = "";
3955 di->call_id = hdr->call_id;
3956 di->transport_salt = dcerpc_get_transport_salt(pinfo);
3957 di->ptype = PDU_REQ;
3958 di->call_data = value;
3961 if (value->rep_frame != 0) {
3962 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
3963 tvb, 0, 0, value->rep_frame);
3964 PROTO_ITEM_SET_GENERATED(pi);
3965 if (parent_pi != NULL) {
3966 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
3970 dissect_dcerpc_cn_stub(tvb, offset, pinfo, dcerpc_tree, tree,
3971 hdr, di, &auth_info, alloc_hint,
3974 /* no bind information, simply show stub data */
3975 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);
3976 show_stub_data(tvb, offset, dcerpc_tree, &auth_info, TRUE);
3980 /* Dissect the verifier */
3981 dissect_dcerpc_verifier(tvb, pinfo, dcerpc_tree, hdr, &auth_info);
3986 dissect_dcerpc_cn_resp(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3987 proto_tree *dcerpc_tree, proto_tree *tree,
3988 e_dce_cn_common_hdr_t *hdr)
3990 dcerpc_call_value *value = NULL;
3991 conversation_t *conv;
3993 dcerpc_auth_info auth_info;
3996 proto_item *parent_pi;
3997 e_uuid_t obj_id_null = DCERPC_UUID_NULL;
3998 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
4000 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4001 hf_dcerpc_cn_alloc_hint, &alloc_hint);
4003 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4004 hf_dcerpc_cn_ctx_id, &ctx_id);
4005 parent_pi = proto_tree_get_parent(dcerpc_tree);
4006 if (parent_pi != NULL) {
4007 proto_item_append_text(parent_pi, ", Ctx: %u", ctx_id);
4010 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
4011 decode_data->dcectxid = ctx_id;
4013 col_append_fstr(pinfo->cinfo, COL_INFO, ", Ctx: %u", ctx_id);
4015 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4016 hf_dcerpc_cn_cancel_count, NULL);
4021 * XXX - what if this was set when the connection was set up,
4022 * and we just have a security context?
4024 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
4026 conv = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
4027 pinfo->srcport, pinfo->destport, 0);
4030 /* no point in creating one here, really */
4031 show_stub_data(tvb, offset, dcerpc_tree, &auth_info, TRUE);
4033 dcerpc_matched_key matched_key, *new_matched_key;
4035 /* !!! we can NOT check flags.visited here since this will interact
4036 badly with when SMB handles (i.e. calls the subdissector)
4037 and desegmented pdu's .
4038 Instead we check if this pdu is already in the matched table or not
4040 matched_key.frame = pinfo->fd->num;
4041 matched_key.call_id = hdr->call_id;
4042 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
4044 dcerpc_cn_call_key call_key;
4045 dcerpc_call_value *call_value;
4047 call_key.conv = conv;
4048 call_key.call_id = hdr->call_id;
4049 call_key.transport_salt = dcerpc_get_transport_salt(pinfo);
4051 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_cn_calls, &call_key))) {
4052 /* extra sanity check, only match them if the reply
4053 came after the request */
4054 if (call_value->req_frame<pinfo->fd->num) {
4055 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
4056 *new_matched_key = matched_key;
4057 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
4059 if (call_value->rep_frame == 0) {
4060 call_value->rep_frame = pinfo->fd->num;
4069 di = wmem_new0(wmem_packet_scope(), dcerpc_info);
4070 /* handoff this call */
4071 di->dcerpc_procedure_name = "";
4073 di->call_id = hdr->call_id;
4074 di->transport_salt = dcerpc_get_transport_salt(pinfo);
4075 di->ptype = PDU_RESP;
4076 di->call_data = value;
4078 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
4080 /* (optional) "Object UUID" from request */
4081 if (dcerpc_tree && (memcmp(&value->object_uuid, &obj_id_null, sizeof(obj_id_null)) != 0)) {
4082 pi = proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
4083 offset, 0, (e_guid_t *) &value->object_uuid, "Object UUID: %s",
4084 guid_to_str(wmem_packet_scope(), (e_guid_t *) &value->object_uuid));
4085 PROTO_ITEM_SET_GENERATED(pi);
4089 if (value->req_frame != 0) {
4091 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4092 tvb, 0, 0, value->req_frame);
4093 PROTO_ITEM_SET_GENERATED(pi);
4094 if (parent_pi != NULL) {
4095 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
4097 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
4098 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
4099 PROTO_ITEM_SET_GENERATED(pi);
4101 proto_tree_add_expert(dcerpc_tree, pinfo, &ei_dcerpc_no_request_found, tvb, 0, 0);
4104 dissect_dcerpc_cn_stub(tvb, offset, pinfo, dcerpc_tree, tree,
4105 hdr, di, &auth_info, alloc_hint,
4108 /* no bind information, simply show stub data */
4109 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);
4110 show_stub_data(tvb, offset, dcerpc_tree, &auth_info, TRUE);
4114 /* Dissect the verifier */
4115 dissect_dcerpc_verifier(tvb, pinfo, dcerpc_tree, hdr, &auth_info);
4119 dissect_dcerpc_cn_fault(tvbuff_t *tvb, gint offset, packet_info *pinfo,
4120 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
4122 dcerpc_call_value *value = NULL;
4123 conversation_t *conv;
4127 dcerpc_auth_info auth_info;
4128 proto_item *pi = NULL;
4129 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
4131 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4132 hf_dcerpc_cn_alloc_hint, &alloc_hint);
4134 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4135 hf_dcerpc_cn_ctx_id, &ctx_id);
4137 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4138 hf_dcerpc_cn_cancel_count, NULL);
4143 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4144 hf_dcerpc_cn_status, &status);
4146 status = ((hdr->drep[0] & DREP_LITTLE_ENDIAN)
4147 ? tvb_get_letohl(tvb, offset)
4148 : tvb_get_ntohl(tvb, offset));
4150 pi = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_status, tvb, offset, 4, DREP_ENC_INTEGER(hdr->drep));
4153 expert_add_info_format(pinfo, pi, &ei_dcerpc_cn_status, "Fault: %s", val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
4155 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
4156 decode_data->dcectxid = ctx_id;
4158 col_append_fstr(pinfo->cinfo, COL_INFO,
4159 ", Ctx: %u, status: %s", ctx_id,
4160 val_to_str(status, reject_status_vals,
4161 "Unknown (0x%08x)"));
4167 * XXX - what if this was set when the connection was set up,
4168 * and we just have a security context?
4170 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
4172 conv = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
4173 pinfo->srcport, pinfo->destport, 0);
4175 /* no point in creating one here, really */
4177 dcerpc_matched_key matched_key, *new_matched_key;
4179 /* !!! we can NOT check flags.visited here since this will interact
4180 badly with when SMB handles (i.e. calls the subdissector)
4181 and desegmented pdu's .
4182 Instead we check if this pdu is already in the matched table or not
4184 matched_key.frame = pinfo->fd->num;
4185 matched_key.call_id = hdr->call_id;
4186 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
4188 dcerpc_cn_call_key call_key;
4189 dcerpc_call_value *call_value;
4191 call_key.conv = conv;
4192 call_key.call_id = hdr->call_id;
4193 call_key.transport_salt = dcerpc_get_transport_salt(pinfo);
4195 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_cn_calls, &call_key))) {
4196 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
4197 *new_matched_key = matched_key;
4198 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
4201 if (call_value->rep_frame == 0) {
4202 call_value->rep_frame = pinfo->fd->num;
4209 int length, stub_length;
4211 proto_item *parent_pi;
4213 di = wmem_new0(wmem_packet_scope(), dcerpc_info);
4214 /* handoff this call */
4215 di->dcerpc_procedure_name = "";
4217 di->call_id = hdr->call_id;
4218 di->transport_salt = dcerpc_get_transport_salt(pinfo);
4219 di->ptype = PDU_FAULT;
4220 di->call_data = value;
4222 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
4223 if (value->req_frame != 0) {
4225 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4226 tvb, 0, 0, value->req_frame);
4227 PROTO_ITEM_SET_GENERATED(pi);
4228 parent_pi = proto_tree_get_parent(dcerpc_tree);
4229 if (parent_pi != NULL) {
4230 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
4232 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
4233 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
4234 PROTO_ITEM_SET_GENERATED(pi);
4236 proto_tree_add_expert(dcerpc_tree, pinfo, &ei_dcerpc_no_request_found, tvb, 0, 0);
4239 length = tvb_reported_length_remaining(tvb, offset);
4240 /* as we now create a tvb in dissect_dcerpc_cn() containing only the
4241 * stub_data, the following calculation is no longer valid:
4242 * stub_length = hdr->frag_len - offset - auth_info.auth_size;
4243 * simply use the remaining length of the tvb instead.
4244 * XXX - or better use the reported_length?!?
4246 stub_length = length;
4247 if (length > stub_length)
4248 length = stub_length;
4250 /* If we don't have reassembly enabled, or this packet contains
4251 the entire PDU, or if we don't have all the data in this
4252 fragment, just call the handoff directly if this is the
4253 first fragment or the PDU isn't fragmented. */
4254 if ( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
4255 !tvb_bytes_exist(tvb, offset, stub_length) ) {
4256 if (hdr->flags&PFC_FIRST_FRAG) {
4257 /* First fragment, possibly the only fragment */
4259 * XXX - should there be a third routine for each
4260 * function in an RPC subdissector, to handle
4261 * fault responses? The DCE RPC 1.1 spec says
4262 * three's "stub data" here, which I infer means
4263 * that it's protocol-specific and call-specific.
4265 * It should probably get passed the status code
4266 * as well, as that might be protocol-specific.
4269 if (stub_length > 0) {
4270 proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
4271 "Fault stub data (%d byte%s)",
4273 plurality(stub_length, "", "s"));
4277 /* PDU is fragmented and this isn't the first fragment */
4279 if (stub_length > 0) {
4280 proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
4281 "Fragment data (%d byte%s)",
4283 plurality(stub_length, "", "s"));
4288 /* Reassembly is enabled, the PDU is fragmented, and
4289 we have all the data in the fragment; the first two
4290 of those mean we should attempt reassembly, and the
4291 third means we can attempt reassembly. */
4294 proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
4295 "Fragment data (%d byte%s)",
4297 plurality(stub_length, "", "s"));
4300 if (hdr->flags&PFC_FIRST_FRAG) { /* FIRST fragment */
4301 if ( (!pinfo->fd->flags.visited) && value->rep_frame ) {
4302 fragment_add_seq_next(&dcerpc_co_reassembly_table,
4304 pinfo, value->rep_frame, NULL,
4308 } else if (hdr->flags&PFC_LAST_FRAG) { /* LAST fragment */
4309 if ( value->rep_frame ) {
4310 fragment_head *fd_head;
4312 fd_head = fragment_add_seq_next(&dcerpc_co_reassembly_table,
4314 pinfo, value->rep_frame, NULL,
4319 /* We completed reassembly */
4321 proto_item *frag_tree_item;
4323 next_tvb = tvb_new_chain(tvb, fd_head->tvb_data);
4324 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
4325 show_fragment_tree(fd_head, &dcerpc_frag_items,
4326 dcerpc_tree, pinfo, next_tvb, &frag_tree_item);
4329 * XXX - should there be a third routine for each
4330 * function in an RPC subdissector, to handle
4331 * fault responses? The DCE RPC 1.1 spec says
4332 * three's "stub data" here, which I infer means
4333 * that it's protocol-specific and call-specific.
4335 * It should probably get passed the status code
4336 * as well, as that might be protocol-specific.
4340 proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
4341 "Fault stub data (%d byte%s)",
4343 plurality(stub_length, "", "s"));
4348 } else { /* MIDDLE fragment(s) */
4349 if ( (!pinfo->fd->flags.visited) && value->rep_frame ) {
4350 fragment_add_seq_next(&dcerpc_co_reassembly_table,
4352 pinfo, value->rep_frame, NULL,
4363 dissect_dcerpc_cn_rts(tvbuff_t *tvb, gint offset, packet_info *pinfo,
4364 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
4366 proto_item *tf = NULL;
4367 proto_item *parent_pi = NULL;
4368 proto_tree *cn_rts_pdu_tree = NULL;
4370 guint16 commands_nb = 0;
4373 const char *info_str = NULL;
4375 /* Dissect specific RTS header */
4376 rts_flags = dcerpc_tvb_get_ntohs(tvb, offset, hdr->drep);
4378 proto_tree *cn_rts_flags_tree;
4380 tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_rts_flags, tvb, offset, 2, rts_flags);
4381 cn_rts_flags_tree = proto_item_add_subtree(tf, ett_dcerpc_cn_rts_flags);
4382 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_none, tvb, offset, 1, rts_flags);
4383 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_ping, tvb, offset, 1, rts_flags);
4384 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_other_cmd, tvb, offset, 1, rts_flags);
4385 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_recycle_channel, tvb, offset, 1, rts_flags);
4386 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_in_channel, tvb, offset, 1, rts_flags);
4387 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_out_channel, tvb, offset, 1, rts_flags);
4388 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_eof, tvb, offset, 1, rts_flags);
4392 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4393 hf_dcerpc_cn_rts_commands_nb, &commands_nb);
4395 /* Create the RTS PDU tree - we do not yet know its name */
4396 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);
4398 cmd = (guint32 *)wmem_alloc(wmem_packet_scope(), sizeof (guint32) * (commands_nb + 1));
4400 /* Dissect commands */
4401 for (i = 0; i < commands_nb; ++i) {
4402 proto_tree *cn_rts_command_tree = NULL;
4403 const guint32 command = dcerpc_tvb_get_ntohl(tvb, offset, hdr->drep);
4405 tf = proto_tree_add_uint(cn_rts_pdu_tree, hf_dcerpc_cn_rts_command, tvb, offset, 4, command);
4406 cn_rts_command_tree = proto_item_add_subtree(tf, ett_dcerpc_cn_rts_command);
4409 case RTS_CMD_RECEIVEWINDOWSIZE:
4410 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_receivewindowsize, NULL);
4412 case RTS_CMD_FLOWCONTROLACK:
4413 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_fack_bytesreceived, NULL);
4414 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_fack_availablewindow, NULL);
4415 offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_fack_channelcookie, NULL);
4417 case RTS_CMD_CONNECTIONTIMEOUT:
4418 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_connectiontimeout, NULL);
4420 case RTS_CMD_COOKIE:
4421 offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_cookie, NULL);
4423 case RTS_CMD_CHANNELLIFETIME:
4424 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_channellifetime, NULL);
4426 case RTS_CMD_CLIENTKEEPALIVE:
4427 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_clientkeepalive, NULL);
4429 case RTS_CMD_VERSION:
4430 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_version, NULL);
4434 case RTS_CMD_PADDING: {
4436 const guint32 conformance_count = dcerpc_tvb_get_ntohl(tvb, offset, hdr->drep);
4437 proto_tree_add_uint(cn_rts_command_tree, hf_dcerpc_cn_rts_command_conformancecount, tvb, offset, 4, conformance_count);
4439 padding = (guint8 *)tvb_memdup(NULL, tvb, offset, conformance_count);
4440 proto_tree_add_bytes(cn_rts_command_tree, hf_dcerpc_cn_rts_command_padding, tvb, offset, conformance_count, padding);
4441 offset += conformance_count;
4443 case RTS_CMD_NEGATIVEANCE:
4447 case RTS_CMD_CLIENTADDRESS: {
4449 const guint32 addrtype = dcerpc_tvb_get_ntohl(tvb, offset, hdr->drep);
4450 proto_tree_add_uint(cn_rts_command_tree, hf_dcerpc_cn_rts_command_addrtype, tvb, offset, 4, addrtype);
4454 const guint32 addr4 = tvb_get_ipv4(tvb, offset);
4455 proto_tree_add_text(cn_rts_command_tree, tvb, offset, 4, "%s", get_hostname(addr4));
4459 struct e_in6_addr addr6;
4460 tvb_get_ipv6(tvb, offset, &addr6);
4461 proto_tree_add_text(cn_rts_command_tree, tvb, offset, 16, "%s", get_hostname6(&addr6));
4465 padding = (guint8 *)tvb_memdup(NULL, tvb, offset, 12);
4466 proto_tree_add_bytes(cn_rts_command_tree, hf_dcerpc_cn_rts_command_padding, tvb, offset, 12, padding);
4469 case RTS_CMD_ASSOCIATIONGROUPID:
4470 offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_associationgroupid, NULL);
4472 case RTS_CMD_DESTINATION:
4473 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_forwarddestination, NULL);
4475 case RTS_CMD_PINGTRAFFICSENTNOTIFY:
4476 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_pingtrafficsentnotify, NULL);
4479 proto_tree_add_text(cn_rts_command_tree, tvb, offset, 0, "unknown RTS command number");
4484 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RPCH");
4486 /* Define which PDU Body we are dealing with */
4487 info_str = "unknown RTS PDU";
4489 switch (rts_flags) {
4491 switch (commands_nb) {
4493 if (cmd[0] == 0x2) {
4494 info_str = "CONN/A3";
4495 } else if (cmd[0] == 0x3) {
4496 info_str = "IN_R1/A5,IN_R1/A6,IN_R2/A2,IN_R2/A5,OUT_R2/A4";
4497 } else if (cmd[0] == 0x7) {
4498 info_str = "IN_R1/B1";
4499 } else if (cmd[0] == 0x0) {
4500 info_str = "IN_R1/B2";
4501 } else if (cmd[0] == 0xD) {
4502 info_str = "IN_R2/A3,IN_R2/A4";
4503 } else if (cmd[0] == 0xA) {
4504 info_str = "OUT_R1/A9,OUT_R1/A10,OUT_R1/A11,OUT_R2/B1,OUT_R2/B2";
4508 if ((cmd[0] == 0x0) && (cmd[1] == 0x6)) {
4509 info_str = "CONN/B3";
4510 } else if ((cmd[0] == 0xD) && (cmd[1] == 0xA)) {
4511 info_str = "OUT_R2/A5,OUT_R2/A6";
4515 if ((cmd[0] == 0x6) && (cmd[1] == 0x0) && (cmd[2] == 0x2)) {
4516 info_str = "CONN/C1,CONN/C2";
4520 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x0)) {
4521 info_str = "CONN/A1";
4522 } else if ((cmd[0] == 0xD) && (cmd[1] == 0x6) && (cmd[2] == 0x0) && (cmd[3] == 0x2)) {
4523 info_str = "IN_R1/A3,IN_R1/A4";
4527 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x4) && (cmd[4] == 0x5) && (cmd[5] == 0xC)) {
4528 info_str = "CONN/B1";
4536 switch (commands_nb) {
4541 if ((cmd[0] == 0x7) || (cmd[0] == 0x8)) {
4542 info_str = "OUT_R2/C1";
4549 case RTS_FLAG_OTHER_CMD:
4550 switch (commands_nb) {
4552 if (cmd[0] == 0x5) {
4553 info_str = "Keep-Alive";
4554 } else if (cmd[0] == 0xE) {
4555 info_str = "PingTrafficSentNotify";
4556 } else if (cmd[0] == 0x1) {
4557 info_str = "FlowControlAck";
4561 if ((cmd[0] == 0xD) && (cmd[1] == 0x1)) {
4562 info_str = "FlowControlAckWithDestination";
4569 case RTS_FLAG_RECYCLE_CHANNEL:
4570 switch (commands_nb) {
4572 if (cmd[0] == 0xD) {
4573 info_str = "OUT_R1/A1,OUT_R1/A2,OUT_R2/A1,OUT_R2/A2";
4577 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3)) {
4578 info_str = "IN_R1/A1,IN_R2/A1";
4582 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3) && (cmd[4] == 0x0)) {
4583 info_str = "OUT_R1/A3,OUT_R2/A3";
4590 case RTS_FLAG_IN_CHANNEL|RTS_FLAG_RECYCLE_CHANNEL:
4591 switch (commands_nb) {
4593 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3) && (cmd[4] == 0x0) && (cmd[5] == 0x2)) {
4594 info_str = "IN_R1/A2";
4601 case RTS_FLAG_IN_CHANNEL:
4602 switch (commands_nb) {
4604 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x0) && (cmd[4] == 0x2) && (cmd[5] == 0xC) && (cmd[6] == 0xB)) {
4605 info_str = "CONN/B2";
4612 case RTS_FLAG_OUT_CHANNEL|RTS_FLAG_RECYCLE_CHANNEL:
4613 switch (commands_nb) {
4615 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3) && (cmd[4] == 0x4) && (cmd[5] == 0) && (cmd[6] == 0x2)) {
4616 info_str = "OUT_R1/A4";
4623 case RTS_FLAG_OUT_CHANNEL:
4624 switch (commands_nb) {
4626 if ((cmd[0] == 0xD) && (cmd[1] == 0x3)) {
4627 info_str = "OUT_R1/A7,OUT_R1/A8,OUT_R2/A8";
4631 if ((cmd[0] == 0xD) && (cmd[1] == 0x6) && (cmd[2] == 0x2)) {
4632 info_str = "OUT_R1/A5,OUT_R1/A6";
4633 } else if ((cmd[0] == 0xD) && (cmd[1] == 0x3) && (cmd[2] == 0x6)) {
4634 info_str = "OUT_R2/A7";
4638 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x4) && (cmd[4] == 0x0)) {
4639 info_str = "CONN/A2";
4647 switch (commands_nb) {
4649 if (cmd[0] == 0xA) {
4650 info_str = "OUT_R2/B3";
4658 switch (commands_nb) {
4670 col_add_fstr(pinfo->cinfo, COL_INFO, "%s, ", info_str);
4671 col_set_fence(pinfo->cinfo,COL_INFO);
4673 parent_pi = proto_tree_get_parent(dcerpc_tree);
4674 if (parent_pi != NULL) {
4675 proto_item_append_text(parent_pi, ", %s", info_str);
4680 is_dcerpc(tvbuff_t *tvb, int offset, packet_info *pinfo _U_)
4683 guint8 rpc_ver_minor;
4686 if (!tvb_bytes_exist(tvb, offset, sizeof(e_dce_cn_common_hdr_t)))
4687 return FALSE; /* not enough information to check */
4689 rpc_ver = tvb_get_guint8(tvb, offset++);
4692 rpc_ver_minor = tvb_get_guint8(tvb, offset++);
4693 if ((rpc_ver_minor != 0) && (rpc_ver_minor != 1))
4695 ptype = tvb_get_guint8(tvb, offset++);
4696 if (ptype > PDU_RTS)
4703 * DCERPC dissector for connection oriented calls.
4706 dissect_dcerpc_cn(tvbuff_t *tvb, int offset, packet_info *pinfo,
4707 proto_tree *tree, gboolean can_desegment, int *pkt_len)
4709 static const guint8 nulls[4] = { 0 };
4713 proto_item *ti = NULL;
4714 proto_item *tf = NULL;
4715 proto_tree *dcerpc_tree = NULL;
4716 proto_tree *cn_flags_tree = NULL;
4717 proto_tree *drep_tree = NULL;
4718 e_dce_cn_common_hdr_t hdr;
4719 dcerpc_auth_info auth_info;
4720 tvbuff_t *fragment_tvb;
4721 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
4724 * when done over nbt, dcerpc requests are padded with 4 bytes of null
4725 * data for some reason.
4727 * XXX - if that's always the case, the right way to do this would
4728 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
4729 * the 4 bytes of null padding, and make that the dissector
4730 * used for "netbios".
4732 if (tvb_memeql(tvb, offset, nulls, 4) == 0) {
4741 * Check if this looks like a C/O DCERPC call
4743 if (!is_dcerpc(tvb, offset, pinfo))
4746 start_offset = offset;
4747 hdr.rpc_ver = tvb_get_guint8(tvb, offset++);
4748 hdr.rpc_ver_minor = tvb_get_guint8(tvb, offset++);
4749 hdr.ptype = tvb_get_guint8(tvb, offset++);
4751 hdr.flags = tvb_get_guint8(tvb, offset++);
4752 tvb_memcpy(tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
4753 offset += (int)sizeof (hdr.drep);
4755 hdr.frag_len = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
4757 hdr.auth_len = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
4759 hdr.call_id = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
4762 if (decode_data->dcectxid == 0) {
4763 col_append_fstr(pinfo->cinfo, COL_DCE_CALL, "%u", hdr.call_id);
4765 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
4766 * prepend a delimiter */
4767 col_append_fstr(pinfo->cinfo, COL_DCE_CALL, "#%u", hdr.call_id);
4770 if (can_desegment && pinfo->can_desegment
4771 && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
4772 pinfo->desegment_offset = start_offset;
4773 pinfo->desegment_len = hdr.frag_len - tvb_reported_length_remaining(tvb, start_offset);
4774 *pkt_len = 0; /* desegmentation required */
4778 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCERPC");
4780 if (decode_data->dcectxid != 0) {
4781 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
4782 * append a delimiter and set a column fence */
4783 col_append_str(pinfo->cinfo, COL_INFO, " # ");
4784 col_set_fence(pinfo->cinfo,COL_INFO);
4786 col_add_fstr(pinfo->cinfo, COL_INFO, "%s: call_id: %u",
4787 pckt_vals[hdr.ptype].strptr, hdr.call_id);
4789 if (decode_data->dcectxid != 0) {
4790 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU */
4791 expert_add_info(pinfo, NULL, &ei_dcerpc_fragment_multiple);
4794 offset = start_offset;
4795 tvb_ensure_bytes_exist(tvb, offset, 16);
4797 ti = proto_tree_add_item(tree, proto_dcerpc, tvb, offset, hdr.frag_len, ENC_NA);
4798 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
4801 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
4804 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset, 1, hdr.rpc_ver_minor);
4807 tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
4810 #if 0 /* XXX - too much "output noise", removed for now */
4811 if (hdr.ptype == PDU_BIND || hdr.ptype == PDU_ALTER ||
4812 hdr.ptype == PDU_BIND_ACK || hdr.ptype == PDU_ALTER_ACK)
4813 expert_add_info_format(pinfo, tf, &ei_dcerpc_context_change, "Context change: %s", val_to_str(hdr.ptype, pckt_vals, "(0x%x)"));
4815 if (hdr.ptype == PDU_BIND_NAK)
4816 expert_add_info(pinfo, tf, &ei_dcerpc_bind_not_acknowledged);
4819 proto_item_append_text(ti, " %s, Fragment: %s",
4820 val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"),
4821 fragment_type(hdr.flags));
4823 tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
4824 cn_flags_tree = proto_item_add_subtree(tf, ett_dcerpc_cn_flags);
4826 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
4827 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
4828 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
4829 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
4830 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
4831 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
4832 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
4833 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
4836 col_append_fstr(pinfo->cinfo, COL_INFO, ", Fragment: %s", fragment_type(hdr.flags));
4839 tf = proto_tree_add_bytes(dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
4840 drep_tree = proto_item_add_subtree(tf, ett_dcerpc_drep);
4842 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
4843 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
4844 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
4845 offset += (int)sizeof (hdr.drep);
4847 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
4850 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
4853 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
4857 proto_item_append_text(ti, ", FragLen: %u, Call: %u", hdr.frag_len, hdr.call_id);
4861 * None of the stuff done above should throw an exception, because
4862 * we would have rejected this as "not DCE RPC" if we didn't have all
4863 * of it. (XXX - perhaps we should request reassembly if we have
4864 * enough of the header to consider it DCE RPC but not enough to
4865 * get the fragment length; in that case the stuff still wouldn't
4866 * throw an exception.)
4868 * The rest of the stuff might, so return the PDU length to our caller.
4869 * XXX - should we construct a tvbuff containing only the PDU and
4870 * use that? Or should we have separate "is this a DCE RPC PDU",
4871 * "how long is it", and "dissect it" routines - which might let us
4872 * do most of the work in "tcp_dissect_pdus()"?
4874 if (pkt_len != NULL)
4875 *pkt_len = hdr.frag_len + padding;
4877 /* The remaining bytes in the current tvb might contain multiple
4878 * DCE/RPC fragments, so create a new tvb subset for this fragment.
4879 * Only limit the end of the fragment, but not the offset start,
4880 * as the authentication function dissect_dcerpc_cn_auth() will fail
4881 * (and other functions might fail as well) computing the right start
4884 subtvb_len = MIN(hdr.frag_len, tvb_reported_length(tvb));
4885 fragment_tvb = tvb_new_subset(tvb, start_offset,
4886 subtvb_len /* length */,
4887 hdr.frag_len /* reported_length */);
4890 * Packet type specific stuff is next.
4892 switch (hdr.ptype) {
4895 dissect_dcerpc_cn_bind(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
4900 dissect_dcerpc_cn_bind_ack(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
4905 * Nothing after the common header other than credentials.
4907 dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr, TRUE,
4912 dissect_dcerpc_cn_rqst(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, tree, &hdr);
4916 dissect_dcerpc_cn_resp(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, tree, &hdr);
4920 dissect_dcerpc_cn_fault(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
4924 dissect_dcerpc_cn_bind_nak(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
4930 * Nothing after the common header other than an authentication
4933 dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr, FALSE,
4939 * Nothing after the common header, not even an authentication
4944 dissect_dcerpc_cn_rts(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
4948 /* might as well dissect the auth info */
4949 dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr, FALSE,
4957 * DCERPC dissector for connection oriented calls over packet-oriented
4961 dissect_dcerpc_cn_pk(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
4963 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
4966 * Only one PDU per transport packet, and only one transport
4969 decode_data->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
4970 if (!dissect_dcerpc_cn(tvb, 0, pinfo, tree, FALSE, NULL)) {
4972 * It wasn't a DCERPC PDU.
4984 * DCERPC dissector for connection oriented calls over byte-stream
4986 * we need to distinguish here between SMB and non-TCP (more in the future?)
4987 * to be able to know what kind of private_data structure to expect.
4990 dissect_dcerpc_cn_bs_body(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4992 volatile int offset = 0;
4994 volatile int dcerpc_pdus = 0;
4995 volatile gboolean ret = FALSE;
4998 * There may be multiple PDUs per transport packet; keep
5001 while (tvb_reported_length_remaining(tvb, offset) != 0) {
5004 if (dissect_dcerpc_cn(tvb, offset, pinfo, tree,
5005 dcerpc_cn_desegment, &pdu_len)) {
5008 } CATCH_NONFATAL_ERRORS {
5010 * Somebody threw an exception that means that there
5011 * was a problem dissecting the payload; that means
5012 * that a dissector was found, so we don't need to
5013 * dissect the payload as data or update the protocol
5016 * Just show the exception and then continue dissecting
5019 show_exception(tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
5021 * Presumably it looked enough like a DCE RPC PDU that we
5022 * dissected enough of it to throw an exception.
5027 if (dcerpc_pdus == 0) {
5028 gboolean try_desegment = FALSE;
5029 if (dcerpc_cn_desegment && pinfo->can_desegment &&
5030 !tvb_bytes_exist(tvb, offset, sizeof(e_dce_cn_common_hdr_t))) {
5031 /* look for a previous occurrence of the DCE-RPC protocol */
5032 wmem_list_frame_t *cur;
5033 cur = wmem_list_frame_prev(wmem_list_tail(pinfo->layers));
5034 while (cur != NULL) {
5035 if (proto_dcerpc == (gint)GPOINTER_TO_UINT(wmem_list_frame_data(cur))) {
5036 try_desegment = TRUE;
5039 cur = wmem_list_frame_prev(cur);
5043 if (try_desegment) {
5044 /* It didn't look like DCE-RPC but we already had one DCE-RPC
5045 * layer in this packet and what we have is short. Assume that
5046 * it was just too short to tell and ask the TCP layer for more
5048 pinfo->desegment_offset = offset;
5049 pinfo->desegment_len = (guint32)(sizeof(e_dce_cn_common_hdr_t) - tvb_reported_length_remaining(tvb, offset));
5051 /* Really not DCE-RPC */
5057 * Well, we've seen at least one DCERPC PDU.
5061 /* if we had more than one Req/Resp in this PDU change the protocol column */
5062 /* this will formerly contain the last interface name, which may not be the same for all Req/Resp */
5063 if (dcerpc_pdus >= 2)
5064 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "%u*DCERPC", dcerpc_pdus);
5068 * Desegmentation required - bail now, but give the user a hint that desegmentation might be done later.
5070 proto_tree_add_uint_format(tree, hf_dcerpc_cn_deseg_req, tvb, offset,
5072 tvb_reported_length_remaining(tvb, offset),
5073 "[DCE RPC: %u byte%s left, desegmentation might follow]",
5074 tvb_reported_length_remaining(tvb, offset),
5075 plurality(tvb_reported_length_remaining(tvb, offset), "", "s"));
5080 * Step to the next PDU.
5088 dissect_dcerpc_cn_bs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5090 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
5092 decode_data->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
5093 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
5097 get_dcerpc_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset _U_)
5102 tvb_memcpy(tvb, (guint8 *)drep, 4, sizeof(drep));
5103 frag_len = dcerpc_tvb_get_ntohs(tvb, 8, drep);
5109 dissect_dcerpc_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
5112 dissect_dcerpc_cn(tvb, 0, pinfo, tree,
5113 /* Desegment is already handled by TCP, don't confuse it */
5120 dissect_dcerpc_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
5122 dcerpc_decode_as_data* decode_data;
5124 if (!is_dcerpc(tvb, 0, pinfo))
5127 decode_data = dcerpc_get_decode_data(pinfo);
5128 decode_data->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
5130 tcp_dissect_pdus(tvb, pinfo, tree, dcerpc_cn_desegment, 10, get_dcerpc_pdu_len, dissect_dcerpc_pdu, data);
5135 dissect_dcerpc_cn_smbpipe(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5137 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
5139 decode_data->dcetransporttype = DCE_CN_TRANSPORT_SMBPIPE;
5140 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
5144 dissect_dcerpc_cn_smb2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5146 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
5148 decode_data->dcetransporttype = DCE_CN_TRANSPORT_SMBPIPE;
5149 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
5155 dissect_dcerpc_dg_auth(tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
5156 e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
5158 proto_tree *auth_tree = NULL;
5159 guint8 protection_level;
5162 * Initially set "*auth_level_p" to -1 to indicate that we haven't
5163 * yet seen any authentication level information.
5165 if (auth_level_p != NULL)
5169 * The authentication information is at the *end* of the PDU; in
5170 * request and response PDUs, the request and response stub data
5173 * If the full packet is here, and there's data past the end of the
5174 * packet body, then dissect the auth info.
5176 offset += hdr->frag_len;
5177 if (tvb_reported_length_remaining(tvb, offset) > 0) {
5178 switch (hdr->auth_proto) {
5180 case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
5181 auth_tree = proto_tree_add_subtree(dcerpc_tree, tvb, offset, -1, ett_dcerpc_krb5_auth_verf, NULL, "Kerberos authentication verifier");
5182 protection_level = tvb_get_guint8(tvb, offset);
5183 if (auth_level_p != NULL)
5184 *auth_level_p = protection_level;
5185 proto_tree_add_uint(auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
5187 proto_tree_add_item(auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, ENC_BIG_ENDIAN);
5189 if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
5190 offset += 6; /* 6 bytes of padding */
5192 offset += 2; /* 2 bytes of padding */
5193 proto_tree_add_item(auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, ENC_NA);
5198 proto_tree_add_text(dcerpc_tree, tvb, offset, -1, "Authentication verifier");
5205 dissect_dcerpc_dg_cancel_ack(tvbuff_t *tvb, int offset, packet_info *pinfo,
5206 proto_tree *dcerpc_tree,
5207 e_dce_dg_common_hdr_t *hdr)
5211 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5212 hdr->drep, hf_dcerpc_dg_cancel_vers,
5218 /* The only version we know about */
5219 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5220 hdr->drep, hf_dcerpc_dg_cancel_id,
5222 /*offset = */dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
5223 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
5230 dissect_dcerpc_dg_cancel(tvbuff_t *tvb, int offset, packet_info *pinfo,
5231 proto_tree *dcerpc_tree,
5232 e_dce_dg_common_hdr_t *hdr)
5236 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5237 hdr->drep, hf_dcerpc_dg_cancel_vers,
5243 /* The only version we know about */
5244 /*offset = */dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5245 hdr->drep, hf_dcerpc_dg_cancel_id,
5247 /* XXX - are NDR Booleans 32 bits? */
5249 /* XXX - the RPC reference in chapter: "the cancel PDU" doesn't mention
5250 the accepting_cancels field (it's only in the cancel_ack PDU)! */
5251 /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
5252 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
5259 dissect_dcerpc_dg_fack(tvbuff_t *tvb, int offset, packet_info *pinfo,
5260 proto_tree *dcerpc_tree,
5261 e_dce_dg_common_hdr_t *hdr)
5268 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
5269 hdr->drep, hf_dcerpc_dg_fack_vers,
5276 case 0: /* The only version documented in the DCE RPC 1.1 spec */
5277 case 1: /* This appears to be the same */
5278 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
5279 hdr->drep, hf_dcerpc_dg_fack_window_size,
5281 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5282 hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
5284 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5285 hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
5287 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
5288 hdr->drep, hf_dcerpc_dg_fack_serial_num,
5290 col_append_fstr(pinfo->cinfo, COL_INFO, " serial: %u",
5292 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
5293 hdr->drep, hf_dcerpc_dg_fack_selack_len,
5295 for (i = 0; i < selack_len; i++) {
5296 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5297 hdr->drep, hf_dcerpc_dg_fack_selack,
5306 dissect_dcerpc_dg_reject_fault(tvbuff_t *tvb, int offset, packet_info *pinfo,
5307 proto_tree *dcerpc_tree,
5308 e_dce_dg_common_hdr_t *hdr)
5312 /*offset = */dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5313 hdr->drep, hf_dcerpc_dg_status,
5316 col_append_fstr (pinfo->cinfo, COL_INFO,
5318 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
5322 dissect_dcerpc_dg_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
5323 proto_tree *dcerpc_tree, proto_tree *tree,
5324 e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
5326 int length, reported_length, stub_length;
5327 gboolean save_fragmented;
5328 fragment_head *fd_head;
5331 proto_item *parent_pi;
5333 col_append_fstr(pinfo->cinfo, COL_INFO, " opnum: %u len: %u",
5334 di->call_data->opnum, hdr->frag_len );
5336 length = tvb_reported_length_remaining(tvb, offset);
5337 reported_length = tvb_reported_length_remaining(tvb, offset);
5338 stub_length = hdr->frag_len;
5339 if (length > stub_length)
5340 length = stub_length;
5341 if (reported_length > stub_length)
5342 reported_length = stub_length;
5344 save_fragmented = pinfo->fragmented;
5346 /* If we don't have reassembly enabled, or this packet contains
5347 the entire PDU, or if this is a short frame (or a frame
5348 not reassembled at a lower layer) that doesn't include all
5349 the data in the fragment, just call the handoff directly if
5350 this is the first fragment or the PDU isn't fragmented. */
5351 if ( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
5352 !tvb_bytes_exist(tvb, offset, stub_length) ) {
5353 if (hdr->frag_num == 0) {
5356 /* First fragment, possibly the only fragment */
5359 * XXX - authentication info?
5361 pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
5362 next_tvb = tvb_new_subset(tvb, offset, length,
5364 dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb,
5365 next_tvb, hdr->drep, di, NULL);
5367 /* PDU is fragmented and this isn't the first fragment */
5370 proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
5371 "Fragment data (%d byte%s)",
5373 plurality(stub_length, "", "s"));
5378 /* Reassembly is enabled, the PDU is fragmented, and
5379 we have all the data in the fragment; the first two
5380 of those mean we should attempt reassembly, and the
5381 third means we can attempt reassembly. */
5384 proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
5385 "Fragment data (%d byte%s)", stub_length,
5386 plurality(stub_length, "", "s"));
5390 fd_head = fragment_add_seq(&dcerpc_cl_reassembly_table,
5392 pinfo, hdr->seqnum, (void *)hdr,
5393 hdr->frag_num, stub_length,
5394 !(hdr->flags1 & PFCL1_LASTFRAG), 0);
5395 if (fd_head != NULL) {
5396 /* We completed reassembly... */
5397 if (pinfo->fd->num == fd_head->reassembled_in) {
5398 /* ...and this is the reassembled RPC PDU */
5399 next_tvb = tvb_new_chain(tvb, fd_head->tvb_data);
5400 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
5401 show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
5402 tree, pinfo, next_tvb, &pi);
5405 * XXX - authentication info?
5407 pinfo->fragmented = FALSE;
5408 dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb,
5409 next_tvb, hdr->drep, di, NULL);
5411 /* ...and this isn't the reassembled RPC PDU */
5412 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
5413 tvb, 0, 0, fd_head->reassembled_in);
5414 PROTO_ITEM_SET_GENERATED(pi);
5415 parent_pi = proto_tree_get_parent(dcerpc_tree);
5416 if (parent_pi != NULL) {
5417 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
5419 col_append_fstr(pinfo->cinfo, COL_INFO,
5420 " [DCE/RPC fragment, reas: #%u]", fd_head->reassembled_in);
5424 pinfo->fragmented = save_fragmented;
5428 dissect_dcerpc_dg_rqst(tvbuff_t *tvb, int offset, packet_info *pinfo,
5429 proto_tree *dcerpc_tree, proto_tree *tree,
5430 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
5433 dcerpc_call_value *value;
5434 dcerpc_matched_key matched_key, *new_matched_key;
5436 proto_item *parent_pi;
5438 if (!(pinfo->fd->flags.visited)) {
5439 dcerpc_call_value *call_value;
5440 dcerpc_dg_call_key *call_key;
5442 call_key = (dcerpc_dg_call_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_dg_call_key));
5443 call_key->conv = conv;
5444 call_key->seqnum = hdr->seqnum;
5445 call_key->act_id = hdr->act_id;
5447 call_value = (dcerpc_call_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_call_value));
5448 call_value->uuid = hdr->if_id;
5449 call_value->ver = hdr->if_ver;
5450 call_value->object_uuid = hdr->obj_id;
5451 call_value->opnum = hdr->opnum;
5452 call_value->req_frame = pinfo->fd->num;
5453 call_value->req_time = pinfo->fd->abs_ts;
5454 call_value->rep_frame = 0;
5455 call_value->max_ptr = 0;
5456 call_value->se_data = NULL;
5457 call_value->private_data = NULL;
5458 call_value->pol = NULL;
5459 /* NDR64 is not available on dg transports ?*/
5460 call_value->flags = 0;
5462 g_hash_table_insert(dcerpc_dg_calls, call_key, call_value);
5464 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof(dcerpc_matched_key));
5465 new_matched_key->frame = pinfo->fd->num;
5466 new_matched_key->call_id = hdr->seqnum;
5467 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
5470 matched_key.frame = pinfo->fd->num;
5471 matched_key.call_id = hdr->seqnum;
5472 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
5474 value = wmem_new(wmem_packet_scope(), dcerpc_call_value);
5475 value->uuid = hdr->if_id;
5476 value->ver = hdr->if_ver;
5477 value->object_uuid = hdr->obj_id;
5478 value->opnum = hdr->opnum;
5479 value->req_frame = pinfo->fd->num;
5480 value->rep_frame = 0;
5482 value->se_data = NULL;
5483 value->private_data = NULL;
5486 di = wmem_new0(wmem_packet_scope(), dcerpc_info);
5487 di->dcerpc_procedure_name = "";
5489 di->call_id = hdr->seqnum;
5490 di->transport_salt = -1;
5491 di->ptype = PDU_REQ;
5492 di->call_data = value;
5494 if (value->rep_frame != 0) {
5495 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
5496 tvb, 0, 0, value->rep_frame);
5497 PROTO_ITEM_SET_GENERATED(pi);
5498 parent_pi = proto_tree_get_parent(dcerpc_tree);
5499 if (parent_pi != NULL) {
5500 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
5503 dissect_dcerpc_dg_stub(tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
5507 dissect_dcerpc_dg_resp(tvbuff_t *tvb, int offset, packet_info *pinfo,
5508 proto_tree *dcerpc_tree, proto_tree *tree,
5509 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
5512 dcerpc_call_value *value;
5513 dcerpc_matched_key matched_key, *new_matched_key;
5515 proto_item *parent_pi;
5517 if (!(pinfo->fd->flags.visited)) {
5518 dcerpc_call_value *call_value;
5519 dcerpc_dg_call_key call_key;
5521 call_key.conv = conv;
5522 call_key.seqnum = hdr->seqnum;
5523 call_key.act_id = hdr->act_id;
5525 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_dg_calls, &call_key))) {
5526 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
5527 new_matched_key->frame = pinfo->fd->num;
5528 new_matched_key->call_id = hdr->seqnum;
5529 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
5530 if (call_value->rep_frame == 0) {
5531 call_value->rep_frame = pinfo->fd->num;
5536 matched_key.frame = pinfo->fd->num;
5537 matched_key.call_id = hdr->seqnum;
5538 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
5540 value = wmem_new0(wmem_packet_scope(), dcerpc_call_value);
5541 value->uuid = hdr->if_id;
5542 value->ver = hdr->if_ver;
5543 value->object_uuid = hdr->obj_id;
5544 value->opnum = hdr->opnum;
5545 value->rep_frame = pinfo->fd->num;
5548 di = wmem_new0(wmem_packet_scope(), dcerpc_info);
5549 di->dcerpc_procedure_name = "";
5551 di->transport_salt = -1;
5552 di->ptype = PDU_RESP;
5553 di->call_data = value;
5555 if (value->req_frame != 0) {
5557 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
5558 tvb, 0, 0, value->req_frame);
5559 PROTO_ITEM_SET_GENERATED(pi);
5560 parent_pi = proto_tree_get_parent(dcerpc_tree);
5561 if (parent_pi != NULL) {
5562 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
5564 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
5565 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
5566 PROTO_ITEM_SET_GENERATED(pi);
5568 proto_tree_add_expert(dcerpc_tree, pinfo, &ei_dcerpc_no_request_found, tvb, 0, 0);
5570 dissect_dcerpc_dg_stub(tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
5574 dissect_dcerpc_dg_ping_ack(tvbuff_t *tvb, int offset, packet_info *pinfo,
5575 proto_tree *dcerpc_tree,
5576 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
5578 proto_item *parent_pi;
5579 /* if (!(pinfo->fd->flags.visited)) {*/
5580 dcerpc_call_value *call_value;
5581 dcerpc_dg_call_key call_key;
5583 call_key.conv = conv;
5584 call_key.seqnum = hdr->seqnum;
5585 call_key.act_id = hdr->act_id;
5587 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_dg_calls, &call_key))) {
5591 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
5592 tvb, 0, 0, call_value->req_frame);
5593 PROTO_ITEM_SET_GENERATED(pi);
5594 parent_pi = proto_tree_get_parent(dcerpc_tree);
5595 if (parent_pi != NULL) {
5596 proto_item_append_text(parent_pi, ", [Req: #%u]", call_value->req_frame);
5599 col_append_fstr(pinfo->cinfo, COL_INFO, " [req: #%u]", call_value->req_frame);
5601 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &call_value->req_time);
5602 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
5603 PROTO_ITEM_SET_GENERATED(pi);
5609 * DCERPC dissector for connectionless calls
5612 dissect_dcerpc_dg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5614 proto_item *ti = NULL;
5615 proto_item *tf = NULL;
5616 proto_tree *dcerpc_tree = NULL;
5617 proto_tree *dg_flags1_tree = NULL;
5618 proto_tree *dg_flags2_tree = NULL;
5619 proto_tree *drep_tree = NULL;
5620 e_dce_dg_common_hdr_t hdr;
5622 conversation_t *conv;
5625 const char *uuid_name = NULL;
5628 * Check if this looks like a CL DCERPC call. All dg packets
5629 * have an 80 byte header on them. Which starts with
5630 * version (4), pkt_type.
5632 if (tvb_reported_length(tvb) < sizeof (hdr)) {
5636 /* Version must be 4 */
5637 hdr.rpc_ver = tvb_get_guint8(tvb, offset++);
5638 if (hdr.rpc_ver != 4)
5641 /* Type must be <= 19 or it's not DCE/RPC */
5642 hdr.ptype = tvb_get_guint8(tvb, offset++);
5646 /* flags1 has bit 1 and 8 as reserved so if any of them are set, it is
5647 probably not a DCE/RPC packet
5649 hdr.flags1 = tvb_get_guint8(tvb, offset++);
5650 if (hdr.flags1&0x81)
5653 /* flags2 has all bits except bit 2 as reserved so if any of them are set
5654 it is probably not DCE/RPC.
5656 hdr.flags2 = tvb_get_guint8(tvb, offset++);
5657 if (hdr.flags2&0xfd)
5661 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCERPC");
5662 col_add_str(pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
5664 tvb_memcpy(tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
5665 offset += (int)sizeof (hdr.drep);
5666 hdr.serial_hi = tvb_get_guint8(tvb, offset++);
5667 dcerpc_tvb_get_uuid(tvb, offset, hdr.drep, &hdr.obj_id);
5669 dcerpc_tvb_get_uuid(tvb, offset, hdr.drep, &hdr.if_id);
5671 dcerpc_tvb_get_uuid(tvb, offset, hdr.drep, &hdr.act_id);
5673 hdr.server_boot = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
5675 hdr.if_ver = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
5677 hdr.seqnum = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
5679 hdr.opnum = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5681 hdr.ihint = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5683 hdr.ahint = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5685 hdr.frag_len = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5687 hdr.frag_num = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5689 hdr.auth_proto = tvb_get_guint8(tvb, offset++);
5690 hdr.serial_lo = tvb_get_guint8(tvb, offset++);
5693 ti = proto_tree_add_item(tree, proto_dcerpc, tvb, 0, -1, ENC_NA);
5695 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
5696 proto_item_append_text(ti, " %s, Seq: %u, Serial: %u, Frag: %u, FragLen: %u",
5697 val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"),
5698 hdr.seqnum, hdr.serial_hi*256+hdr.serial_lo,
5699 hdr.frag_num, hdr.frag_len);
5705 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
5709 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
5713 tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
5714 dg_flags1_tree = proto_item_add_subtree(tf, ett_dcerpc_dg_flags1);
5715 if (dg_flags1_tree) {
5716 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
5717 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
5718 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
5719 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
5720 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
5721 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
5722 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
5723 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
5725 proto_item_append_text(tf, " %s%s%s%s%s%s",
5726 (hdr.flags1 & PFCL1_BROADCAST) ? "\"Broadcast\" " : "",
5727 (hdr.flags1 & PFCL1_IDEMPOTENT) ? "\"Idempotent\" " : "",
5728 (hdr.flags1 & PFCL1_MAYBE) ? "\"Maybe\" " : "",
5729 (hdr.flags1 & PFCL1_NOFACK) ? "\"No Fack\" " : "",
5730 (hdr.flags1 & PFCL1_FRAG) ? "\"Fragment\" " : "",
5731 (hdr.flags1 & PFCL1_LASTFRAG) ? "\"Last Fragment\" " : "");
5738 tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
5739 dg_flags2_tree = proto_item_add_subtree(tf, ett_dcerpc_dg_flags2);
5740 if (dg_flags2_tree) {
5741 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
5742 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
5743 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
5744 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
5745 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
5746 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
5747 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
5748 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
5750 proto_item_append_text(tf, " %s",
5751 (hdr.flags2 & PFCL2_CANCEL_PENDING) ? "\"Cancel Pending\" " : "");
5758 tf = proto_tree_add_bytes(dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
5759 drep_tree = proto_item_add_subtree(tf, ett_dcerpc_drep);
5761 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
5762 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
5763 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
5764 proto_item_append_text(tf, " (Order: %s, Char: %s, Float: %s)",
5765 val_to_str_const(hdr.drep[0] >> 4, drep_byteorder_vals, "Unknown"),
5766 val_to_str_const(hdr.drep[0] & 0x0f, drep_character_vals, "Unknown"),
5767 val_to_str_const(hdr.drep[1], drep_fp_vals, "Unknown"));
5770 offset += (int)sizeof (hdr.drep);
5773 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
5777 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
5778 offset, 16, (e_guid_t *) &hdr.obj_id, "Object UUID: %s",
5779 guid_to_str(wmem_packet_scope(), (e_guid_t *) &hdr.obj_id));
5784 uuid_str = guid_to_str(wmem_packet_scope(), (e_guid_t*)&hdr.if_id);
5785 uuid_name = guids_get_uuid_name(&hdr.if_id);
5787 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
5788 offset, 16, (e_guid_t *) &hdr.if_id, "Interface: %s UUID: %s", uuid_name, uuid_str);
5790 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
5791 offset, 16, (e_guid_t *) &hdr.if_id, "Interface UUID: %s", uuid_str);
5797 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
5798 offset, 16, (e_guid_t *) &hdr.act_id, "Activity: %s",
5799 guid_to_str(wmem_packet_scope(), (e_guid_t *) &hdr.act_id));
5804 nstime_t server_boot;
5806 server_boot.secs = hdr.server_boot;
5807 server_boot.nsecs = 0;
5809 if (hdr.server_boot == 0)
5810 proto_tree_add_time_format_value(dcerpc_tree, hf_dcerpc_dg_server_boot,
5811 tvb, offset, 4, &server_boot,
5814 proto_tree_add_time(dcerpc_tree, hf_dcerpc_dg_server_boot,
5815 tvb, offset, 4, &server_boot);
5820 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
5824 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
5825 col_append_fstr(pinfo->cinfo, COL_INFO, ": seq: %u", hdr.seqnum);
5826 col_append_fstr(pinfo->cinfo, COL_DCE_CALL, "%u", hdr.seqnum);
5830 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
5834 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
5838 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
5842 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
5846 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
5847 if (hdr.flags1 & PFCL1_FRAG) {
5848 /* Fragmented - put the fragment number into the Info column */
5849 col_append_fstr(pinfo->cinfo, COL_INFO, " frag: %u",
5855 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
5859 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
5860 if (hdr.flags1 & PFCL1_FRAG) {
5861 /* Fragmented - put the serial number into the Info column */
5862 col_append_fstr(pinfo->cinfo, COL_INFO, " serial: %u",
5863 (hdr.serial_hi << 8) | hdr.serial_lo);
5869 * XXX - for Kerberos, we get a protection level; if it's
5870 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
5873 dissect_dcerpc_dg_auth(tvb, offset, dcerpc_tree, &hdr,
5878 * keeping track of the conversation shouldn't really be necessary
5879 * for connectionless packets, because everything we need to know
5880 * to dissect is in the header for each packet. Unfortunately,
5881 * Microsoft's implementation is buggy and often puts the
5882 * completely wrong if_id in the header. go figure. So, keep
5883 * track of the seqnum and use that if possible. Note: that's not
5884 * completely correct. It should really be done based on both the
5885 * activity_id and seqnum. I haven't seen anywhere that it would
5886 * make a difference, but for future reference...
5888 conv = find_or_create_conversation(pinfo);
5891 * Packet type specific stuff is next.
5894 switch (hdr.ptype) {
5896 case PDU_CANCEL_ACK:
5897 /* Body is optional */
5898 /* XXX - we assume "frag_len" is the length of the body */
5899 if (hdr.frag_len != 0)
5900 dissect_dcerpc_dg_cancel_ack(tvb, offset, pinfo, dcerpc_tree, &hdr);
5905 * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
5906 * but in at least one capture none of the Cl_cancel PDUs had a
5909 /* XXX - we assume "frag_len" is the length of the body */
5910 if (hdr.frag_len != 0)
5911 dissect_dcerpc_dg_cancel(tvb, offset, pinfo, dcerpc_tree, &hdr);
5915 /* Body is optional; if present, it's the same as PDU_FACK */
5916 /* XXX - we assume "frag_len" is the length of the body */
5917 if (hdr.frag_len != 0)
5918 dissect_dcerpc_dg_fack(tvb, offset, pinfo, dcerpc_tree, &hdr);
5922 /* Body is optional */
5923 /* XXX - we assume "frag_len" is the length of the body */
5924 if (hdr.frag_len != 0)
5925 dissect_dcerpc_dg_fack(tvb, offset, pinfo, dcerpc_tree, &hdr);
5930 dissect_dcerpc_dg_reject_fault(tvb, offset, pinfo, dcerpc_tree, &hdr);
5934 dissect_dcerpc_dg_rqst(tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
5938 dissect_dcerpc_dg_resp(tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
5941 /* these requests have no body */
5944 dissect_dcerpc_dg_ping_ack(tvb, offset, pinfo, dcerpc_tree, &hdr, conv);
5955 dcerpc_init_protocol(void)
5957 /* structures and data for BIND */
5959 g_hash_table_destroy(dcerpc_binds);
5960 dcerpc_binds = NULL;
5962 if (!dcerpc_binds) {
5963 dcerpc_binds = g_hash_table_new(dcerpc_bind_hash, dcerpc_bind_equal);
5966 /* structures and data for CALL */
5967 if (dcerpc_cn_calls) {
5968 g_hash_table_destroy(dcerpc_cn_calls);
5970 dcerpc_cn_calls = g_hash_table_new(dcerpc_cn_call_hash, dcerpc_cn_call_equal);
5971 if (dcerpc_dg_calls) {
5972 g_hash_table_destroy(dcerpc_dg_calls);
5974 dcerpc_dg_calls = g_hash_table_new(dcerpc_dg_call_hash, dcerpc_dg_call_equal);
5976 /* structure and data for MATCHED */
5977 if (dcerpc_matched) {
5978 g_hash_table_destroy(dcerpc_matched);
5980 dcerpc_matched = g_hash_table_new(dcerpc_matched_hash, dcerpc_matched_equal);
5982 decode_dcerpc_inject_bindings();
5986 proto_register_dcerpc(void)
5988 static hf_register_info hf[] = {
5989 { &hf_dcerpc_request_in,
5990 { "Request in frame", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE,
5991 NULL, 0, "This packet is a response to the packet with this number", HFILL }},
5992 { &hf_dcerpc_response_in,
5993 { "Response in frame", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
5994 NULL, 0, "This packet will be responded in the packet with this number", HFILL }},
5995 { &hf_dcerpc_referent_id32,
5996 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
5997 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
5998 { &hf_dcerpc_referent_id64,
5999 { "Referent ID", "dcerpc.referent_id", FT_UINT64, BASE_HEX,
6000 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
6002 { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6003 { &hf_dcerpc_ver_minor,
6004 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6005 { &hf_dcerpc_packet_type,
6006 { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS(pckt_vals), 0x0, NULL, HFILL }},
6007 { &hf_dcerpc_cn_flags,
6008 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6009 { &hf_dcerpc_cn_flags_first_frag,
6010 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_FIRST_FRAG, NULL, HFILL }},
6011 { &hf_dcerpc_cn_flags_last_frag,
6012 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_LAST_FRAG, NULL, HFILL }},
6013 { &hf_dcerpc_cn_flags_cancel_pending,
6014 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_PENDING_CANCEL, NULL, HFILL }},
6015 { &hf_dcerpc_cn_flags_reserved,
6016 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_RESERVED_1, NULL, HFILL }},
6017 { &hf_dcerpc_cn_flags_mpx,
6018 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_CONC_MPX, NULL, HFILL }},
6019 { &hf_dcerpc_cn_flags_dne,
6020 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_DID_NOT_EXECUTE, NULL, HFILL }},
6021 { &hf_dcerpc_cn_flags_maybe,
6022 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_MAYBE, NULL, HFILL }},
6023 { &hf_dcerpc_cn_flags_object,
6024 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_OBJECT_UUID, NULL, HFILL }},
6026 { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6027 { &hf_dcerpc_drep_byteorder,
6028 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS(drep_byteorder_vals), 0x0, NULL, HFILL }},
6029 { &hf_dcerpc_drep_character,
6030 { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS(drep_character_vals), 0x0, NULL, HFILL }},
6031 { &hf_dcerpc_drep_fp,
6032 { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS(drep_fp_vals), 0x0, NULL, HFILL }},
6033 { &hf_dcerpc_cn_frag_len,
6034 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6035 { &hf_dcerpc_cn_auth_len,
6036 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6037 { &hf_dcerpc_cn_call_id,
6038 { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6039 { &hf_dcerpc_cn_max_xmit,
6040 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6041 { &hf_dcerpc_cn_max_recv,
6042 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6043 { &hf_dcerpc_cn_assoc_group,
6044 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6045 { &hf_dcerpc_cn_num_ctx_items,
6046 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6047 { &hf_dcerpc_cn_ctx_item,
6048 { "Ctx Item", "dcerpc.cn_ctx_item", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6049 { &hf_dcerpc_cn_ctx_id,
6050 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6051 { &hf_dcerpc_cn_num_trans_items,
6052 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6053 { &hf_dcerpc_cn_bind_abstract_syntax,
6054 { "Abstract Syntax", "dcerpc.cn_bind_abstract_syntax", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6055 { &hf_dcerpc_cn_bind_if_id,
6056 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6057 { &hf_dcerpc_cn_bind_if_ver,
6058 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6059 { &hf_dcerpc_cn_bind_if_ver_minor,
6060 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6061 { &hf_dcerpc_cn_bind_trans_syntax,
6062 { "Transfer Syntax", "dcerpc.cn_bind_trans", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6063 { &hf_dcerpc_cn_bind_trans_id,
6064 { "ID", "dcerpc.cn_bind_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6065 { &hf_dcerpc_cn_bind_trans_ver,
6066 { "ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6067 { &hf_dcerpc_cn_bind_trans_btfn_01, /* [MS-RPCE] 2.2.2.14 */
6068 { "Security Context Multiplexing Supported", "dcerpc.cn_bind_trans_btfn.01", FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x01, NULL, HFILL }},
6069 { &hf_dcerpc_cn_bind_trans_btfn_02,
6070 { "Keep Connection On Orphan Supported", "dcerpc.cn_bind_trans_btfn.02", FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x02, NULL, HFILL }},
6071 { &hf_dcerpc_cn_alloc_hint,
6072 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6073 { &hf_dcerpc_cn_sec_addr_len,
6074 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6075 { &hf_dcerpc_cn_sec_addr,
6076 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6077 { &hf_dcerpc_cn_num_results,
6078 { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6079 { &hf_dcerpc_cn_ack_result,
6080 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, NULL, HFILL }},
6081 { &hf_dcerpc_cn_ack_reason,
6082 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, NULL, HFILL }},
6083 { &hf_dcerpc_cn_ack_trans_id,
6084 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6085 { &hf_dcerpc_cn_ack_trans_ver,
6086 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6087 { &hf_dcerpc_cn_ack_btfn,
6088 { "Bind Time Feature Negotiation Bitmask", "dcerpc.cn_ack_btfn", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6089 { &hf_dcerpc_cn_reject_reason,
6090 { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, NULL, HFILL }},
6091 { &hf_dcerpc_cn_num_protocols,
6092 { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6093 { &hf_dcerpc_cn_protocol_ver_major,
6094 { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6095 { &hf_dcerpc_cn_protocol_ver_minor,
6096 { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6097 { &hf_dcerpc_cn_cancel_count,
6098 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6099 { &hf_dcerpc_cn_status,
6100 { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, NULL, HFILL }},
6101 { &hf_dcerpc_cn_deseg_req,
6102 { "Desegmentation Required", "dcerpc.cn_deseg_req", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6103 { &hf_dcerpc_auth_type,
6104 { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS(authn_protocol_vals), 0x0, NULL, HFILL }},
6105 { &hf_dcerpc_auth_level,
6106 { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, NULL, HFILL }},
6107 { &hf_dcerpc_auth_pad_len,
6108 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6109 { &hf_dcerpc_auth_rsrvd,
6110 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6111 { &hf_dcerpc_auth_ctx_id,
6112 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6113 { &hf_dcerpc_dg_flags1,
6114 { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6115 { &hf_dcerpc_dg_flags1_rsrvd_01,
6116 { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_RESERVED_01, NULL, HFILL }},
6117 { &hf_dcerpc_dg_flags1_last_frag,
6118 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_LASTFRAG, NULL, HFILL }},
6119 { &hf_dcerpc_dg_flags1_frag,
6120 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_FRAG, NULL, HFILL }},
6121 { &hf_dcerpc_dg_flags1_nofack,
6122 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_NOFACK, NULL, HFILL }},
6123 { &hf_dcerpc_dg_flags1_maybe,
6124 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_MAYBE, NULL, HFILL }},
6125 { &hf_dcerpc_dg_flags1_idempotent,
6126 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_IDEMPOTENT, NULL, HFILL }},
6127 { &hf_dcerpc_dg_flags1_broadcast,
6128 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_BROADCAST, NULL, HFILL }},
6129 { &hf_dcerpc_dg_flags1_rsrvd_80,
6130 { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_RESERVED_80, NULL, HFILL }},
6131 { &hf_dcerpc_dg_flags2,
6132 { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6133 { &hf_dcerpc_dg_flags2_rsrvd_01,
6134 { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_01, NULL, HFILL }},
6135 { &hf_dcerpc_dg_flags2_cancel_pending,
6136 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_CANCEL_PENDING, NULL, HFILL }},
6137 { &hf_dcerpc_dg_flags2_rsrvd_04,
6138 { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_04, NULL, HFILL }},
6139 { &hf_dcerpc_dg_flags2_rsrvd_08,
6140 { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_08, NULL, HFILL }},
6141 { &hf_dcerpc_dg_flags2_rsrvd_10,
6142 { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_10, NULL, HFILL }},
6143 { &hf_dcerpc_dg_flags2_rsrvd_20,
6144 { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_20, NULL, HFILL }},
6145 { &hf_dcerpc_dg_flags2_rsrvd_40,
6146 { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_40, NULL, HFILL }},
6147 { &hf_dcerpc_dg_flags2_rsrvd_80,
6148 { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_80, NULL, HFILL }},
6149 { &hf_dcerpc_dg_serial_lo,
6150 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6151 { &hf_dcerpc_dg_serial_hi,
6152 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6153 { &hf_dcerpc_dg_ahint,
6154 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6155 { &hf_dcerpc_dg_ihint,
6156 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6157 { &hf_dcerpc_dg_frag_len,
6158 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6159 { &hf_dcerpc_dg_frag_num,
6160 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6161 { &hf_dcerpc_dg_auth_proto,
6162 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS(authn_protocol_vals), 0x0, NULL, HFILL }},
6163 { &hf_dcerpc_dg_seqnum,
6164 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6165 { &hf_dcerpc_dg_server_boot,
6166 { "Server boot time", "dcerpc.dg_server_boot", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0, NULL, HFILL }},
6167 { &hf_dcerpc_dg_if_ver,
6168 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6169 { &hf_dcerpc_krb5_av_prot_level,
6170 { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, NULL, HFILL }},
6171 { &hf_dcerpc_krb5_av_key_vers_num,
6172 { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6173 { &hf_dcerpc_krb5_av_key_auth_verifier,
6174 { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6175 { &hf_dcerpc_obj_id,
6176 { "Object", "dcerpc.obj_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6177 { &hf_dcerpc_dg_if_id,
6178 { "Interface", "dcerpc.dg_if_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6179 { &hf_dcerpc_dg_act_id,
6180 { "Activity", "dcerpc.dg_act_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6182 { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6184 { &hf_dcerpc_dg_cancel_vers,
6185 { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6187 { &hf_dcerpc_dg_cancel_id,
6188 { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6190 { &hf_dcerpc_dg_server_accepting_cancels,
6191 { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6193 { &hf_dcerpc_dg_fack_vers,
6194 { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6196 { &hf_dcerpc_dg_fack_window_size,
6197 { "Window Size", "dcerpc.fack_window_size", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6199 { &hf_dcerpc_dg_fack_max_tsdu,
6200 { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6202 { &hf_dcerpc_dg_fack_max_frag_size,
6203 { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6205 { &hf_dcerpc_dg_fack_serial_num,
6206 { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6208 { &hf_dcerpc_dg_fack_selack_len,
6209 { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6211 { &hf_dcerpc_dg_fack_selack,
6212 { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6214 { &hf_dcerpc_dg_status,
6215 { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, NULL, HFILL }},
6217 { &hf_dcerpc_array_max_count,
6218 { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
6220 { &hf_dcerpc_array_offset,
6221 { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
6223 { &hf_dcerpc_array_actual_count,
6224 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
6227 { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6229 { &hf_dcerpc_fragments,
6230 { "Reassembled DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
6231 NULL, 0x0, "DCE/RPC Fragments", HFILL }},
6233 { &hf_dcerpc_fragment,
6234 { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM, BASE_NONE,
6235 NULL, 0x0, NULL, HFILL }},
6237 { &hf_dcerpc_fragment_overlap,
6238 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE,
6239 NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
6241 { &hf_dcerpc_fragment_overlap_conflict,
6242 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE,
6243 NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
6245 { &hf_dcerpc_fragment_multiple_tails,
6246 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE,
6247 NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
6249 { &hf_dcerpc_fragment_too_long_fragment,
6250 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE,
6251 NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
6253 { &hf_dcerpc_fragment_error,
6254 { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE,
6255 NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
6257 { &hf_dcerpc_fragment_count,
6258 { "Fragment count", "dcerpc.fragment.count", FT_UINT32, BASE_DEC,
6259 NULL, 0x0, NULL, HFILL }},
6262 { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE,
6263 NULL, 0, "Time between Request and Response for DCE-RPC calls", HFILL }},
6265 { &hf_dcerpc_reassembled_in,
6266 { "Reassembled PDU in frame", "dcerpc.reassembled_in", FT_FRAMENUM, BASE_NONE,
6267 NULL, 0x0, "The DCE/RPC PDU is completely reassembled in the packet with this number", HFILL }},
6269 { &hf_dcerpc_reassembled_length,
6270 { "Reassembled DCE/RPC length", "dcerpc.reassembled.length", FT_UINT32, BASE_DEC,
6271 NULL, 0x0, "The total length of the reassembled payload", HFILL }},
6273 { &hf_dcerpc_unknown_if_id,
6274 { "Unknown DCERPC interface id", "dcerpc.unknown_if_id", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6276 { &hf_dcerpc_cn_rts_flags,
6277 { "RTS Flags", "dcerpc.cn_rts_flags", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6278 { &hf_dcerpc_cn_rts_flags_none,
6279 {"None", "dcerpc.cn_rts_flags.none", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_NONE, NULL, HFILL }},
6280 { &hf_dcerpc_cn_rts_flags_ping,
6281 { "Ping", "dcerpc.cn_rts.flags.ping", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_PING, NULL, HFILL }},
6282 { &hf_dcerpc_cn_rts_flags_other_cmd,
6283 { "Other Cmd", "dcerpc.cn_rts_flags.other_cmd", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_OTHER_CMD, NULL, HFILL }},
6284 { &hf_dcerpc_cn_rts_flags_recycle_channel,
6285 { "Recycle Channel", "dcerpc.cn_rts_flags.recycle_channel", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_RECYCLE_CHANNEL, NULL, HFILL }},
6286 { &hf_dcerpc_cn_rts_flags_in_channel,
6287 { "In Channel", "dcerpc.cn_rts_flags.in_channel", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_IN_CHANNEL, NULL, HFILL }},
6288 { &hf_dcerpc_cn_rts_flags_out_channel,
6289 { "Out Channel", "dcerpc.cn_rts_flags.out_channel", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_OUT_CHANNEL, NULL, HFILL }},
6290 { &hf_dcerpc_cn_rts_flags_eof,
6291 { "EOF", "dcerpc.cn_rts_flags.eof", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_EOF, NULL, HFILL }},
6292 { &hf_dcerpc_cn_rts_commands_nb,
6293 { "RTS Number of Commands", "dcerpc.cn_rts_commands_nb", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6294 { &hf_dcerpc_cn_rts_command,
6295 { "RTS Command", "dcerpc.cn_rts_command", FT_UINT32, BASE_HEX, VALS(rts_command_vals), 0x0, NULL, HFILL }},
6296 { &hf_dcerpc_cn_rts_command_receivewindowsize,
6297 {"Receive Window Size", "dcerpc.cn_rts_command.receivewindowsize", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6298 { &hf_dcerpc_cn_rts_command_fack_bytesreceived,
6299 {"Bytes Received", "dcerpc.cn_rts_command.fack.bytesreceived", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6300 { &hf_dcerpc_cn_rts_command_fack_availablewindow,
6301 {"Available Window", "dcerpc.cn_rts_command.fack.availablewindow", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6302 { &hf_dcerpc_cn_rts_command_fack_channelcookie,
6303 {"Channel Cookie", "dcerpc.cn_rts_command.fack.channelcookie", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6304 { &hf_dcerpc_cn_rts_command_connectiontimeout,
6305 {"Connection Timeout", "dcerpc.cn_rts_command.connectiontimeout", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6306 { &hf_dcerpc_cn_rts_command_cookie,
6307 {"Cookie", "dcerpc.cn_rts_command.cookie", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6308 { &hf_dcerpc_cn_rts_command_channellifetime,
6309 {"Channel Lifetime", "dcerpc.cn_rts_command.channellifetime", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6310 { &hf_dcerpc_cn_rts_command_clientkeepalive,
6311 {"Client Keepalive", "dcerpc.cn_rts_command.clientkeepalive", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6312 { &hf_dcerpc_cn_rts_command_version,
6313 {"Version", "dcerpc.cn_rts_command.version", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6314 { &hf_dcerpc_cn_rts_command_conformancecount,
6315 {"Conformance Count", "dcerpc.cn_rts_command.padding.conformancecount", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6316 { &hf_dcerpc_cn_rts_command_padding,
6317 { "Padding", "dcerpc.cn_rts_command.padding.padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
6318 { &hf_dcerpc_cn_rts_command_addrtype,
6319 { "Address Type", "dcerpc.cn_rts_command.addrtype", FT_UINT32, BASE_DEC, VALS(rts_addresstype_vals), 0x0, NULL, HFILL }},
6320 { &hf_dcerpc_cn_rts_command_associationgroupid,
6321 {"Association Group ID", "dcerpc.cn_rts_command.associationgroupid", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6322 { &hf_dcerpc_cn_rts_command_forwarddestination,
6323 {"Forward Destination", "dcerpc.cn_rts_command.forwarddestination", FT_UINT32, BASE_DEC, VALS(rts_forward_destination_vals), 0x0, NULL, HFILL }},
6324 { &hf_dcerpc_cn_rts_command_pingtrafficsentnotify,
6325 {"Ping Traffic Sent Notify", "dcerpc.cn_rts_command.pingtrafficsentnotify", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6327 static gint *ett[] = {
6329 &ett_dcerpc_cn_flags,
6331 &ett_dcerpc_cn_iface,
6332 &ett_dcerpc_cn_trans_syntax,
6333 &ett_dcerpc_cn_trans_btfn,
6334 &ett_dcerpc_cn_rts_flags,
6335 &ett_dcerpc_cn_rts_command,
6336 &ett_dcerpc_cn_rts_pdu,
6338 &ett_dcerpc_dg_flags1,
6339 &ett_dcerpc_dg_flags2,
6340 &ett_dcerpc_pointer_data,
6342 &ett_dcerpc_fragments,
6343 &ett_dcerpc_fragment,
6344 &ett_dcerpc_krb5_auth_verf,
6347 static ei_register_info ei[] = {
6348 { &ei_dcerpc_fragment, { "dcerpc.fragment", PI_REASSEMBLE, PI_CHAT, "%s fragment", EXPFILL }},
6349 { &ei_dcerpc_fragment_reassembled, { "dcerpc.fragment_reassembled", PI_REASSEMBLE, PI_CHAT, "%s fragment, reassembled", EXPFILL }},
6350 { &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 }},
6351 { &ei_dcerpc_no_request_found, { "dcerpc.no_request_found", PI_SEQUENCE, PI_NOTE, "No request to this DCE/RPC call found", EXPFILL }},
6352 { &ei_dcerpc_cn_status, { "dcerpc.cn_status.expert", PI_RESPONSE_CODE, PI_NOTE, "Fault: %s", EXPFILL }},
6353 { &ei_dcerpc_fragment_multiple, { "dcerpc.fragment_multiple", PI_SEQUENCE, PI_CHAT, "Multiple DCE/RPC fragments/PDU's in one packet", EXPFILL }},
6354 { &ei_dcerpc_context_change, { "dcerpc.context_change", PI_SEQUENCE, PI_CHAT, "Context change: %s", EXPFILL }},
6355 { &ei_dcerpc_bind_not_acknowledged, { "dcerpc.bind_not_acknowledged", PI_SEQUENCE, PI_WARN, "Bind not acknowledged", EXPFILL }},
6356 { &ei_dcerpc_verifier_unavailable, { "dcerpc.verifier_unavailable", PI_UNDECODED, PI_WARN, NULL, EXPFILL }},
6357 { &ei_dcerpc_invalid_pdu_authentication_attempt, { "dcerpc.invalid_pdu_authentication_attempt", PI_UNDECODED, PI_WARN, NULL, EXPFILL }},
6360 /* Decode As handling */
6361 static build_valid_func dcerpc_da_build_value[1] = {dcerpc_value};
6362 static decode_as_value_t dcerpc_da_values = {dcerpc_prompt, 1, dcerpc_da_build_value};
6363 static decode_as_t dcerpc_da = {"dcerpc", "DCE-RPC",
6364 /* XXX - DCE/RPC doesn't have a true (sub)dissector table, so
6365 provide a "fake" one to fit the Decode As algorithm */
6367 1, 0, &dcerpc_da_values, NULL, NULL,
6368 dcerpc_populate_list, decode_dcerpc_binding_reset, dcerpc_decode_as_change, dcerpc_decode_as_free};
6370 module_t *dcerpc_module;
6371 expert_module_t* expert_dcerpc;
6373 proto_dcerpc = proto_register_protocol("Distributed Computing Environment / Remote Procedure Call (DCE/RPC)", "DCERPC", "dcerpc");
6374 proto_register_field_array(proto_dcerpc, hf, array_length(hf));
6375 proto_register_subtree_array(ett, array_length(ett));
6376 expert_dcerpc = expert_register_protocol(proto_dcerpc);
6377 expert_register_field_array(expert_dcerpc, ei, array_length(ei));
6379 register_init_routine(dcerpc_init_protocol);
6380 dcerpc_module = prefs_register_protocol(proto_dcerpc, NULL);
6381 prefs_register_bool_preference(dcerpc_module,
6383 "Reassemble DCE/RPC messages spanning multiple TCP segments",
6384 "Whether the DCE/RPC dissector should reassemble messages"
6385 " spanning multiple TCP segments."
6386 " To use this option, you must also enable"
6387 " \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
6388 &dcerpc_cn_desegment);
6389 prefs_register_bool_preference(dcerpc_module,
6390 "reassemble_dcerpc",
6391 "Reassemble DCE/RPC fragments",
6392 "Whether the DCE/RPC dissector should reassemble fragmented DCE/RPC PDUs",
6393 &dcerpc_reassemble);
6394 register_init_routine(dcerpc_reassemble_init);
6395 dcerpc_uuids = g_hash_table_new(dcerpc_uuid_hash, dcerpc_uuid_equal);
6396 dcerpc_tap = register_tap("dcerpc");
6398 register_decode_as(&dcerpc_da);
6402 proto_reg_handoff_dcerpc(void)
6404 heur_dissector_add("tcp", dissect_dcerpc_tcp, proto_dcerpc);
6405 heur_dissector_add("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
6406 heur_dissector_add("udp", dissect_dcerpc_dg, proto_dcerpc);
6407 heur_dissector_add("smb_transact", dissect_dcerpc_cn_smbpipe, proto_dcerpc);
6408 heur_dissector_add("smb2_heur_subdissectors", dissect_dcerpc_cn_smb2, proto_dcerpc);
6409 heur_dissector_add("http", dissect_dcerpc_cn_bs, proto_dcerpc);
6410 dcerpc_smb_init(proto_dcerpc);
6412 guids_add_uuid(&uuid_data_repr_proto, "32bit NDR");
6413 guids_add_uuid(&uuid_ndr64, "64bit NDR");
6414 guids_add_uuid(&uuid_bind_time_feature_nego_00, "bind time feature negotiation");
6415 guids_add_uuid(&uuid_bind_time_feature_nego_01, "bind time feature negotiation");
6416 guids_add_uuid(&uuid_bind_time_feature_nego_02, "bind time feature negotiation");
6417 guids_add_uuid(&uuid_bind_time_feature_nego_03, "bind time feature negotiation");
6418 guids_add_uuid(&uuid_asyncemsmdb, "async MAPI");
6422 * Editor modelines - http://www.wireshark.org/tools/modelines.html
6427 * indent-tabs-mode: nil
6430 * vi: set shiftwidth=4 tabstop=8 expandtab:
6431 * :indentSize=4:tabSize=8:noTabs=true: