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>
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 /* The DCE RPC specification can be found at:
29 * http://www.opengroup.org/dce/
38 #include <epan/packet.h>
39 #include <epan/exceptions.h>
40 #include <epan/conversation.h>
41 #include <epan/prefs.h>
42 #include <epan/reassemble.h>
44 #include <epan/wmem/wmem.h>
45 #include <epan/expert.h>
46 #include <epan/strutil.h>
47 #include <epan/addr_resolv.h>
48 #include <epan/show_exception.h>
49 #include <epan/decode_as.h>
50 #include <epan/dissectors/packet-dcerpc.h>
51 #include <epan/dissectors/packet-dcerpc-nt.h>
53 static int dcerpc_tap = -1;
55 /* 32bit Network Data Representation, see DCE/RPC Appendix I */
56 static e_uuid_t uuid_data_repr_proto = { 0x8a885d04, 0x1ceb, 0x11c9,
57 { 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60 } };
59 /* 64bit Network Data Representation, introduced in Windows Server 2008 */
60 static e_uuid_t uuid_ndr64 = { 0x71710533, 0xbeba, 0x4937,
61 { 0x83, 0x19, 0xb5, 0xdb, 0xef, 0x9c, 0xcc, 0x36 } };
63 /* Bind Time Feature Negotiation, see [MS-RPCE] 3.3.1.5.3 */
64 static e_uuid_t uuid_bind_time_feature_nego_00 = { 0x6cb71c2c, 0x9812, 0x4540, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
65 static e_uuid_t uuid_bind_time_feature_nego_01 = { 0x6cb71c2c, 0x9812, 0x4540, { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
66 static e_uuid_t uuid_bind_time_feature_nego_02 = { 0x6cb71c2c, 0x9812, 0x4540, { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
67 static e_uuid_t uuid_bind_time_feature_nego_03 = { 0x6cb71c2c, 0x9812, 0x4540, { 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
69 /* see [MS-OXRPC] Appendix A: Full IDL, http://msdn.microsoft.com/en-us/library/ee217991%28v=exchg.80%29.aspx */
70 static e_uuid_t uuid_asyncemsmdb = { 0x5261574a, 0x4572, 0x206e,
71 { 0xb2, 0x68, 0x6b, 0x19, 0x92, 0x13, 0xb4, 0xe4 } };
73 static const value_string pckt_vals[] = {
74 { PDU_REQ, "Request"},
76 { PDU_RESP, "Response"},
77 { PDU_FAULT, "Fault"},
78 { PDU_WORKING, "Working"},
79 { PDU_NOCALL, "Nocall"},
80 { PDU_REJECT, "Reject"},
82 { PDU_CL_CANCEL, "Cl_cancel"},
84 { PDU_CANCEL_ACK, "Cancel_ack"},
86 { PDU_BIND_ACK, "Bind_ack"},
87 { PDU_BIND_NAK, "Bind_nak"},
88 { PDU_ALTER, "Alter_context"},
89 { PDU_ALTER_ACK, "Alter_context_resp"},
90 { PDU_AUTH3, "AUTH3"},
91 { PDU_SHUTDOWN, "Shutdown"},
92 { PDU_CO_CANCEL, "Co_cancel"},
93 { PDU_ORPHANED, "Orphaned"},
94 { PDU_RTS, "RPC-over-HTTP RTS"},
98 static const value_string drep_byteorder_vals[] = {
100 { 1, "Little-endian" },
104 static const value_string drep_character_vals[] = {
110 #define DCE_RPC_DREP_FP_IEEE 0
111 #define DCE_RPC_DREP_FP_VAX 1
112 #define DCE_RPC_DREP_FP_CRAY 2
113 #define DCE_RPC_DREP_FP_IBM 3
115 static const value_string drep_fp_vals[] = {
116 { DCE_RPC_DREP_FP_IEEE, "IEEE" },
117 { DCE_RPC_DREP_FP_VAX, "VAX" },
118 { DCE_RPC_DREP_FP_CRAY, "Cray" },
119 { DCE_RPC_DREP_FP_IBM, "IBM" },
124 * Authentication services.
126 static const value_string authn_protocol_vals[] = {
127 { DCE_C_RPC_AUTHN_PROTOCOL_NONE, "None" },
128 { DCE_C_RPC_AUTHN_PROTOCOL_KRB5, "Kerberos 5" },
129 { DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO, "SPNEGO" },
130 { DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP, "NTLMSSP" },
131 { DCE_C_RPC_AUTHN_PROTOCOL_GSS_SCHANNEL, "SCHANNEL SSP" },
132 { DCE_C_RPC_AUTHN_PROTOCOL_GSS_KERBEROS, "Kerberos SSP" },
133 { DCE_C_RPC_AUTHN_PROTOCOL_DPA,
134 "Distributed Password Authentication SSP"},
135 { DCE_C_RPC_AUTHN_PROTOCOL_MSN, "MSN SSP"},
136 { DCE_C_RPC_AUTHN_PROTOCOL_DIGEST, "Digest SSP"},
137 { DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN, "NETLOGON Secure Channel" },
138 { DCE_C_RPC_AUTHN_PROTOCOL_MQ, "MSMQ SSP"},
145 static const value_string authn_level_vals[] = {
146 { DCE_C_AUTHN_LEVEL_NONE, "None" },
147 { DCE_C_AUTHN_LEVEL_CONNECT, "Connect" },
148 { DCE_C_AUTHN_LEVEL_CALL, "Call" },
149 { DCE_C_AUTHN_LEVEL_PKT, "Packet" },
150 { DCE_C_AUTHN_LEVEL_PKT_INTEGRITY, "Packet integrity" },
151 { DCE_C_AUTHN_LEVEL_PKT_PRIVACY, "Packet privacy" },
156 * Flag bits in first flag field in connectionless PDU header.
158 #define PFCL1_RESERVED_01 0x01 /* Reserved for use by implementations */
159 #define PFCL1_LASTFRAG 0x02 /* If set, the PDU is the last
160 * fragment of a multi-PDU
162 #define PFCL1_FRAG 0x04 /* If set, the PDU is a fragment of
163 a multi-PDU transmission */
164 #define PFCL1_NOFACK 0x08 /* If set, the receiver is not
165 * requested to send a `fack' PDU
166 * for the fragment */
167 #define PFCL1_MAYBE 0x10 /* If set, the PDU is for a `maybe'
169 #define PFCL1_IDEMPOTENT 0x20 /* If set, the PDU is for an idempotent
171 #define PFCL1_BROADCAST 0x40 /* If set, the PDU is for a broadcast
173 #define PFCL1_RESERVED_80 0x80 /* Reserved for use by implementations */
176 * Flag bits in second flag field in connectionless PDU header.
178 #define PFCL2_RESERVED_01 0x01 /* Reserved for use by implementations */
179 #define PFCL2_CANCEL_PENDING 0x02 /* Cancel pending at the call end */
180 #define PFCL2_RESERVED_04 0x04 /* Reserved for future use */
181 #define PFCL2_RESERVED_08 0x08 /* Reserved for future use */
182 #define PFCL2_RESERVED_10 0x10 /* Reserved for future use */
183 #define PFCL2_RESERVED_20 0x20 /* Reserved for future use */
184 #define PFCL2_RESERVED_40 0x40 /* Reserved for future use */
185 #define PFCL2_RESERVED_80 0x80 /* Reserved for future use */
188 * Flag bits in connection-oriented PDU header.
190 #define PFC_FIRST_FRAG 0x01 /* First fragment */
191 #define PFC_LAST_FRAG 0x02 /* Last fragment */
192 #define PFC_PENDING_CANCEL 0x04 /* Cancel was pending at sender */
193 #define PFC_RESERVED_1 0x08
194 #define PFC_CONC_MPX 0x10 /* supports concurrent multiplexing
195 * of a single connection. */
196 #define PFC_DID_NOT_EXECUTE 0x20 /* only meaningful on `fault' packet;
197 * if true, guaranteed call did not
199 #define PFC_MAYBE 0x40 /* `maybe' call semantics requested */
200 #define PFC_OBJECT_UUID 0x80 /* if true, a non-nil object UUID
201 * was specified in the handle, and
202 * is present in the optional object
203 * field. If false, the object field
207 * Tests whether a connection-oriented PDU is fragmented; returns TRUE if
208 * it's not fragmented (i.e., this is both the first *and* last fragment),
209 * and FALSE otherwise.
211 #define PFC_NOT_FRAGMENTED(hdr) \
212 ((hdr->flags&(PFC_FIRST_FRAG|PFC_LAST_FRAG)) == (PFC_FIRST_FRAG|PFC_LAST_FRAG))
215 * Presentation context negotiation result.
217 static const value_string p_cont_result_vals[] = {
219 { 1, "User rejection" },
220 { 2, "Provider rejection" },
221 { 3, "Negotiate ACK" }, /* [MS-RPCE] 2.2.2.4 */
226 * Presentation context negotiation rejection reasons.
228 static const value_string p_provider_reason_vals[] = {
229 { 0, "Reason not specified" },
230 { 1, "Abstract syntax not supported" },
231 { 2, "Proposed transfer syntaxes not supported" },
232 { 3, "Local limit exceeded" },
239 #define REASON_NOT_SPECIFIED 0
240 #define TEMPORARY_CONGESTION 1
241 #define LOCAL_LIMIT_EXCEEDED 2
242 #define CALLED_PADDR_UNKNOWN 3 /* not used */
243 #define PROTOCOL_VERSION_NOT_SUPPORTED 4
244 #define DEFAULT_CONTEXT_NOT_SUPPORTED 5 /* not used */
245 #define USER_DATA_NOT_READABLE 6 /* not used */
246 #define NO_PSAP_AVAILABLE 7 /* not used */
247 #define AUTH_TYPE_NOT_RECOGNIZED 8 /* [MS-RPCE] 2.2.2.5 */
248 #define INVALID_CHECKSUM 9 /* [MS-RPCE] 2.2.2.5 */
250 static const value_string reject_reason_vals[] = {
251 { REASON_NOT_SPECIFIED, "Reason not specified" },
252 { TEMPORARY_CONGESTION, "Temporary congestion" },
253 { LOCAL_LIMIT_EXCEEDED, "Local limit exceeded" },
254 { CALLED_PADDR_UNKNOWN, "Called paddr unknown" },
255 { PROTOCOL_VERSION_NOT_SUPPORTED, "Protocol version not supported" },
256 { DEFAULT_CONTEXT_NOT_SUPPORTED, "Default context not supported" },
257 { USER_DATA_NOT_READABLE, "User data not readable" },
258 { NO_PSAP_AVAILABLE, "No PSAP available" },
259 { AUTH_TYPE_NOT_RECOGNIZED, "Authentication type not recognized" },
260 { INVALID_CHECKSUM, "Invalid checksum" },
265 * Reject status codes.
267 static const value_string reject_status_vals[] = {
268 { 0, "Stub-defined exception" },
269 { 0x00000001, "nca_s_fault_other" },
270 { 0x00000005, "nca_s_fault_access_denied" },
271 { 0x000006f7, "nca_s_fault_ndr" },
272 { 0x000006d8, "nca_s_fault_cant_perform" },
273 { 0x1c000001, "nca_s_fault_int_div_by_zero" },
274 { 0x1c000002, "nca_s_fault_addr_error" },
275 { 0x1c000003, "nca_s_fault_fp_div_zero" },
276 { 0x1c000004, "nca_s_fault_fp_underflow" },
277 { 0x1c000005, "nca_s_fault_fp_overflow" },
278 { 0x1c000006, "nca_s_fault_invalid_tag" },
279 { 0x1c000007, "nca_s_fault_invalid_bound" },
280 { 0x1c000008, "nca_rpc_version_mismatch" },
281 { 0x1c000009, "nca_unspec_reject" },
282 { 0x1c00000a, "nca_s_bad_actid" },
283 { 0x1c00000b, "nca_who_are_you_failed" },
284 { 0x1c00000c, "nca_manager_not_entered" },
285 { 0x1c00000d, "nca_s_fault_cancel" },
286 { 0x1c00000e, "nca_s_fault_ill_inst" },
287 { 0x1c00000f, "nca_s_fault_fp_error" },
288 { 0x1c000010, "nca_s_fault_int_overflow" },
289 { 0x1c000014, "nca_s_fault_pipe_empty" },
290 { 0x1c000015, "nca_s_fault_pipe_closed" },
291 { 0x1c000016, "nca_s_fault_pipe_order" },
292 { 0x1c000017, "nca_s_fault_pipe_discipline" },
293 { 0x1c000018, "nca_s_fault_pipe_comm_error" },
294 { 0x1c000019, "nca_s_fault_pipe_memory" },
295 { 0x1c00001a, "nca_s_fault_context_mismatch" },
296 { 0x1c00001b, "nca_s_fault_remote_no_memory" },
297 { 0x1c00001c, "nca_invalid_pres_context_id" },
298 { 0x1c00001d, "nca_unsupported_authn_level" },
299 { 0x1c00001f, "nca_invalid_checksum" },
300 { 0x1c000020, "nca_invalid_crc" },
301 { 0x1c000021, "ncs_s_fault_user_defined" },
302 { 0x1c000022, "nca_s_fault_tx_open_failed" },
303 { 0x1c000023, "nca_s_fault_codeset_conv_error" },
304 { 0x1c000024, "nca_s_fault_object_not_found" },
305 { 0x1c000025, "nca_s_fault_no_client_stub" },
306 { 0x1c010002, "nca_op_rng_error" },
307 { 0x1c010003, "nca_unk_if"},
308 { 0x1c010006, "nca_wrong_boot_time" },
309 { 0x1c010009, "nca_s_you_crashed" },
310 { 0x1c01000b, "nca_proto_error" },
311 { 0x1c010013, "nca_out_args_too_big" },
312 { 0x1c010014, "nca_server_too_busy" },
313 { 0x1c010017, "nca_unsupported_type" },
314 /* MS Windows specific values
315 * see: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/system_error_codes__1700-3999_.asp
316 * and: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/seccrypto/security/common_hresult_values.asp
317 * and: http://www.megos.ch/support/doserrors.txt
319 * XXX - we might need a way to dynamically add entries here, as higher layer protocols use these values too,
320 * at least MS protocols (like DCOM) do it that way ... */
321 { 0x80004001, "E_NOTIMPL" },
322 { 0x80004003, "E_POINTER" },
323 { 0x80004004, "E_ABORT" },
324 { 0x8000FFFF, "E_UNEXPECTED" },
325 { 0x80010105, "RPC_E_SERVERFAULT" },
326 { 0x80010108, "RPC_E_DISCONNECTED" },
327 { 0x80010113, "RPC_E_INVALID_IPID" },
328 { 0x8001011F, "RPC_E_TIMEOUT" },
329 { 0x80020003, "DISP_E_MEMBERNOTFOUND" },
330 { 0x80020006, "DISP_E_UNKNOWNNAME" },
331 { 0x8002000E, "DISP_E_BADPARAMCOUNT" },
332 { 0x8004CB00, "CBA_E_MALFORMED" },
333 { 0x8004CB01, "CBA_E_UNKNOWNOBJECT" },
334 { 0x8004CB05, "CBA_E_INVALIDID" },
335 { 0x8004CB09, "CBA_E_INVALIDCOOKIE" },
336 { 0x8004CB0B, "CBA_E_QOSTYPEUNSUPPORTED" },
337 { 0x8004CB0C, "CBA_E_QOSVALUEUNSUPPORTED" },
338 { 0x8004CB0F, "CBA_E_NOTAPPLICABLE" },
339 { 0x8004CB12, "CBA_E_LIMITVIOLATION" },
340 { 0x8004CB13, "CBA_E_QOSTYPENOTAPPLICABLE" },
341 { 0x8004CB18, "CBA_E_OUTOFPARTNERACCOS" },
342 { 0x8004CB1C, "CBA_E_FLAGUNSUPPORTED" },
343 { 0x8004CB23, "CBA_E_FRAMECOUNTUNSUPPORTED" },
344 { 0x8004CB25, "CBA_E_MODECHANGE" },
345 { 0x8007000E, "E_OUTOFMEMORY" },
346 { 0x80070057, "E_INVALIDARG" },
347 { 0x800706d1, "RPC_S_PROCNUM_OUT_OF_RANGE" },
348 { 0x80070776, "OR_INVALID_OXID" },
356 #define RTS_FLAG_NONE 0x0000
357 #define RTS_FLAG_PING 0x0001
358 #define RTS_FLAG_OTHER_CMD 0x0002
359 #define RTS_FLAG_RECYCLE_CHANNEL 0x0004
360 #define RTS_FLAG_IN_CHANNEL 0x0008
361 #define RTS_FLAG_OUT_CHANNEL 0x0010
362 #define RTS_FLAG_EOF 0x0020
363 #define RTS_FLAG_ECHO 0x0040
369 #define RTS_CMD_RECEIVEWINDOWSIZE 0x0
370 #define RTS_CMD_FLOWCONTROLACK 0x1
371 #define RTS_CMD_CONNECTIONTIMEOUT 0x2
372 #define RTS_CMD_COOKIE 0x3
373 #define RTS_CMD_CHANNELLIFETIME 0x4
374 #define RTS_CMD_CLIENTKEEPALIVE 0x5
375 #define RTS_CMD_VERSION 0x6
376 #define RTS_CMD_EMPTY 0x7
377 #define RTS_CMD_PADDING 0x8
378 #define RTS_CMD_NEGATIVEANCE 0x9
379 #define RTS_CMD_ANCE 0xA
380 #define RTS_CMD_CLIENTADDRESS 0xB
381 #define RTS_CMD_ASSOCIATIONGROUPID 0xC
382 #define RTS_CMD_DESTINATION 0xD
383 #define RTS_CMD_PINGTRAFFICSENTNOTIFY 0xE
385 static const value_string rts_command_vals[] = {
386 { RTS_CMD_RECEIVEWINDOWSIZE, "ReceiveWindowSize" },
387 { RTS_CMD_FLOWCONTROLACK, "FlowControlAck" },
388 { RTS_CMD_CONNECTIONTIMEOUT, "ConnectionTimeOut" },
389 { RTS_CMD_COOKIE, "Cookie" },
390 { RTS_CMD_CHANNELLIFETIME, "ChannelLifetime" },
391 { RTS_CMD_CLIENTKEEPALIVE, "ClientKeepalive" },
392 { RTS_CMD_VERSION, "Version" },
393 { RTS_CMD_EMPTY, "Empty" },
394 { RTS_CMD_PADDING, "Padding" },
395 { RTS_CMD_NEGATIVEANCE, "NegativeANCE" },
396 { RTS_CMD_ANCE, "ANCE" },
397 { RTS_CMD_CLIENTADDRESS, "ClientAddress" },
398 { RTS_CMD_ASSOCIATIONGROUPID, "AssociationGroupId" },
399 { RTS_CMD_DESTINATION, "Destination" },
400 { RTS_CMD_PINGTRAFFICSENTNOTIFY, "PingTrafficSentNotify" },
405 * RTS client address type
410 static const value_string rts_addresstype_vals[] = {
411 { RTS_IPV4, "IPV4" },
412 { RTS_IPV6, "IPV6" },
417 * RTS Forward destination
420 static const value_string rts_forward_destination_vals[] = {
422 { 0x1, "FDInProxy" },
424 { 0x3, "FDOutProxy" },
428 /* we need to keep track of what transport were used, ie what handle we came
429 * in through so we know what kind of pinfo->dce_smb_fid was passed to us.
431 /* Value of -1 is reserved for "not DCE packet" in packet_info.dcetransporttype. */
432 #define DCE_TRANSPORT_UNKNOWN 0
433 #define DCE_CN_TRANSPORT_SMBPIPE 1
436 static int proto_dcerpc = -1;
439 static int hf_dcerpc_request_in = -1;
440 static int hf_dcerpc_time = -1;
441 static int hf_dcerpc_response_in = -1;
442 static int hf_dcerpc_ver = -1;
443 static int hf_dcerpc_ver_minor = -1;
444 static int hf_dcerpc_packet_type = -1;
445 static int hf_dcerpc_cn_flags = -1;
446 static int hf_dcerpc_cn_flags_first_frag = -1;
447 static int hf_dcerpc_cn_flags_last_frag = -1;
448 static int hf_dcerpc_cn_flags_cancel_pending = -1;
449 static int hf_dcerpc_cn_flags_reserved = -1;
450 static int hf_dcerpc_cn_flags_mpx = -1;
451 static int hf_dcerpc_cn_flags_dne = -1;
452 static int hf_dcerpc_cn_flags_maybe = -1;
453 static int hf_dcerpc_cn_flags_object = -1;
454 static int hf_dcerpc_drep = -1;
455 int hf_dcerpc_drep_byteorder = -1;
456 static int hf_dcerpc_drep_character = -1;
457 static int hf_dcerpc_drep_fp = -1;
458 static int hf_dcerpc_cn_frag_len = -1;
459 static int hf_dcerpc_cn_auth_len = -1;
460 static int hf_dcerpc_cn_call_id = -1;
461 static int hf_dcerpc_cn_max_xmit = -1;
462 static int hf_dcerpc_cn_max_recv = -1;
463 static int hf_dcerpc_cn_assoc_group = -1;
464 static int hf_dcerpc_cn_num_ctx_items = -1;
465 static int hf_dcerpc_cn_ctx_item = -1;
466 static int hf_dcerpc_cn_ctx_id = -1;
467 static int hf_dcerpc_cn_num_trans_items = -1;
468 static int hf_dcerpc_cn_bind_abstract_syntax = -1;
469 static int hf_dcerpc_cn_bind_if_id = -1;
470 static int hf_dcerpc_cn_bind_if_ver = -1;
471 static int hf_dcerpc_cn_bind_if_ver_minor = -1;
472 static int hf_dcerpc_cn_bind_trans_syntax = -1;
473 static int hf_dcerpc_cn_bind_trans_id = -1;
474 static int hf_dcerpc_cn_bind_trans_ver = -1;
475 static int hf_dcerpc_cn_bind_trans_btfn_01 = -1;
476 static int hf_dcerpc_cn_bind_trans_btfn_02 = -1;
477 static int hf_dcerpc_cn_alloc_hint = -1;
478 static int hf_dcerpc_cn_sec_addr_len = -1;
479 static int hf_dcerpc_cn_sec_addr = -1;
480 static int hf_dcerpc_cn_num_results = -1;
481 static int hf_dcerpc_cn_ack_result = -1;
482 static int hf_dcerpc_cn_ack_reason = -1;
483 static int hf_dcerpc_cn_ack_trans_id = -1;
484 static int hf_dcerpc_cn_ack_trans_ver = -1;
485 static int hf_dcerpc_cn_ack_btfn = -1;
486 static int hf_dcerpc_cn_reject_reason = -1;
487 static int hf_dcerpc_cn_num_protocols = -1;
488 static int hf_dcerpc_cn_protocol_ver_major = -1;
489 static int hf_dcerpc_cn_protocol_ver_minor = -1;
490 static int hf_dcerpc_cn_cancel_count = -1;
491 static int hf_dcerpc_cn_status = -1;
492 static int hf_dcerpc_cn_deseg_req = -1;
493 static int hf_dcerpc_cn_rts_flags = -1;
494 static int hf_dcerpc_cn_rts_flags_none = -1;
495 static int hf_dcerpc_cn_rts_flags_ping = -1;
496 static int hf_dcerpc_cn_rts_flags_other_cmd = -1;
497 static int hf_dcerpc_cn_rts_flags_recycle_channel = -1;
498 static int hf_dcerpc_cn_rts_flags_in_channel = -1;
499 static int hf_dcerpc_cn_rts_flags_out_channel = -1;
500 static int hf_dcerpc_cn_rts_flags_eof = -1;
501 static int hf_dcerpc_cn_rts_commands_nb = -1;
502 static int hf_dcerpc_cn_rts_command = -1;
503 static int hf_dcerpc_cn_rts_command_receivewindowsize = -1;
504 static int hf_dcerpc_cn_rts_command_fack_bytesreceived = -1;
505 static int hf_dcerpc_cn_rts_command_fack_availablewindow = -1;
506 static int hf_dcerpc_cn_rts_command_fack_channelcookie = -1;
507 static int hf_dcerpc_cn_rts_command_connectiontimeout = -1;
508 static int hf_dcerpc_cn_rts_command_cookie = -1;
509 static int hf_dcerpc_cn_rts_command_channellifetime = -1;
510 static int hf_dcerpc_cn_rts_command_clientkeepalive = -1;
511 static int hf_dcerpc_cn_rts_command_version = -1;
512 static int hf_dcerpc_cn_rts_command_conformancecount = -1;
513 static int hf_dcerpc_cn_rts_command_padding = -1;
514 static int hf_dcerpc_cn_rts_command_addrtype = -1;
515 static int hf_dcerpc_cn_rts_command_associationgroupid = -1;
516 static int hf_dcerpc_cn_rts_command_forwarddestination = -1;
517 static int hf_dcerpc_cn_rts_command_pingtrafficsentnotify = -1;
518 static int hf_dcerpc_auth_type = -1;
519 static int hf_dcerpc_auth_level = -1;
520 static int hf_dcerpc_auth_pad_len = -1;
521 static int hf_dcerpc_auth_rsrvd = -1;
522 static int hf_dcerpc_auth_ctx_id = -1;
523 static int hf_dcerpc_dg_flags1 = -1;
524 static int hf_dcerpc_dg_flags1_rsrvd_01 = -1;
525 static int hf_dcerpc_dg_flags1_last_frag = -1;
526 static int hf_dcerpc_dg_flags1_frag = -1;
527 static int hf_dcerpc_dg_flags1_nofack = -1;
528 static int hf_dcerpc_dg_flags1_maybe = -1;
529 static int hf_dcerpc_dg_flags1_idempotent = -1;
530 static int hf_dcerpc_dg_flags1_broadcast = -1;
531 static int hf_dcerpc_dg_flags1_rsrvd_80 = -1;
532 static int hf_dcerpc_dg_flags2 = -1;
533 static int hf_dcerpc_dg_flags2_rsrvd_01 = -1;
534 static int hf_dcerpc_dg_flags2_cancel_pending = -1;
535 static int hf_dcerpc_dg_flags2_rsrvd_04 = -1;
536 static int hf_dcerpc_dg_flags2_rsrvd_08 = -1;
537 static int hf_dcerpc_dg_flags2_rsrvd_10 = -1;
538 static int hf_dcerpc_dg_flags2_rsrvd_20 = -1;
539 static int hf_dcerpc_dg_flags2_rsrvd_40 = -1;
540 static int hf_dcerpc_dg_flags2_rsrvd_80 = -1;
541 static int hf_dcerpc_dg_serial_hi = -1;
542 static int hf_dcerpc_obj_id = -1;
543 static int hf_dcerpc_dg_if_id = -1;
544 static int hf_dcerpc_dg_act_id = -1;
545 static int hf_dcerpc_dg_serial_lo = -1;
546 static int hf_dcerpc_dg_ahint = -1;
547 static int hf_dcerpc_dg_ihint = -1;
548 static int hf_dcerpc_dg_frag_len = -1;
549 static int hf_dcerpc_dg_frag_num = -1;
550 static int hf_dcerpc_dg_auth_proto = -1;
551 static int hf_dcerpc_opnum = -1;
552 static int hf_dcerpc_dg_seqnum = -1;
553 static int hf_dcerpc_dg_server_boot = -1;
554 static int hf_dcerpc_dg_if_ver = -1;
555 static int hf_dcerpc_krb5_av_prot_level = -1;
556 static int hf_dcerpc_krb5_av_key_vers_num = -1;
557 static int hf_dcerpc_krb5_av_key_auth_verifier = -1;
558 static int hf_dcerpc_dg_cancel_vers = -1;
559 static int hf_dcerpc_dg_cancel_id = -1;
560 static int hf_dcerpc_dg_server_accepting_cancels = -1;
561 static int hf_dcerpc_dg_fack_vers = -1;
562 static int hf_dcerpc_dg_fack_window_size = -1;
563 static int hf_dcerpc_dg_fack_max_tsdu = -1;
564 static int hf_dcerpc_dg_fack_max_frag_size = -1;
565 static int hf_dcerpc_dg_fack_serial_num = -1;
566 static int hf_dcerpc_dg_fack_selack_len = -1;
567 static int hf_dcerpc_dg_fack_selack = -1;
568 static int hf_dcerpc_dg_status = -1;
569 static int hf_dcerpc_array_max_count = -1;
570 static int hf_dcerpc_array_offset = -1;
571 static int hf_dcerpc_array_actual_count = -1;
572 static int hf_dcerpc_array_buffer = -1;
573 static int hf_dcerpc_op = -1;
574 static int hf_dcerpc_referent_id = -1;
575 static int hf_dcerpc_fragments = -1;
576 static int hf_dcerpc_fragment = -1;
577 static int hf_dcerpc_fragment_overlap = -1;
578 static int hf_dcerpc_fragment_overlap_conflict = -1;
579 static int hf_dcerpc_fragment_multiple_tails = -1;
580 static int hf_dcerpc_fragment_too_long_fragment = -1;
581 static int hf_dcerpc_fragment_error = -1;
582 static int hf_dcerpc_fragment_count = -1;
583 static int hf_dcerpc_reassembled_in = -1;
584 static int hf_dcerpc_reassembled_length = -1;
585 static int hf_dcerpc_unknown_if_id = -1;
587 static gint ett_dcerpc = -1;
588 static gint ett_dcerpc_cn_flags = -1;
589 static gint ett_dcerpc_cn_ctx = -1;
590 static gint ett_dcerpc_cn_iface = -1;
591 static gint ett_dcerpc_cn_trans_syntax = -1;
592 static gint ett_dcerpc_cn_trans_btfn = -1;
593 static gint ett_dcerpc_cn_rts_flags = -1;
594 static gint ett_dcerpc_cn_rts_command = -1;
595 static gint ett_dcerpc_cn_rts_pdu = -1;
596 static gint ett_dcerpc_drep = -1;
597 static gint ett_dcerpc_dg_flags1 = -1;
598 static gint ett_dcerpc_dg_flags2 = -1;
599 static gint ett_dcerpc_pointer_data = -1;
600 static gint ett_dcerpc_string = -1;
601 static gint ett_dcerpc_fragments = -1;
602 static gint ett_dcerpc_fragment = -1;
603 static gint ett_dcerpc_krb5_auth_verf = -1;
605 static expert_field ei_dcerpc_fragment_multiple = EI_INIT;
606 static expert_field ei_dcerpc_cn_status = EI_INIT;
607 static expert_field ei_dcerpc_fragment_reassembled = EI_INIT;
608 static expert_field ei_dcerpc_fragment = EI_INIT;
609 static expert_field ei_dcerpc_no_request_found = EI_INIT;
610 static expert_field ei_dcerpc_context_change = EI_INIT;
611 static expert_field ei_dcerpc_cn_ctx_id_no_bind = EI_INIT;
612 static expert_field ei_dcerpc_bind_not_acknowledged = EI_INIT;
615 static GSList *decode_dcerpc_bindings = NULL;
617 * To keep track of ctx_id mappings.
619 * Every time we see a bind call we update this table.
620 * Note that we always specify a SMB FID. For non-SMB transports this
623 static GHashTable *dcerpc_binds = NULL;
625 typedef struct _dcerpc_bind_key {
626 conversation_t *conv;
631 typedef struct _dcerpc_bind_value {
637 /* Extra data for DCERPC handling and tracking of context ids */
638 typedef struct _dcerpc_decode_as_data {
639 guint16 dcectxid; /**< Context ID (DCERPC-specific) */
640 int dcetransporttype; /**< Transport type
641 * Value -1 means "not a DCERPC packet"
643 guint16 dcetransportsalt; /**< fid: if transporttype==DCE_CN_TRANSPORT_SMBPIPE */
644 } dcerpc_decode_as_data;
646 static dcerpc_decode_as_data*
647 dcerpc_get_decode_data(packet_info* pinfo)
649 dcerpc_decode_as_data* data = (dcerpc_decode_as_data*)p_get_proto_data(pinfo->pool, pinfo, proto_dcerpc, 0);
652 data = wmem_new0(pinfo->pool, dcerpc_decode_as_data);
653 data->dcetransporttype = -1;
654 p_add_proto_data(pinfo->pool, pinfo, proto_dcerpc, 0, data);
661 * Registers a conversation/UUID binding association, so that
662 * we can invoke the proper sub-dissector for a given DCERPC
665 * @param binding all values needed to create and bind a new conversation
667 * @return Pointer to newly-added UUID/conversation binding.
669 static struct _dcerpc_bind_value *
670 dcerpc_add_conv_to_bind_table(decode_dcerpc_bind_values_t *binding)
672 dcerpc_bind_value *bind_value;
673 dcerpc_bind_key *key;
674 conversation_t *conv;
676 conv = find_conversation(
686 conv = conversation_new(
696 bind_value = (dcerpc_bind_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_value));
697 bind_value->uuid = binding->uuid;
698 bind_value->ver = binding->ver;
699 /* For now, assume all DCE/RPC we pick from "decode as" is using
700 standard ndr and not ndr64.
701 We should make this selectable from the dialog in the future
703 bind_value->transport = uuid_data_repr_proto;
705 key = (dcerpc_bind_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_key));
707 key->ctx_id = binding->ctx_id;
708 key->smb_fid = binding->smb_fid;
710 /* add this entry to the bind table */
711 g_hash_table_insert(dcerpc_binds, key, bind_value);
717 /* inject one of our bindings into the dcerpc binding table */
719 decode_dcerpc_inject_binding(gpointer data, gpointer user_data _U_)
721 dcerpc_add_conv_to_bind_table((decode_dcerpc_bind_values_t *) data);
724 /* inject all of our bindings into the dcerpc binding table */
726 decode_dcerpc_inject_bindings(void) {
727 g_slist_foreach(decode_dcerpc_bindings, decode_dcerpc_inject_binding, NULL /* user_data */);
732 decode_dcerpc_binding_free(void *binding_in)
734 decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t *)binding_in;
736 g_free((void *) binding->addr_a.data);
737 g_free((void *) binding->addr_b.data);
739 g_string_free(binding->ifname, TRUE);
744 dcerpc_decode_as_free(gpointer value)
746 decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t *)value;
748 decode_dcerpc_binding_free(binding);
751 /* removes all bindings */
753 decode_dcerpc_reset_all(void)
755 decode_dcerpc_bind_values_t *binding;
757 while(decode_dcerpc_bindings) {
758 binding = (decode_dcerpc_bind_values_t *)decode_dcerpc_bindings->data;
760 decode_dcerpc_binding_free(binding);
761 decode_dcerpc_bindings = g_slist_remove(
762 decode_dcerpc_bindings,
763 decode_dcerpc_bindings->data);
769 decode_dcerpc_add_show_list(decode_add_show_list_func func, gpointer user_data)
771 g_slist_foreach(decode_dcerpc_bindings, func, user_data);
775 dcerpc_prompt(packet_info *pinfo, gchar* result)
777 GString *str = g_string_new("Replace binding between:\r\n"),
778 *address_str = g_string_new("");
779 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
781 switch(pinfo->ptype) {
783 g_string_append(address_str, "Address: ToBeDone TCP port");
786 g_string_append(address_str, "Address: ToBeDone UDP port");
789 g_string_append(address_str, "Address: ToBeDone Unknown port type");
792 g_string_append_printf(str, "%s: %u\r\n", address_str->str, pinfo->srcport);
793 g_string_append(str, "&\r\n");
794 g_string_append_printf(str, "%s: %u\r\n", address_str->str, pinfo->destport);
795 g_string_append_printf(str, "&\r\nContext ID: %u\r\n", decode_data->dcectxid);
796 g_string_append_printf(str, "&\r\nSMB FID: %u\r\n", dcerpc_get_transport_salt(pinfo));
797 g_string_append(str, "with:\r\n");
799 g_strlcpy(result, str->str, MAX_DECODE_AS_PROMPT_LEN);
800 g_string_free(str, TRUE);
801 g_string_free(address_str, TRUE);
805 dcerpc_value(packet_info *pinfo)
807 decode_dcerpc_bind_values_t *binding;
808 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
811 binding = g_new(decode_dcerpc_bind_values_t,1);
812 COPY_ADDRESS(&binding->addr_a, &pinfo->src);
813 COPY_ADDRESS(&binding->addr_b, &pinfo->dst);
814 binding->ptype = pinfo->ptype;
815 binding->port_a = pinfo->srcport;
816 binding->port_b = pinfo->destport;
817 binding->ctx_id = decode_data->dcectxid;
818 binding->smb_fid = dcerpc_get_transport_salt(pinfo);
819 binding->ifname = NULL;
820 /*binding->uuid = NULL;*/
826 struct dcerpc_decode_as_populate
828 decode_as_add_to_list_func add_to_list;
833 decode_dcerpc_add_to_list(gpointer key, gpointer value, gpointer user_data)
835 struct dcerpc_decode_as_populate* populate = (struct dcerpc_decode_as_populate*)user_data;
837 /*dcerpc_uuid_key *k = key;*/
838 dcerpc_uuid_value *v = (dcerpc_uuid_value *)value;
840 if(strcmp(v->name, "(none)"))
841 populate->add_to_list("DCE-RPC", v->name, key, populate->ui_element);
845 dcerpc_populate_list(const gchar *table_name _U_, decode_as_add_to_list_func add_to_list, gpointer ui_element)
847 struct dcerpc_decode_as_populate populate;
849 populate.add_to_list = add_to_list;
850 populate.ui_element = ui_element;
852 g_hash_table_foreach(dcerpc_uuids, decode_dcerpc_add_to_list, &populate);
855 /* compare two bindings (except the interface related things, e.g. uuid) */
857 decode_dcerpc_binding_cmp(gconstpointer a, gconstpointer b)
859 const decode_dcerpc_bind_values_t *binding_a = (const decode_dcerpc_bind_values_t *)a;
860 const decode_dcerpc_bind_values_t *binding_b = (const decode_dcerpc_bind_values_t *)b;
863 /* don't compare uuid and ver! */
865 ADDRESSES_EQUAL(&binding_a->addr_a, &binding_b->addr_a) &&
866 ADDRESSES_EQUAL(&binding_a->addr_b, &binding_b->addr_b) &&
867 binding_a->ptype == binding_b->ptype &&
868 binding_a->port_a == binding_b->port_a &&
869 binding_a->port_b == binding_b->port_b &&
870 binding_a->ctx_id == binding_b->ctx_id &&
871 binding_a->smb_fid == binding_b->smb_fid)
881 /* remove a binding (looking the same way as the given one) */
883 decode_dcerpc_binding_reset(const char *name _U_, const gpointer pattern)
885 decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t*)pattern;
887 decode_dcerpc_bind_values_t *old_binding;
889 /* find the old binding (if it exists) */
890 le = g_slist_find_custom(decode_dcerpc_bindings,
892 decode_dcerpc_binding_cmp);
896 old_binding = (decode_dcerpc_bind_values_t *)le->data;
898 decode_dcerpc_bindings = g_slist_remove(decode_dcerpc_bindings, le->data);
900 g_free((void *) old_binding->addr_a.data);
901 g_free((void *) old_binding->addr_b.data);
902 g_string_free(old_binding->ifname, TRUE);
908 dcerpc_decode_as_change(const char *name, const gpointer pattern, gpointer handle, gchar* list_name)
910 decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t*)pattern;
911 decode_dcerpc_bind_values_t *stored_binding;
912 dcerpc_uuid_key *key = *((dcerpc_uuid_key**)handle);
915 binding->ifname = g_string_new(list_name);
916 binding->uuid = key->uuid;
917 binding->ver = key->ver;
919 /* remove a probably existing old binding */
920 decode_dcerpc_binding_reset(name, binding);
922 /* clone the new binding and append it to the list */
923 stored_binding = g_new(decode_dcerpc_bind_values_t,1);
924 *stored_binding = *binding;
925 COPY_ADDRESS(&stored_binding->addr_a, &binding->addr_a);
926 COPY_ADDRESS(&stored_binding->addr_b, &binding->addr_b);
927 stored_binding->ifname = g_string_new(binding->ifname->str);
929 decode_dcerpc_bindings = g_slist_append (decode_dcerpc_bindings, stored_binding);
934 static const fragment_items dcerpc_frag_items = {
935 &ett_dcerpc_fragments,
936 &ett_dcerpc_fragment,
938 &hf_dcerpc_fragments,
940 &hf_dcerpc_fragment_overlap,
941 &hf_dcerpc_fragment_overlap_conflict,
942 &hf_dcerpc_fragment_multiple_tails,
943 &hf_dcerpc_fragment_too_long_fragment,
944 &hf_dcerpc_fragment_error,
945 &hf_dcerpc_fragment_count,
947 &hf_dcerpc_reassembled_length,
948 /* Reassembled data field */
953 /* list of hooks to be called when init_protocols is done */
954 GHookList dcerpc_hooks_init_protos;
959 static dcerpc_info di[20];
960 static int di_counter = 0;
963 if (di_counter >= 20) {
967 memset(&di[di_counter], 0, sizeof(dcerpc_info));
968 di[di_counter].dcerpc_procedure_name = "";
970 return &di[di_counter];
973 /* try to desegment big DCE/RPC packets over TCP? */
974 static gboolean dcerpc_cn_desegment = TRUE;
976 /* reassemble DCE/RPC fragments */
977 /* reassembly of cl dcerpc fragments will not work for the case where ONE frame
978 might contain multiple dcerpc fragments for different PDUs.
979 this case would be so unusual/weird so if you got captures like that:
982 reassembly of co dcerpc fragments will not work for the case where TCP/SMB frames
983 are coming in out of sequence, but that will hurt in a lot of other places as well.
985 static gboolean dcerpc_reassemble = TRUE;
986 static reassembly_table dcerpc_co_reassembly_table;
987 static reassembly_table dcerpc_cl_reassembly_table;
989 typedef struct _dcerpc_fragment_key {
994 } dcerpc_fragment_key;
997 dcerpc_fragment_hash(gconstpointer k)
999 const dcerpc_fragment_key* key = (const dcerpc_fragment_key*) k;
1004 hash_val += key->id;
1005 hash_val += key->act_id.Data1;
1006 hash_val += key->act_id.Data2 << 16;
1007 hash_val += key->act_id.Data3;
1013 dcerpc_fragment_equal(gconstpointer k1, gconstpointer k2)
1015 const dcerpc_fragment_key* key1 = (const dcerpc_fragment_key*) k1;
1016 const dcerpc_fragment_key* key2 = (const dcerpc_fragment_key*) k2;
1018 /*key.id is the first item to compare since item is most
1019 likely to differ between sessions, thus shortcircuiting
1020 the comparison of addresses.
1022 return (((key1->id == key2->id)
1023 && (ADDRESSES_EQUAL(&key1->src, &key2->src))
1024 && (ADDRESSES_EQUAL(&key1->dst, &key2->dst))
1025 && (memcmp (&key1->act_id, &key2->act_id, sizeof (e_uuid_t)) == 0))
1029 /* allocate a persistent dcerpc fragment key to insert in the hash */
1031 dcerpc_fragment_temporary_key(const packet_info *pinfo, const guint32 id,
1034 dcerpc_fragment_key *key = g_slice_new(dcerpc_fragment_key);
1035 e_dce_dg_common_hdr_t *hdr = (e_dce_dg_common_hdr_t *)data;
1037 key->src = pinfo->src;
1038 key->dst = pinfo->dst;
1040 key->act_id = hdr->act_id;
1045 /* allocate a persistent dcerpc fragment key to insert in the hash */
1047 dcerpc_fragment_persistent_key(const packet_info *pinfo, const guint32 id,
1050 dcerpc_fragment_key *key = g_slice_new(dcerpc_fragment_key);
1051 e_dce_dg_common_hdr_t *hdr = (e_dce_dg_common_hdr_t *)data;
1053 COPY_ADDRESS(&key->src, &pinfo->src);
1054 COPY_ADDRESS(&key->dst, &pinfo->dst);
1056 key->act_id = hdr->act_id;
1062 dcerpc_fragment_free_temporary_key(gpointer ptr)
1064 dcerpc_fragment_key *key = (dcerpc_fragment_key *)ptr;
1067 g_slice_free(dcerpc_fragment_key, key);
1071 dcerpc_fragment_free_persistent_key(gpointer ptr)
1073 dcerpc_fragment_key *key = (dcerpc_fragment_key *)ptr;
1077 * Free up the copies of the addresses from the old key.
1079 g_free((gpointer)key->src.data);
1080 g_free((gpointer)key->dst.data);
1082 g_slice_free(dcerpc_fragment_key, key);
1086 static const reassembly_table_functions dcerpc_cl_reassembly_table_functions = {
1087 dcerpc_fragment_hash,
1088 dcerpc_fragment_equal,
1089 dcerpc_fragment_temporary_key,
1090 dcerpc_fragment_persistent_key,
1091 dcerpc_fragment_free_temporary_key,
1092 dcerpc_fragment_free_persistent_key
1096 dcerpc_reassemble_init(void)
1099 * XXX - addresses_ports_reassembly_table_functions?
1100 * Or can a single connection-oriented DCE RPC session persist
1101 * over multiple transport layer connections?
1103 reassembly_table_init(&dcerpc_co_reassembly_table,
1104 &addresses_reassembly_table_functions);
1105 reassembly_table_init(&dcerpc_cl_reassembly_table,
1106 &dcerpc_cl_reassembly_table_functions);
1110 * Authentication subdissectors. Used to dissect authentication blobs in
1111 * DCERPC binds, requests and responses.
1114 typedef struct _dcerpc_auth_subdissector {
1117 dcerpc_auth_subdissector_fns auth_fns;
1118 } dcerpc_auth_subdissector;
1120 static GSList *dcerpc_auth_subdissector_list;
1122 static dcerpc_auth_subdissector_fns *get_auth_subdissector_fns(
1123 guint8 auth_level, guint8 auth_type)
1128 for (i = 0; (data = g_slist_nth_data(dcerpc_auth_subdissector_list, i)); i++) {
1129 dcerpc_auth_subdissector *asd = (dcerpc_auth_subdissector *)data;
1131 if ((asd->auth_level == auth_level) &&
1132 (asd->auth_type == auth_type))
1133 return &asd->auth_fns;
1139 void register_dcerpc_auth_subdissector(guint8 auth_level, guint8 auth_type,
1140 dcerpc_auth_subdissector_fns *fns)
1142 dcerpc_auth_subdissector *d;
1144 if (get_auth_subdissector_fns(auth_level, auth_type))
1147 d = (dcerpc_auth_subdissector *)g_malloc(sizeof(dcerpc_auth_subdissector));
1149 d->auth_level = auth_level;
1150 d->auth_type = auth_type;
1151 memcpy(&d->auth_fns, fns, sizeof(dcerpc_auth_subdissector_fns));
1153 dcerpc_auth_subdissector_list = g_slist_append(dcerpc_auth_subdissector_list, d);
1156 /* Hand off verifier data to a registered dissector */
1158 static void dissect_auth_verf(tvbuff_t *auth_tvb, packet_info *pinfo,
1160 dcerpc_auth_subdissector_fns *auth_fns,
1161 e_dce_cn_common_hdr_t *hdr,
1162 dcerpc_auth_info *auth_info)
1164 dcerpc_dissect_fnct_t *volatile fn = NULL;
1165 /* XXX - "stub" a fake DCERPC INFO STRUCTURE
1166 If a dcerpc_info is really needed, update
1167 the call stacks to include it
1169 FAKE_DCERPC_INFO_STRUCTURE
1171 switch (hdr->ptype) {
1174 fn = auth_fns->bind_fn;
1178 fn = auth_fns->bind_ack_fn;
1181 fn = auth_fns->auth3_fn;
1184 fn = auth_fns->req_verf_fn;
1187 fn = auth_fns->resp_verf_fn;
1190 /* Don't know how to handle authentication data in this
1194 g_warning("attempt to dissect %s pdu authentication data",
1195 val_to_str(hdr->ptype, pckt_vals, "Unknown (%u)"));
1200 fn(auth_tvb, 0, pinfo, tree, &di, hdr->drep);
1202 tvb_ensure_bytes_exist(auth_tvb, 0, hdr->auth_len);
1203 proto_tree_add_text(tree, auth_tvb, 0, hdr->auth_len,
1205 val_to_str(auth_info->auth_type,
1206 authn_protocol_vals,
1211 /* Hand off payload data to a registered dissector */
1213 static tvbuff_t *decode_encrypted_data(tvbuff_t *data_tvb,
1216 dcerpc_auth_subdissector_fns *auth_fns,
1217 gboolean is_request,
1218 dcerpc_auth_info *auth_info)
1220 dcerpc_decode_data_fnct_t *fn;
1223 fn = auth_fns->req_data_fn;
1225 fn = auth_fns->resp_data_fn;
1228 return fn(data_tvb, auth_tvb, 0, pinfo, auth_info);
1237 /* the registered subdissectors */
1238 GHashTable *dcerpc_uuids = NULL;
1241 dcerpc_uuid_equal(gconstpointer k1, gconstpointer k2)
1243 const dcerpc_uuid_key *key1 = (const dcerpc_uuid_key *)k1;
1244 const dcerpc_uuid_key *key2 = (const dcerpc_uuid_key *)k2;
1245 return ((memcmp(&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
1246 && (key1->ver == key2->ver));
1250 dcerpc_uuid_hash(gconstpointer k)
1252 const dcerpc_uuid_key *key = (const dcerpc_uuid_key *)k;
1253 /* This isn't perfect, but the Data1 part of these is almost always
1255 return key->uuid.Data1;
1259 dcerpc_init_uuid(int proto, int ett, e_uuid_t *uuid, guint16 ver,
1260 dcerpc_sub_dissector *procs, int opnum_hf)
1262 dcerpc_uuid_key *key = (dcerpc_uuid_key *)g_malloc(sizeof (*key));
1263 dcerpc_uuid_value *value = (dcerpc_uuid_value *)g_malloc(sizeof (*value));
1264 header_field_info *hf_info;
1265 module_t *samr_module;
1266 const char *filter_name = proto_get_protocol_filter_name(proto);
1271 value->proto = find_protocol_by_id(proto);
1272 value->proto_id = proto;
1274 value->name = proto_get_protocol_short_name(value->proto);
1275 value->procs = procs;
1276 value->opnum_hf = opnum_hf;
1278 g_hash_table_insert(dcerpc_uuids, key, value);
1280 hf_info = proto_registrar_get_nth(opnum_hf);
1281 hf_info->strings = value_string_from_subdissectors(procs);
1283 /* add this GUID to the global name resolving */
1284 guids_add_uuid(uuid, proto_get_protocol_short_name(value->proto));
1286 /* Register the samr.nt_password preference as obsolete */
1287 /* This should be in packet-dcerpc-samr.c */
1288 if (strcmp(filter_name, "samr") == 0) {
1289 samr_module = prefs_register_protocol(proto, NULL);
1290 prefs_register_obsolete_preference(samr_module, "nt_password");
1294 /* Function to find the name of a registered protocol
1295 * or NULL if the protocol/version is not known to wireshark.
1298 dcerpc_get_proto_name(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->name;
1311 /* Function to find the opnum hf-field of a registered protocol
1312 * or -1 if the protocol/version is not known to wireshark.
1315 dcerpc_get_proto_hf_opnum(e_uuid_t *uuid, guint16 ver)
1317 dcerpc_uuid_key key;
1318 dcerpc_uuid_value *sub_proto;
1322 if (!(sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key))) {
1325 return sub_proto->opnum_hf;
1328 /* Create a value_string consisting of DCERPC opnum and name from a
1329 subdissector array. */
1331 value_string *value_string_from_subdissectors(dcerpc_sub_dissector *sd)
1333 value_string *vs = NULL;
1338 for (i = 0; sd[i].name; i++) {
1340 vs[i].value = sd[i].num;
1341 vs[i].strptr = sd[i].name;
1347 vs = (value_string *)wmem_alloc(wmem_epan_scope(), (num_sd + 1) * sizeof(value_string));
1351 vs[num_sd].value = 0;
1352 vs[num_sd].strptr = NULL;
1357 /* Function to find the subdissector table of a registered protocol
1358 * or NULL if the protocol/version is not known to wireshark.
1360 dcerpc_sub_dissector *
1361 dcerpc_get_proto_sub_dissector(e_uuid_t *uuid, guint16 ver)
1363 dcerpc_uuid_key key;
1364 dcerpc_uuid_value *sub_proto;
1368 if (!(sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key))) {
1371 return sub_proto->procs;
1377 dcerpc_bind_equal(gconstpointer k1, gconstpointer k2)
1379 const dcerpc_bind_key *key1 = (const dcerpc_bind_key *)k1;
1380 const dcerpc_bind_key *key2 = (const dcerpc_bind_key *)k2;
1381 return ((key1->conv == key2->conv)
1382 && (key1->ctx_id == key2->ctx_id)
1383 && (key1->smb_fid == key2->smb_fid));
1387 dcerpc_bind_hash(gconstpointer k)
1389 const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
1392 hash = GPOINTER_TO_UINT(key->conv) + key->ctx_id + key->smb_fid;
1398 * To keep track of callid mappings. Should really use some generic
1399 * conversation support instead.
1401 static GHashTable *dcerpc_cn_calls = NULL;
1402 static GHashTable *dcerpc_dg_calls = NULL;
1404 typedef struct _dcerpc_cn_call_key {
1405 conversation_t *conv;
1408 } dcerpc_cn_call_key;
1410 typedef struct _dcerpc_dg_call_key {
1411 conversation_t *conv;
1414 } dcerpc_dg_call_key;
1418 dcerpc_cn_call_equal(gconstpointer k1, gconstpointer k2)
1420 const dcerpc_cn_call_key *key1 = (const dcerpc_cn_call_key *)k1;
1421 const dcerpc_cn_call_key *key2 = (const dcerpc_cn_call_key *)k2;
1422 return ((key1->conv == key2->conv)
1423 && (key1->call_id == key2->call_id)
1424 && (key1->smb_fid == key2->smb_fid));
1428 dcerpc_dg_call_equal(gconstpointer k1, gconstpointer k2)
1430 const dcerpc_dg_call_key *key1 = (const dcerpc_dg_call_key *)k1;
1431 const dcerpc_dg_call_key *key2 = (const dcerpc_dg_call_key *)k2;
1432 return ((key1->conv == key2->conv)
1433 && (key1->seqnum == key2->seqnum)
1434 && ((memcmp(&key1->act_id, &key2->act_id, sizeof (e_uuid_t)) == 0)));
1438 dcerpc_cn_call_hash(gconstpointer k)
1440 const dcerpc_cn_call_key *key = (const dcerpc_cn_call_key *)k;
1441 return GPOINTER_TO_UINT(key->conv) + key->call_id + key->smb_fid;
1445 dcerpc_dg_call_hash(gconstpointer k)
1447 const dcerpc_dg_call_key *key = (const dcerpc_dg_call_key *)k;
1448 return (GPOINTER_TO_UINT(key->conv) + key->seqnum + key->act_id.Data1
1449 + (key->act_id.Data2 << 16) + key->act_id.Data3
1450 + (key->act_id.Data4[0] << 24) + (key->act_id.Data4[1] << 16)
1451 + (key->act_id.Data4[2] << 8) + (key->act_id.Data4[3] << 0)
1452 + (key->act_id.Data4[4] << 24) + (key->act_id.Data4[5] << 16)
1453 + (key->act_id.Data4[6] << 8) + (key->act_id.Data4[7] << 0));
1456 /* to keep track of matched calls/responses
1457 this one uses the same value struct as calls, but the key is the frame id
1458 and call id; there can be more than one call in a frame.
1460 XXX - why not just use the same keys as are used for calls?
1463 static GHashTable *dcerpc_matched = NULL;
1465 typedef struct _dcerpc_matched_key {
1468 } dcerpc_matched_key;
1471 dcerpc_matched_equal(gconstpointer k1, gconstpointer k2)
1473 const dcerpc_matched_key *key1 = (const dcerpc_matched_key *)k1;
1474 const dcerpc_matched_key *key2 = (const dcerpc_matched_key *)k2;
1475 return ((key1->frame == key2->frame)
1476 && (key1->call_id == key2->call_id));
1480 dcerpc_matched_hash(gconstpointer k)
1482 const dcerpc_matched_key *key = (const dcerpc_matched_key *)k;
1489 * Utility functions. Modeled after packet-rpc.c
1493 dissect_dcerpc_uint8(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1494 proto_tree *tree, guint8 *drep,
1495 int hfindex, guint8 *pdata)
1499 data = tvb_get_guint8(tvb, offset);
1501 proto_tree_add_item(tree, hfindex, tvb, offset, 1, DREP_ENC_INTEGER(drep));
1509 dissect_dcerpc_uint16(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1510 proto_tree *tree, guint8 *drep,
1511 int hfindex, guint16 *pdata)
1515 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1516 ? tvb_get_letohs(tvb, offset)
1517 : tvb_get_ntohs(tvb, offset));
1520 proto_tree_add_item(tree, hfindex, tvb, offset, 2, DREP_ENC_INTEGER(drep));
1528 dissect_dcerpc_uint32(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1529 proto_tree *tree, guint8 *drep,
1530 int hfindex, guint32 *pdata)
1534 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1535 ? tvb_get_letohl(tvb, offset)
1536 : tvb_get_ntohl(tvb, offset));
1539 proto_tree_add_item(tree, hfindex, tvb, offset, 4, DREP_ENC_INTEGER(drep));
1546 /* handles 32 bit unix time_t */
1548 dissect_dcerpc_time_t(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1549 proto_tree *tree, guint8 *drep,
1550 int hfindex, guint32 *pdata)
1555 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1556 ? tvb_get_letohl(tvb, offset)
1557 : tvb_get_ntohl(tvb, offset));
1562 if (data == 0xffffffff) {
1563 /* special case, no time specified */
1564 proto_tree_add_time_format_value(tree, hfindex, tvb, offset, 4, &tv, "No time specified");
1566 proto_tree_add_time(tree, hfindex, tvb, offset, 4, &tv);
1576 dissect_dcerpc_uint64(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1577 proto_tree *tree, guint8 *drep,
1578 int hfindex, guint64 *pdata)
1582 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1583 ? tvb_get_letoh64(tvb, offset)
1584 : tvb_get_ntoh64(tvb, offset));
1587 header_field_info *hfinfo;
1589 /* This might be a field that is either 32bit, in NDR or
1590 64 bits in NDR64. So we must be careful and call the right
1593 hfinfo = proto_registrar_get_nth(hfindex);
1595 switch (hfinfo->type) {
1597 proto_tree_add_uint64(tree, hfindex, tvb, offset, 8, data);
1600 proto_tree_add_int64(tree, hfindex, tvb, offset, 8, data);
1603 DISSECTOR_ASSERT(data <= G_MAXUINT32);
1604 proto_tree_add_uint(tree, hfindex, tvb, offset, 8, (guint32)data);
1614 dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1615 proto_tree *tree, guint8 *drep,
1616 int hfindex, gfloat *pdata)
1622 case(DCE_RPC_DREP_FP_IEEE):
1623 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1624 ? tvb_get_letohieee_float(tvb, offset)
1625 : tvb_get_ntohieee_float(tvb, offset));
1627 proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
1630 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
1631 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1632 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
1634 /* ToBeDone: non IEEE floating formats */
1635 /* Set data to a negative infinity value */
1638 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep[1]);
1648 dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1649 proto_tree *tree, guint8 *drep,
1650 int hfindex, gdouble *pdata)
1656 case(DCE_RPC_DREP_FP_IEEE):
1657 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1658 ? tvb_get_letohieee_double(tvb, offset)
1659 : tvb_get_ntohieee_double(tvb, offset));
1661 proto_tree_add_double(tree, hfindex, tvb, offset, 8, data);
1664 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
1665 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1666 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
1668 /* ToBeDone: non IEEE double formats */
1669 /* Set data to a negative infinity value */
1670 data = -G_MAXDOUBLE;
1672 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep[1]);
1682 dissect_dcerpc_uuid_t(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1683 proto_tree *tree, guint8 *drep,
1684 int hfindex, e_uuid_t *pdata)
1689 if (drep[0] & DREP_LITTLE_ENDIAN) {
1690 tvb_get_letohguid(tvb, offset, (e_guid_t *) &uuid);
1692 tvb_get_ntohguid(tvb, offset, (e_guid_t *) &uuid);
1695 proto_tree_add_guid(tree, hfindex, tvb, offset, 16, (e_guid_t *) &uuid);
1705 * a couple simpler things
1708 dcerpc_tvb_get_ntohs(tvbuff_t *tvb, gint offset, guint8 *drep)
1710 if (drep[0] & DREP_LITTLE_ENDIAN) {
1711 return tvb_get_letohs(tvb, offset);
1713 return tvb_get_ntohs(tvb, offset);
1718 dcerpc_tvb_get_ntohl(tvbuff_t *tvb, gint offset, guint8 *drep)
1720 if (drep[0] & DREP_LITTLE_ENDIAN) {
1721 return tvb_get_letohl(tvb, offset);
1723 return tvb_get_ntohl(tvb, offset);
1728 dcerpc_tvb_get_uuid(tvbuff_t *tvb, gint offset, guint8 *drep, e_uuid_t *uuid)
1730 if (drep[0] & DREP_LITTLE_ENDIAN) {
1731 tvb_get_letohguid(tvb, offset, (e_guid_t *) uuid);
1733 tvb_get_ntohguid(tvb, offset, (e_guid_t *) uuid);
1739 /* function to dissect a unidimensional conformant array */
1741 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1742 proto_tree *tree, dcerpc_info *di, guint8 *drep,
1743 dcerpc_dissect_fnct_t *fnct)
1747 int conformance_size = 4;
1749 if (di->call_data->flags & DCERPC_IS_NDR64) {
1750 conformance_size = 8;
1753 if (di->conformant_run) {
1756 /* conformant run, just dissect the max_count header */
1757 old_offset = offset;
1758 di->conformant_run = 0;
1759 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1760 hf_dcerpc_array_max_count, &val);
1761 di->array_max_count = (gint32)val;
1762 di->array_max_count_offset = offset-conformance_size;
1763 di->conformant_run = 1;
1764 di->conformant_eaten = offset-old_offset;
1766 /* we don't remember where in the bytestream this field was */
1767 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, conformance_size, di->array_max_count);
1769 /* real run, dissect the elements */
1770 for(i=0; i<di->array_max_count; i++) {
1771 offset = (*fnct)(tvb, offset, pinfo, tree, di, drep);
1778 /* function to dissect a unidimensional conformant and varying array
1779 * depending on the dissection function passed as a parameter,
1780 * content of the array will be dissected as a block or byte by byte
1783 dissect_ndr_ucvarray_core(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1784 proto_tree *tree, dcerpc_info *di, guint8 *drep,
1785 dcerpc_dissect_fnct_t *fnct_bytes,
1786 dcerpc_dissect_fnct_blk_t *fnct_block)
1790 int conformance_size = 4;
1792 if (di->call_data->flags & DCERPC_IS_NDR64) {
1793 conformance_size = 8;
1796 if (di->conformant_run) {
1799 /* conformant run, just dissect the max_count header */
1800 old_offset = offset;
1801 di->conformant_run = 0;
1802 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1803 hf_dcerpc_array_max_count, &val);
1804 DISSECTOR_ASSERT(val <= G_MAXUINT32);
1805 di->array_max_count = (guint32)val;
1806 di->array_max_count_offset = offset-conformance_size;
1807 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1808 hf_dcerpc_array_offset, &val);
1809 DISSECTOR_ASSERT(val <= G_MAXUINT32);
1810 di->array_offset = (guint32)val;
1811 di->array_offset_offset = offset-conformance_size;
1812 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1813 hf_dcerpc_array_actual_count, &val);
1814 DISSECTOR_ASSERT(val <= G_MAXUINT32);
1815 di->array_actual_count = (guint32)val;
1816 di->array_actual_count_offset = offset-conformance_size;
1817 di->conformant_run = 1;
1818 di->conformant_eaten = offset-old_offset;
1820 /* we don't remember where in the bytestream these fields were */
1821 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, conformance_size, di->array_max_count);
1822 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, conformance_size, di->array_offset);
1823 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, conformance_size, di->array_actual_count);
1825 /* real run, dissect the elements */
1827 offset = (*fnct_block)(tvb, offset, di->array_actual_count, pinfo, tree, drep);
1829 for(i=0 ;i<di->array_actual_count; i++) {
1830 old_offset = offset;
1831 offset = (*fnct_bytes)(tvb, offset, pinfo, tree, di, drep);
1832 if (offset <= old_offset)
1833 THROW(ReportedBoundsError);
1842 dissect_ndr_ucvarray_block(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1843 proto_tree *tree, dcerpc_info *di, guint8 *drep,
1844 dcerpc_dissect_fnct_blk_t *fnct)
1846 return dissect_ndr_ucvarray_core(tvb, offset, pinfo, tree, di, drep, NULL, fnct);
1850 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1851 proto_tree *tree, dcerpc_info *di, guint8 *drep,
1852 dcerpc_dissect_fnct_t *fnct)
1854 return dissect_ndr_ucvarray_core(tvb, offset, pinfo, tree, di, drep, fnct, NULL);
1856 /* function to dissect a unidimensional varying array */
1858 dissect_ndr_uvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1859 proto_tree *tree, dcerpc_info *di, guint8 *drep,
1860 dcerpc_dissect_fnct_t *fnct)
1864 int conformance_size = 4;
1866 if (di->call_data->flags & DCERPC_IS_NDR64) {
1867 conformance_size = 8;
1870 if (di->conformant_run) {
1873 /* conformant run, just dissect the max_count header */
1874 old_offset = offset;
1875 di->conformant_run = 0;
1876 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1877 hf_dcerpc_array_offset, &val);
1878 DISSECTOR_ASSERT(val <= G_MAXUINT32);
1879 di->array_offset = (guint32)val;
1880 di->array_offset_offset = offset-conformance_size;
1881 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1882 hf_dcerpc_array_actual_count, &val);
1883 DISSECTOR_ASSERT(val <= G_MAXUINT32);
1884 di->array_actual_count = (guint32)val;
1885 di->array_actual_count_offset = offset-conformance_size;
1886 di->conformant_run = 1;
1887 di->conformant_eaten = offset-old_offset;
1889 /* we don't remember where in the bytestream these fields were */
1890 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, conformance_size, di->array_offset);
1891 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, conformance_size, di->array_actual_count);
1893 /* real run, dissect the elements */
1894 for(i=0; i<di->array_actual_count; i++) {
1895 offset = (*fnct)(tvb, offset, pinfo, tree, di, drep);
1902 /* Dissect an string of bytes. This corresponds to
1903 IDL of the form '[string] byte *foo'.
1905 It can also be used for a conformant varying array of bytes if
1906 the contents of the array should be shown as a big blob, rather
1907 than showing each byte as an individual element.
1909 XXX - which of those is really the IDL type for, for example,
1910 the encrypted data in some MAPI packets? (Microsoft hasn't
1913 XXX - does this need to do all the conformant array stuff that
1914 "dissect_ndr_ucvarray()" does? These are presumably for strings
1915 that are conformant and varying - they're stored like conformant
1916 varying arrays of bytes. */
1918 dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo,
1919 proto_tree *tree, dcerpc_info *di, guint8 *drep)
1923 if (di->conformant_run) {
1924 /* just a run to handle conformant arrays, no scalars to dissect */
1928 /* NDR array header */
1930 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1931 hf_dcerpc_array_max_count, NULL);
1933 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1934 hf_dcerpc_array_offset, NULL);
1936 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1937 hf_dcerpc_array_actual_count, &len);
1939 DISSECTOR_ASSERT(len <= G_MAXUINT32);
1941 tvb_ensure_bytes_exist(tvb, offset, (guint32)len);
1942 proto_tree_add_item(tree, hf_dcerpc_array_buffer,
1943 tvb, offset, (guint32)len, ENC_NA);
1946 offset += (guint32)len;
1951 /* For dissecting arrays that are to be interpreted as strings. */
1953 /* Dissect an NDR conformant varying string of elements.
1954 The length of each element is given by the 'size_is' parameter;
1955 the elements are assumed to be characters or wide characters.
1957 XXX - does this need to do all the conformant array stuff that
1958 "dissect_ndr_ucvarray()" does? */
1960 dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1961 proto_tree *tree, dcerpc_info *di, guint8 *drep, int size_is,
1962 int hfindex, gboolean add_subtree, char **data)
1964 proto_item *string_item;
1965 proto_tree *string_tree;
1969 header_field_info *hfinfo;
1971 if (di->conformant_run) {
1972 /* just a run to handle conformant arrays, no scalars to dissect */
1977 string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1978 proto_registrar_get_name(hfindex));
1979 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1985 /* NDR array header */
1987 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
1988 hf_dcerpc_array_max_count, NULL);
1990 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
1991 hf_dcerpc_array_offset, NULL);
1993 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
1994 hf_dcerpc_array_actual_count, &len);
1996 DISSECTOR_ASSERT(len <= G_MAXUINT32);
1997 buffer_len = size_is * (guint32)len;
2000 if (!di->no_align && (offset % size_is))
2001 offset += size_is - (offset % size_is);
2003 if (size_is == sizeof(guint16)) {
2004 /* XXX - use drep to determine the byte order? */
2005 /* XXX - once we have an ENC_ value for UTF-16, just use
2006 proto_tree_add_item() with the appropriate ENC_ value? */
2007 /* XXX - should this ever be used with something that's *not*
2009 s = tvb_get_unicode_string(wmem_packet_scope(), tvb, offset, buffer_len, ENC_LITTLE_ENDIAN);
2010 if (tree && buffer_len) {
2011 hfinfo = proto_registrar_get_nth(hfindex);
2012 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
2013 if (hfinfo->type == FT_STRING) {
2014 proto_tree_add_string(string_tree, hfindex, tvb, offset,
2017 proto_tree_add_item(string_tree, hfindex, tvb, offset,
2018 buffer_len, DREP_ENC_INTEGER(drep));
2024 * "tvb_get_string()" throws an exception if the entire string
2025 * isn't in the tvbuff. If the length is bogus, this should
2026 * keep us from trying to allocate an immensely large buffer.
2027 * (It won't help if the length is *valid* but immensely large,
2028 * but that's another matter; in any case, that would happen only
2029 * if we had an immensely large tvbuff....)
2031 * XXX - if this is an octet string, does the byte order
2032 * matter? Will this ever be anything *other* than an
2033 * octet string? What if size_is is neither 1 nor 2?
2035 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
2036 s = tvb_get_string(wmem_packet_scope(), tvb, offset, buffer_len);
2037 if (tree && buffer_len)
2038 proto_tree_add_item(string_tree, hfindex, tvb, offset,
2039 buffer_len, DREP_ENC_INTEGER(drep));
2042 if (string_item != NULL)
2043 proto_item_append_text(string_item, ": %s", s);
2048 offset += buffer_len;
2050 proto_item_set_end(string_item, tvb, offset);
2056 dissect_ndr_cstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2057 proto_tree *tree, dcerpc_info *di, guint8 *drep, int size_is,
2058 int hfindex, gboolean add_subtree, char **data)
2060 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep, size_is, hfindex, add_subtree, data);
2063 /* Dissect an conformant varying string of chars.
2064 This corresponds to IDL of the form '[string] char *foo'.
2066 XXX - at least according to the DCE RPC 1.1 spec, a string has
2067 a null terminator, which isn't necessary as a terminator for
2068 the transfer language (as there's a length), but is presumably
2069 there for the benefit of null-terminated-string languages
2070 such as C. Is this ever used for purely counted strings?
2071 (Not that it matters if it is.) */
2073 dissect_ndr_char_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2074 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2076 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep,
2077 sizeof(guint8), di->hf_index,
2081 /* Dissect a conformant varying string of wchars (wide characters).
2082 This corresponds to IDL of the form '[string] wchar *foo'
2084 XXX - at least according to the DCE RPC 1.1 spec, a string has
2085 a null terminator, which isn't necessary as a terminator for
2086 the transfer language (as there's a length), but is presumably
2087 there for the benefit of null-terminated-string languages
2088 such as C. Is this ever used for purely counted strings?
2089 (Not that it matters if it is.) */
2091 dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2092 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2094 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep,
2095 sizeof(guint16), di->hf_index,
2099 /* This function is aimed for PIDL usage and dissects a UNIQUE pointer to
2103 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)
2106 gint levels = CB_STR_ITEM_LEVELS(param);
2108 offset = dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep,
2112 if (!di->conformant_run) {
2113 /* Append string to COL_INFO */
2114 if (param & PIDL_SET_COL_INFO) {
2115 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", s);
2117 /* Save string to dcv->private_data */
2118 if ((param & PIDL_STR_SAVE)
2119 && (!pinfo->fd->flags.visited)) {
2120 dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2121 dcv->private_data = wmem_strdup(wmem_file_scope(), s);
2123 /* Append string to upper-level proto_items */
2124 if ((levels > 0) && tree && s && s[0]) {
2125 proto_item_append_text(tree, ": %s", s);
2126 tree = tree->parent;
2129 proto_item_append_text(tree, ": %s", s);
2130 tree = tree->parent;
2132 while (levels > 0) {
2133 proto_item_append_text(tree, " %s", s);
2134 tree = tree->parent;
2145 /* Dissect an NDR varying string of elements.
2146 The length of each element is given by the 'size_is' parameter;
2147 the elements are assumed to be characters or wide characters.
2150 dissect_ndr_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2151 proto_tree *tree, dcerpc_info *di, guint8 *drep, int size_is,
2152 int hfindex, gboolean add_subtree, char **data)
2154 proto_item *string_item;
2155 proto_tree *string_tree;
2159 header_field_info *hfinfo;
2161 if (di->conformant_run) {
2162 /* just a run to handle conformant arrays, no scalars to dissect */
2167 string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
2168 proto_registrar_get_name(hfindex));
2169 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
2175 /* NDR array header */
2176 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
2177 hf_dcerpc_array_offset, NULL);
2179 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
2180 hf_dcerpc_array_actual_count, &len);
2182 DISSECTOR_ASSERT(len <= G_MAXUINT32);
2183 buffer_len = size_is * (guint32)len;
2186 if (!di->no_align && (offset % size_is))
2187 offset += size_is - (offset % size_is);
2189 if (size_is == sizeof(guint16)) {
2190 /* XXX - use drep to determine the byte order? */
2191 /* XXX - once we have an ENC_ value for UTF-16, just use
2192 proto_tree_add_item() with the appropriate ENC_ value? */
2193 /* XXX - should this ever be used with something that's *not*
2195 s = tvb_get_unicode_string(wmem_packet_scope(), tvb, offset, buffer_len, ENC_LITTLE_ENDIAN);
2196 if (tree && buffer_len) {
2197 hfinfo = proto_registrar_get_nth(hfindex);
2198 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
2199 if (hfinfo->type == FT_STRING) {
2200 proto_tree_add_string(string_tree, hfindex, tvb, offset,
2203 proto_tree_add_item(string_tree, hfindex, tvb, offset,
2204 buffer_len, DREP_ENC_INTEGER(drep));
2210 * "tvb_get_string()" throws an exception if the entire string
2211 * isn't in the tvbuff. If the length is bogus, this should
2212 * keep us from trying to allocate an immensely large buffer.
2213 * (It won't help if the length is *valid* but immensely large,
2214 * but that's another matter; in any case, that would happen only
2215 * if we had an immensely large tvbuff....)
2217 * XXX - if this is an octet string, does the byte order
2218 * matter? Will this ever be anything *other* than an
2219 * octet string? What if size_is is neither 1 nor 2?
2221 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
2222 s = tvb_get_string(wmem_packet_scope(), tvb, offset, buffer_len);
2223 if (tree && buffer_len)
2224 proto_tree_add_item(string_tree, hfindex, tvb, offset,
2225 buffer_len, DREP_ENC_INTEGER(drep));
2228 if (string_item != NULL)
2229 proto_item_append_text(string_item, ": %s", s);
2234 offset += buffer_len;
2236 proto_item_set_end(string_item, tvb, offset);
2241 /* Dissect an varying string of chars.
2242 This corresponds to IDL of the form '[string] char *foo'.
2244 XXX - at least according to the DCE RPC 1.1 spec, a string has
2245 a null terminator, which isn't necessary as a terminator for
2246 the transfer language (as there's a length), but is presumably
2247 there for the benefit of null-terminated-string languages
2248 such as C. Is this ever used for purely counted strings?
2249 (Not that it matters if it is.) */
2251 dissect_ndr_char_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2252 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2254 return dissect_ndr_vstring(tvb, offset, pinfo, tree, di, drep,
2255 sizeof(guint8), di->hf_index,
2259 /* Dissect a varying string of wchars (wide characters).
2260 This corresponds to IDL of the form '[string] wchar *foo'
2262 XXX - at least according to the DCE RPC 1.1 spec, a string has
2263 a null terminator, which isn't necessary as a terminator for
2264 the transfer language (as there's a length), but is presumably
2265 there for the benefit of null-terminated-string languages
2266 such as C. Is this ever used for purely counted strings?
2267 (Not that it matters if it is.) */
2269 dissect_ndr_wchar_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2270 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2272 return dissect_ndr_vstring(tvb, offset, pinfo, tree, di, drep,
2273 sizeof(guint16), di->hf_index,
2278 /* ndr pointer handling */
2279 /* list of pointers encountered so far */
2280 static GSList *ndr_pointer_list = NULL;
2282 /* position where in the list to insert newly encountered pointers */
2283 static int ndr_pointer_list_pos = 0;
2285 /* Boolean controlling whether pointers are top-level or embedded */
2286 static gboolean pointers_are_top_level = TRUE;
2288 /* as a kludge, we represent all embedded reference pointers as id == -1
2289 hoping that his will not collide with any non-ref pointers */
2290 typedef struct ndr_pointer_data {
2292 proto_item *item; /* proto_item for pointer */
2293 proto_tree *tree; /* subtree of above item */
2294 dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
2296 dcerpc_callback_fnct_t *callback;
2297 void *callback_args;
2298 } ndr_pointer_data_t;
2301 init_ndr_pointer_list(dcerpc_info *di)
2303 di->conformant_run = 0;
2305 while (ndr_pointer_list) {
2306 ndr_pointer_data_t *npd = (ndr_pointer_data_t *)g_slist_nth_data(ndr_pointer_list, 0);
2307 ndr_pointer_list = g_slist_remove(ndr_pointer_list, npd);
2311 ndr_pointer_list = NULL;
2312 ndr_pointer_list_pos = 0;
2313 pointers_are_top_level = TRUE;
2317 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, dcerpc_info *di, guint8 *drep)
2319 int found_new_pointer;
2328 found_new_pointer = 0;
2329 len = g_slist_length(ndr_pointer_list);
2330 for(i=next_pointer; i<len; i++) {
2331 ndr_pointer_data_t *tnpd = (ndr_pointer_data_t *)g_slist_nth_data(ndr_pointer_list, i);
2333 dcerpc_dissect_fnct_t *fnct;
2336 found_new_pointer = 1;
2339 ndr_pointer_list_pos = i+1;
2340 di->hf_index = tnpd->hf_index;
2341 /* first a run to handle any conformant
2343 di->conformant_run = 1;
2344 di->conformant_eaten = 0;
2345 old_offset = offset;
2346 offset = (*(fnct))(tvb, offset, pinfo, NULL, di, drep);
2348 DISSECTOR_ASSERT((offset-old_offset) == di->conformant_eaten);
2349 /* This is to check for any bugs in the dissectors.
2351 * Basically, the NDR representation will store all
2352 * arrays in two blocks, one block with the dimension
2353 * description, like size, number of elements and such,
2354 * and another block that contains the actual data stored
2356 * If the array is embedded directly inside another,
2357 * encapsulating aggregate type, like a union or struct,
2358 * then these two blocks will be stored at different places
2359 * in the bytestream, with other data between the blocks.
2361 * For this reason, all pointers to types (both aggregate
2362 * and scalar, for simplicity no distinction is made)
2363 * will have its dissector called twice.
2364 * The dissector will first be called with conformant_run == 1
2365 * in which mode the dissector MUST NOT consume any data from
2366 * the tvbuff (i.e. may not dissect anything) except the
2367 * initial control block for arrays.
2368 * The second time the dissector is called, with
2369 * conformant_run == 0, all other data for the type will be
2372 * All dissect_ndr_<type> dissectors are already prepared
2373 * for this and knows when it should eat data from the tvb
2374 * and when not to, so implementors of dissectors will
2375 * normally not need to worry about this or even know about
2376 * it. However, if a dissector for an aggregate type calls
2377 * a subdissector from outside packet-dcerpc.c, such as
2378 * the dissector in packet-smb.c for NT Security Descriptors
2379 * as an example, then it is VERY important to encapsulate
2380 * this call to an external subdissector with the appropriate
2381 * test for conformant_run, i.e. it will need something like
2383 * dcerpc_info *di (received as function parameter)
2385 * if (di->conformant_run) {
2389 * to make sure it makes the right thing.
2390 * This assert will signal when someone has forgotten to
2391 * make the dissector aware of this requirement.
2394 /* now we dissect the actual pointer */
2395 di->conformant_run = 0;
2396 old_offset = offset;
2397 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, di, drep);
2399 tnpd->callback(pinfo, tnpd->tree, tnpd->item, di, tvb, old_offset, offset, tnpd->callback_args);
2400 proto_item_set_len(tnpd->item, offset - old_offset);
2404 } while (found_new_pointer);
2411 add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
2412 dcerpc_info *di, dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index,
2413 dcerpc_callback_fnct_t *callback, void *callback_args)
2415 ndr_pointer_data_t *npd;
2417 /* check if this pointer is valid */
2418 if (id != 0xffffffff) {
2419 dcerpc_call_value *value;
2421 value = di->call_data;
2423 if (di->ptype == PDU_REQ) {
2424 if (!(pinfo->fd->flags.visited)) {
2425 if (id > value->max_ptr) {
2426 value->max_ptr = id;
2430 /* if we haven't seen the request bail out since we cant
2431 know whether this is the first non-NULL instance
2433 if (value->req_frame == 0) {
2434 /* XXX THROW EXCEPTION */
2437 /* We saw this one in the request frame, nothing to
2439 if (id <= value->max_ptr) {
2445 npd = (ndr_pointer_data_t *)g_malloc(sizeof(ndr_pointer_data_t));
2450 npd->hf_index = hf_index;
2451 npd->callback = callback;
2452 npd->callback_args = callback_args;
2453 ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
2454 ndr_pointer_list_pos);
2455 ndr_pointer_list_pos++;
2460 find_pointer_index(guint32 id)
2462 ndr_pointer_data_t *npd;
2465 len = g_slist_length(ndr_pointer_list);
2466 for(i=0; i<len; i++) {
2467 npd = (ndr_pointer_data_t *)g_slist_nth_data(ndr_pointer_list, i);
2469 if (npd->id == id) {
2478 /* This function dissects an NDR pointer and stores the callback for later
2479 * deferred dissection.
2481 * fnct is the callback function for when we have reached this object in
2484 * type is what type of pointer.
2486 * this is text is what text we should put in any created tree node.
2488 * hf_index is what hf value we want to pass to the callback function when
2489 * it is called, the callback can later pick this one up from di->hf_index.
2491 * callback is executed after the pointer has been dereferenced.
2493 * callback_args is passed as an argument to the callback function
2495 * See packet-dcerpc-samr.c for examples
2498 dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2499 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2500 int type, const char *text, int hf_index,
2501 dcerpc_callback_fnct_t *callback, void *callback_args)
2503 proto_tree *tr = NULL;
2504 gint start_offset = offset;
2505 int pointer_size = 4;
2507 if (di->conformant_run) {
2508 /* this call was only for dissecting the header for any
2509 embedded conformant array. we will not parse any
2510 pointers in this mode.
2514 if (di->call_data->flags & DCERPC_IS_NDR64) {
2519 /*TOP LEVEL REFERENCE POINTER*/
2520 if ( pointers_are_top_level
2521 && (type == NDR_POINTER_REF) ) {
2524 /* we must find out a nice way to do the length here */
2525 item = proto_tree_add_text(tree, tvb, offset, 0,
2527 tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2529 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
2530 hf_index, callback, callback_args);
2534 /*TOP LEVEL FULL POINTER*/
2535 if ( pointers_are_top_level
2536 && (type == NDR_POINTER_PTR) ) {
2541 /* get the referent id */
2542 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
2544 tvb_ensure_bytes_exist(tvb, offset-pointer_size, pointer_size);
2545 /* we got a NULL pointer */
2547 proto_tree_add_text(tree, tvb, offset-pointer_size,
2549 "(NULL pointer) %s",text);
2553 /* see if we have seen this pointer before */
2554 DISSECTOR_ASSERT(id <= G_MAXUINT32);
2555 idx = find_pointer_index((guint32)id);
2557 /* we have seen this pointer before */
2559 proto_tree_add_text(tree, tvb, offset-pointer_size,
2561 "(duplicate PTR) %s",text);
2566 item = proto_tree_add_text(tree, tvb, offset-pointer_size,
2569 tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2570 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb,
2571 offset-pointer_size, pointer_size, (guint32)id);
2572 add_pointer_to_list(pinfo, tr, item, di, fnct, (guint32)id, hf_index,
2573 callback, callback_args);
2576 /*TOP LEVEL UNIQUE POINTER*/
2577 if ( pointers_are_top_level
2578 && (type == NDR_POINTER_UNIQUE) ) {
2582 /* get the referent id */
2583 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
2585 tvb_ensure_bytes_exist(tvb, offset-pointer_size, pointer_size);
2586 /* we got a NULL pointer */
2588 proto_tree_add_text(tree, tvb, offset-pointer_size,
2590 "(NULL pointer) %s",text);
2595 DISSECTOR_ASSERT(id <= G_MAXUINT32);
2596 item = proto_tree_add_text(tree, tvb, offset-pointer_size,
2599 tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2600 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb,
2601 offset-pointer_size, pointer_size, (guint32)id);
2602 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
2603 hf_index, callback, callback_args);
2607 /*EMBEDDED REFERENCE POINTER*/
2608 if ( (!pointers_are_top_level)
2609 && (type == NDR_POINTER_REF) ) {
2613 /* get the referent id */
2614 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
2616 tvb_ensure_bytes_exist(tvb, offset-pointer_size, pointer_size);
2618 item = proto_tree_add_text(tree, tvb, offset-pointer_size,
2621 tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2622 DISSECTOR_ASSERT(id <= G_MAXUINT32);
2623 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb,
2624 offset-pointer_size, pointer_size, (guint32)id);
2625 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
2626 hf_index, callback, callback_args);
2630 /*EMBEDDED UNIQUE POINTER*/
2631 if ( (!pointers_are_top_level)
2632 && (type == NDR_POINTER_UNIQUE) ) {
2636 /* get the referent id */
2637 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
2639 tvb_ensure_bytes_exist(tvb, offset-pointer_size, pointer_size);
2640 /* we got a NULL pointer */
2642 proto_tree_add_text(tree, tvb, offset-pointer_size,
2644 "(NULL pointer) %s", text);
2649 item = proto_tree_add_text(tree, tvb, offset-pointer_size,
2652 tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2653 DISSECTOR_ASSERT(id <= G_MAXUINT32);
2654 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb,
2655 offset-pointer_size, pointer_size, (guint32)id);
2656 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
2657 hf_index, callback, callback_args);
2661 /*EMBEDDED FULL POINTER*/
2662 if ( (!pointers_are_top_level)
2663 && (type == NDR_POINTER_PTR) ) {
2668 /* get the referent id */
2669 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
2671 tvb_ensure_bytes_exist(tvb, offset-pointer_size, pointer_size);
2672 /* we got a NULL pointer */
2674 proto_tree_add_text(tree, tvb, offset-pointer_size,
2676 "(NULL pointer) %s",text);
2680 /* see if we have seen this pointer before */
2681 DISSECTOR_ASSERT(id <= G_MAXUINT32);
2682 idx = find_pointer_index((guint32)id);
2684 /* we have seen this pointer before */
2686 proto_tree_add_text(tree, tvb, offset-pointer_size,
2688 "(duplicate PTR) %s",text);
2693 item = proto_tree_add_text(tree, tvb, offset-pointer_size,
2696 tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2697 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb,
2698 offset-pointer_size, pointer_size, (guint32)id);
2699 add_pointer_to_list(pinfo, tr, item, di, fnct, (guint32)id, hf_index,
2700 callback, callback_args);
2706 /* After each top level pointer we have dissected we have to
2707 dissect all deferrals before we move on to the next top level
2709 if (pointers_are_top_level == TRUE) {
2710 pointers_are_top_level = FALSE;
2711 offset = dissect_deferred_pointers(pinfo, tvb, offset, di, drep);
2712 pointers_are_top_level = TRUE;
2715 /* Set the length for the new subtree */
2717 proto_item_set_len(tr, offset-start_offset);
2723 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2724 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2725 int type, const char *text, int hf_index)
2727 return dissect_ndr_pointer_cb(
2728 tvb, offset, pinfo, tree, di, drep, fnct, type, text, hf_index,
2732 dissect_ndr_toplevel_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2733 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2734 int type, const char *text, int hf_index)
2738 pointers_are_top_level = TRUE;
2739 ret = dissect_ndr_pointer_cb(
2740 tvb, offset, pinfo, tree, di, drep, fnct, type, text, hf_index,
2745 dissect_ndr_embedded_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2746 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2747 int type, const char *text, int hf_index)
2751 pointers_are_top_level = FALSE;
2752 ret = dissect_ndr_pointer_cb(
2753 tvb, offset, pinfo, tree, di, drep, fnct, type, text, hf_index,
2759 show_stub_data(tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
2760 dcerpc_auth_info *auth_info, gboolean is_encrypted)
2762 int length, plain_length, auth_pad_len;
2763 guint auth_pad_offset;
2766 * We don't show stub data unless we have some in the tvbuff;
2767 * however, in the protocol tree, we show, as the number of
2768 * bytes, the reported number of bytes, not the number of bytes
2769 * that happen to be in the tvbuff.
2771 if (tvb_length_remaining(tvb, offset) > 0) {
2772 auth_pad_len = auth_info?auth_info->auth_pad_len:0;
2773 length = tvb_reported_length_remaining(tvb, offset);
2775 /* if auth_pad_len is larger than length then we ignore auth_pad_len totally */
2776 plain_length = length - auth_pad_len;
2777 if (plain_length < 1) {
2778 plain_length = length;
2781 auth_pad_offset = offset + plain_length;
2783 if ((auth_info != NULL) &&
2784 (auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)) {
2786 tvb_ensure_bytes_exist(tvb, offset, length);
2787 proto_tree_add_text(dcerpc_tree, tvb, offset, length,
2788 "Encrypted stub data (%d byte%s)",
2789 length, plurality(length, "", "s"));
2790 /* is the padding is still inside the encrypted blob, don't display it explicit */
2793 tvb_ensure_bytes_exist(tvb, offset, plain_length);
2794 proto_tree_add_text(dcerpc_tree, tvb, offset, plain_length,
2795 "Decrypted stub data (%d byte%s)",
2796 plain_length, plurality(plain_length, "", "s"));
2799 tvb_ensure_bytes_exist(tvb, offset, plain_length);
2800 proto_tree_add_text(dcerpc_tree, tvb, offset, plain_length,
2801 "Stub data (%d byte%s)", plain_length,
2802 plurality(plain_length, "", "s"));
2804 /* If there is auth padding at the end of the stub, display it */
2805 if (auth_pad_len != 0) {
2806 tvb_ensure_bytes_exist(tvb, auth_pad_offset, auth_pad_len);
2807 proto_tree_add_text(dcerpc_tree, tvb, auth_pad_offset,
2809 "Auth Padding (%u byte%s)",
2811 plurality(auth_pad_len, "", "s"));
2817 dcerpc_try_handoff(packet_info *pinfo, proto_tree *tree,
2818 proto_tree *dcerpc_tree,
2819 tvbuff_t *volatile tvb, tvbuff_t *decrypted_tvb,
2820 guint8 *drep, dcerpc_info *info,
2821 dcerpc_auth_info *auth_info)
2823 volatile gint offset = 0;
2824 dcerpc_uuid_key key;
2825 dcerpc_uuid_value *sub_proto;
2826 proto_tree *volatile sub_tree = NULL;
2827 dcerpc_sub_dissector *proc;
2828 const gchar *name = NULL;
2829 const char *volatile saved_proto;
2830 guint length = 0, reported_length = 0;
2831 tvbuff_t *volatile stub_tvb;
2832 volatile guint auth_pad_len;
2833 volatile int auth_pad_offset;
2834 proto_item *sub_item = NULL;
2835 proto_item *pi, *hidden_item;
2837 dcerpc_dissect_fnct_t *volatile sub_dissect;
2839 key.uuid = info->call_data->uuid;
2840 key.ver = info->call_data->ver;
2842 if ((sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key)) == NULL
2843 || !proto_is_protocol_enabled(sub_proto->proto)) {
2845 * We don't have a dissector for this UUID, or the protocol
2846 * for that UUID is disabled.
2849 hidden_item = proto_tree_add_boolean(dcerpc_tree, hf_dcerpc_unknown_if_id,
2850 tvb, offset, 0, TRUE);
2851 PROTO_ITEM_SET_HIDDEN(hidden_item);
2852 col_append_fstr(pinfo->cinfo, COL_INFO, " %s V%u",
2853 guids_resolve_uuid_to_str(&info->call_data->uuid), info->call_data->ver);
2855 if (decrypted_tvb != NULL) {
2856 show_stub_data(decrypted_tvb, 0, dcerpc_tree, auth_info,
2859 show_stub_data(tvb, 0, dcerpc_tree, auth_info, TRUE);
2863 for (proc = sub_proto->procs; proc->name; proc++) {
2864 if (proc->num == info->call_data->opnum) {
2870 col_set_str(pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
2873 col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown operation %u %s",
2874 info->call_data->opnum,
2875 (info->ptype == PDU_REQ) ? "request" : "response");
2877 col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
2878 name, (info->ptype == PDU_REQ) ? "request" : "response");
2880 sub_dissect = (info->ptype == PDU_REQ) ?
2881 proc->dissect_rqst : proc->dissect_resp;
2884 sub_item = proto_tree_add_item(tree, sub_proto->proto_id,
2885 (decrypted_tvb != NULL)?decrypted_tvb:tvb,
2889 sub_tree = proto_item_add_subtree(sub_item, sub_proto->ett);
2891 proto_item_append_text(sub_item, ", unknown operation %u",
2892 info->call_data->opnum);
2894 proto_item_append_text(sub_item, ", %s", name);
2898 * Put the operation number into the tree along with
2899 * the operation's name.
2901 if (sub_proto->opnum_hf != -1)
2902 proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
2903 tvb, 0, 0, info->call_data->opnum,
2904 "Operation: %s (%u)",
2905 name ? name : "Unknown operation",
2906 info->call_data->opnum);
2908 proto_tree_add_uint_format_value(sub_tree, hf_dcerpc_op, tvb,
2909 0, 0, info->call_data->opnum,
2911 name ? name : "Unknown operation",
2912 info->call_data->opnum);
2914 if ((info->ptype == PDU_REQ) && (info->call_data->rep_frame != 0)) {
2915 pi = proto_tree_add_uint(sub_tree, hf_dcerpc_response_in,
2916 tvb, 0, 0, info->call_data->rep_frame);
2917 PROTO_ITEM_SET_GENERATED(pi);
2919 if ((info->ptype == PDU_RESP) && (info->call_data->req_frame != 0)) {
2920 pi = proto_tree_add_uint(sub_tree, hf_dcerpc_request_in,
2921 tvb, 0, 0, info->call_data->req_frame);
2922 PROTO_ITEM_SET_GENERATED(pi);
2926 if (decrypted_tvb != NULL) {
2927 /* Either there was no encryption or we successfully decrypted
2928 the encrypted payload. */
2930 /* We have a subdissector - call it. */
2931 saved_proto = pinfo->current_proto;
2932 pinfo->current_proto = sub_proto->name;
2934 init_ndr_pointer_list(info);
2936 length = tvb_length(decrypted_tvb);
2937 reported_length = tvb_reported_length(decrypted_tvb);
2940 * Remove the authentication padding from the stub data.
2942 if ((auth_info != NULL) && (auth_info->auth_pad_len != 0)) {
2943 if (reported_length >= auth_info->auth_pad_len) {
2945 * OK, the padding length isn't so big that it
2946 * exceeds the stub length. Trim the reported
2947 * length of the tvbuff.
2949 reported_length -= auth_info->auth_pad_len;
2952 * If that exceeds the actual amount of data in
2953 * the tvbuff (which means we have at least one
2954 * byte of authentication padding in the tvbuff),
2955 * trim the actual amount.
2957 if (length > reported_length)
2958 length = reported_length;
2960 stub_tvb = tvb_new_subset(decrypted_tvb, 0, length, reported_length);
2961 auth_pad_len = auth_info->auth_pad_len;
2962 auth_pad_offset = reported_length;
2965 * The padding length exceeds the stub length.
2966 * Don't bother dissecting the stub, trim the padding
2967 * length to what's in the stub data, and show the
2968 * entire stub as authentication padding.
2971 auth_pad_len = reported_length;
2972 auth_pad_offset = 0;
2977 * No authentication padding.
2979 stub_tvb = decrypted_tvb;
2981 auth_pad_offset = 0;
2985 proto_item_set_len(sub_item, length);
2988 if (stub_tvb != NULL) {
2990 * Catch all exceptions other than BoundsError, so that even
2991 * if the stub data is bad, we still show the authentication
2994 * If we get BoundsError, it means the frame was cut short
2995 * by a snapshot length, so there's nothing more to
2996 * dissect; just re-throw that exception.
3001 offset = sub_dissect(stub_tvb, 0, pinfo, sub_tree,
3004 /* If we have a subdissector and it didn't dissect all
3005 data in the tvb, make a note of it. */
3006 remaining = tvb_reported_length_remaining(stub_tvb, offset);
3007 if (remaining > 0) {
3008 proto_tree_add_text(sub_tree, stub_tvb, offset,
3010 "[Long frame (%d byte%s)]",
3012 plurality(remaining, "", "s"));
3013 col_append_fstr(pinfo->cinfo, COL_INFO,
3014 "[Long frame (%d byte%s)]",
3016 plurality(remaining, "", "s"));
3019 } CATCH_NONFATAL_ERRORS {
3021 * Somebody threw an exception that means that there
3022 * was a problem dissecting the payload; that means
3023 * that a dissector was found, so we don't need to
3024 * dissect the payload as data or update the protocol
3027 * Just show the exception and then drive on to show
3028 * the authentication padding.
3030 show_exception(stub_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
3034 /* If there is auth padding at the end of the stub, display it */
3035 if (auth_pad_len != 0) {
3036 tvb_ensure_bytes_exist(tvb, auth_pad_offset, auth_pad_len);
3037 proto_tree_add_text(sub_tree, decrypted_tvb, auth_pad_offset,
3039 "Auth Padding (%u byte%s)",
3041 plurality(auth_pad_len, "", "s"));
3044 pinfo->current_proto = saved_proto;
3046 /* No subdissector - show it as stub data. */
3047 if (decrypted_tvb) {
3048 show_stub_data(decrypted_tvb, 0, sub_tree, auth_info, FALSE);
3050 show_stub_data(tvb, 0, sub_tree, auth_info, TRUE);
3054 show_stub_data(tvb, 0, sub_tree, auth_info, TRUE);
3056 tap_queue_packet(dcerpc_tap, pinfo, info);
3061 dissect_dcerpc_verifier(tvbuff_t *tvb, packet_info *pinfo,
3062 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
3063 dcerpc_auth_info *auth_info)
3067 auth_info->auth_data = NULL;
3069 if (auth_info->auth_size != 0) {
3070 dcerpc_auth_subdissector_fns *auth_fns;
3073 auth_offset = hdr->frag_len - hdr->auth_len;
3075 auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
3078 auth_info->auth_data = auth_tvb;
3080 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
3081 auth_info->auth_type))) {
3083 * Catch all bounds-error exceptions, so that even if the
3084 * verifier is bad or we don't have all of it, we still
3085 * show the stub data.
3088 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
3090 } CATCH_BOUNDS_ERRORS {
3091 show_exception(auth_tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
3094 tvb_ensure_bytes_exist(tvb, 0, hdr->auth_len);
3095 proto_tree_add_text(dcerpc_tree, auth_tvb, 0, hdr->auth_len,
3100 return hdr->auth_len;
3104 dissect_dcerpc_cn_auth(tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
3105 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
3106 gboolean are_credentials, dcerpc_auth_info *auth_info)
3108 volatile int offset;
3111 * Initially set auth_level and auth_type to zero to indicate that we
3112 * haven't yet seen any authentication level information.
3114 auth_info->auth_level = 0;
3115 auth_info->auth_type = 0;
3116 auth_info->auth_size = 0;
3117 auth_info->auth_pad_len = 0;
3120 * The authentication information is at the *end* of the PDU; in
3121 * request and response PDUs, the request and response stub data
3124 * Is there any authentication data (i.e., is the authentication length
3125 * non-zero), and is the authentication length valid (i.e., is it, plus
3126 * 8 bytes for the type/level/pad length/reserved/context id, less than
3127 * or equal to the fragment length minus the starting offset of the
3132 && ((hdr->auth_len + 8) <= (hdr->frag_len - stub_offset))) {
3135 * Yes, there is authentication data, and the length is valid.
3136 * Do we have all the bytes of stub data?
3137 * (If not, we'd throw an exception dissecting *that*, so don't
3138 * bother trying to dissect the authentication information and
3139 * throwing another exception there.)
3141 offset = hdr->frag_len - (hdr->auth_len + 8);
3142 if (offset == 0 || tvb_offset_exists(tvb, offset - 1)) {
3144 * Either there's no stub data, or the last byte of the stub
3145 * data is present in the captured data, so we shouldn't
3146 * get a BoundsError dissecting the stub data.
3148 * Try dissecting the authentication data.
3149 * Catch all exceptions, so that even if the auth info is bad
3150 * or we don't have all of it, we still show the stuff we
3151 * dissect after this, such as stub data.
3154 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3155 hf_dcerpc_auth_type,
3156 &auth_info->auth_type);
3157 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3158 hf_dcerpc_auth_level,
3159 &auth_info->auth_level);
3161 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3162 hf_dcerpc_auth_pad_len,
3163 &auth_info->auth_pad_len);
3164 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3165 hf_dcerpc_auth_rsrvd, NULL);
3166 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3167 hf_dcerpc_auth_ctx_id, NULL);
3170 * Dissect the authentication data.
3172 if (are_credentials) {
3174 dcerpc_auth_subdissector_fns *auth_fns;
3176 auth_tvb = tvb_new_subset(tvb, offset,
3177 MIN(hdr->auth_len,tvb_length_remaining(tvb, offset)),
3180 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
3181 auth_info->auth_type)))
3182 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
3185 proto_tree_add_text(dcerpc_tree, tvb, offset, hdr->auth_len,
3186 "Auth Credentials");
3189 /* Compute the size of the auth block. Note that this should not
3190 include auth padding, since when NTLMSSP encryption is used, the
3191 padding is actually inside the encrypted stub */
3192 auth_info->auth_size = hdr->auth_len + 8;
3193 } CATCH_BOUNDS_ERRORS {
3194 show_exception(tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
3201 /* We need to hash in the SMB fid number to generate a unique hash table
3202 * key as DCERPC over SMB allows several pipes over the same TCP/IP
3204 * We pass this function the transport type here to make sure we only look
3205 * at this function if it came across an SMB pipe.
3206 * Other transports might need to mix in their own extra multiplexing data
3207 * as well in the future.
3210 guint16 dcerpc_get_transport_salt(packet_info *pinfo)
3212 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
3214 switch (decode_data->dcetransporttype) {
3215 case DCE_CN_TRANSPORT_SMBPIPE:
3216 /* DCERPC over smb */
3217 return decode_data->dcetransportsalt;
3220 /* Some other transport... */
3224 void dcerpc_set_transport_salt(guint16 dcetransportsalt, packet_info *pinfo)
3226 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
3228 decode_data->dcetransportsalt = dcetransportsalt;
3232 * Connection oriented packet types
3236 dissect_dcerpc_cn_bind(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3237 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
3239 conversation_t *conv = find_or_create_conversation(pinfo);
3240 guint8 num_ctx_items = 0;
3243 guint8 num_trans_items;
3248 guint16 if_ver, if_ver_minor;
3249 dcerpc_auth_info auth_info;
3251 const char *uuid_name = NULL;
3252 proto_item *iface_item = NULL;
3253 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
3255 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3256 hf_dcerpc_cn_max_xmit, NULL);
3258 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3259 hf_dcerpc_cn_max_recv, NULL);
3261 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3262 hf_dcerpc_cn_assoc_group, NULL);
3264 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3265 hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
3270 col_append_fstr(pinfo->cinfo, COL_INFO, ", %u context items:", num_ctx_items);
3272 for (i = 0; i < num_ctx_items; i++) {
3273 proto_item *ctx_item = NULL;
3274 proto_tree *ctx_tree = NULL, *iface_tree = NULL;
3275 gint ctx_offset = offset;
3277 dissect_dcerpc_uint16(tvb, offset, pinfo, NULL, hdr->drep,
3278 hf_dcerpc_cn_ctx_id, &ctx_id);
3280 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3281 /* (if we have multiple contexts, this might cause "decode as"
3282 * to behave unpredictably) */
3283 decode_data->dcectxid = ctx_id;
3286 ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_item,
3289 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
3292 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree, hdr->drep,
3293 hf_dcerpc_cn_ctx_id, &ctx_id);
3294 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, ctx_tree, hdr->drep,
3295 hf_dcerpc_cn_num_trans_items, &num_trans_items);
3298 proto_item_append_text(ctx_item, "[%u]: Context ID:%u", i+1, ctx_id);
3304 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &if_id);
3307 iface_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_abstract_syntax, tvb, offset, 0, ENC_NA);
3308 iface_tree = proto_item_add_subtree(iface_item, ett_dcerpc_cn_iface);
3310 uuid_str = guid_to_str((e_guid_t*)&if_id);
3311 uuid_name = guids_get_uuid_name(&if_id);
3313 proto_tree_add_guid_format(iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
3314 offset, 16, (e_guid_t *) &if_id, "Interface: %s UUID: %s", uuid_name, uuid_str);
3315 proto_item_append_text(iface_item, ": %s", uuid_name);
3316 proto_item_append_text(ctx_item, ", %s", uuid_name);
3318 proto_tree_add_guid_format(iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
3319 offset, 16, (e_guid_t *) &if_id, "Interface UUID: %s", uuid_str);
3320 proto_item_append_text(iface_item, ": %s", uuid_str);
3321 proto_item_append_text(ctx_item, ", %s", uuid_str);
3326 if (hdr->drep[0] & DREP_LITTLE_ENDIAN) {
3327 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
3328 hf_dcerpc_cn_bind_if_ver, &if_ver);
3329 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
3330 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
3332 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
3333 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
3334 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
3335 hf_dcerpc_cn_bind_if_ver, &if_ver);
3339 proto_item_append_text(iface_item, " V%u.%u", if_ver, if_ver_minor);
3340 proto_item_set_len(iface_item, 20);
3343 memset(&trans_id, 0, sizeof(trans_id));
3344 for (j = 0; j < num_trans_items; j++) {
3345 proto_tree *trans_tree = NULL;
3346 proto_item *trans_item = NULL;
3347 proto_item *uuid_item = NULL;
3349 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &trans_id);
3352 trans_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_trans_syntax, tvb, offset, 0, ENC_NA);
3353 trans_tree = proto_item_add_subtree(trans_item, ett_dcerpc_cn_trans_syntax);
3355 uuid_str = guid_to_str((e_guid_t *) &trans_id);
3356 uuid_name = guids_get_uuid_name(&trans_id);
3359 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);
3360 proto_item_append_text(trans_item, "[%u]: %s", j+1, uuid_name);
3361 proto_item_append_text(ctx_item, ", %s", uuid_name);
3363 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);
3364 proto_item_append_text(trans_item, "[%u]: %s", j+1, uuid_str);
3365 proto_item_append_text(ctx_item, ", %s", uuid_str);
3368 /* check for [MS-RPCE] 3.3.1.5.3 Bind Time Feature Negotiation */
3369 if (trans_id.Data1 == 0x6cb71c2c && trans_id.Data2 == 0x9812 && trans_id.Data3 == 0x4540) {
3370 proto_tree *uuid_tree = proto_item_add_subtree(uuid_item, ett_dcerpc_cn_trans_btfn);
3371 proto_tree_add_boolean(uuid_tree, hf_dcerpc_cn_bind_trans_btfn_01, tvb, offset+8, 1, trans_id.Data4[0]);
3372 proto_tree_add_boolean(uuid_tree, hf_dcerpc_cn_bind_trans_btfn_02, tvb, offset+8, 1, trans_id.Data4[0]);
3377 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, trans_tree, hdr->drep,
3378 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
3380 proto_item_set_len(trans_item, 20);
3381 proto_item_append_text(trans_item, " V%u", trans_ver);
3385 /* if this is the first time we've seen this packet, we need to
3386 update the dcerpc_binds table so that any later calls can
3387 match to the interface.
3388 XXX We assume that BINDs will NEVER be fragmented.
3390 if (!(pinfo->fd->flags.visited)) {
3391 dcerpc_bind_key *key;
3392 dcerpc_bind_value *value;
3394 key = (dcerpc_bind_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_key));
3396 key->ctx_id = ctx_id;
3397 key->smb_fid = dcerpc_get_transport_salt(pinfo);
3399 value = (dcerpc_bind_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_value));
3400 value->uuid = if_id;
3401 value->ver = if_ver;
3402 value->transport = trans_id;
3404 /* add this entry to the bind table */
3405 g_hash_table_insert(dcerpc_binds, key, value);
3409 col_append_fstr(pinfo->cinfo, COL_INFO, ",");
3410 col_append_fstr(pinfo->cinfo, COL_INFO, " %s V%u.%u (%s)",
3411 guids_resolve_uuid_to_str(&if_id), if_ver, if_ver_minor,
3412 guids_resolve_uuid_to_str(&trans_id));
3415 proto_item_set_len(ctx_item, offset - ctx_offset);
3420 * XXX - we should save the authentication type *if* we have
3421 * an authentication header, and associate it with an authentication
3422 * context, so subsequent PDUs can use that context.
3424 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
3428 dissect_dcerpc_cn_bind_ack(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3429 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
3431 guint16 max_xmit, max_recv;
3432 guint16 sec_addr_len;
3439 dcerpc_auth_info auth_info;
3440 const char *uuid_name = NULL;
3441 const char *result_str = NULL;
3443 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3444 hf_dcerpc_cn_max_xmit, &max_xmit);
3446 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3447 hf_dcerpc_cn_max_recv, &max_recv);
3449 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3450 hf_dcerpc_cn_assoc_group, NULL);
3452 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3453 hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
3454 if (sec_addr_len != 0) {
3455 tvb_ensure_bytes_exist(tvb, offset, sec_addr_len);
3456 proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
3457 sec_addr_len, ENC_ASCII|ENC_NA);
3458 offset += sec_addr_len;
3462 offset += 4 - offset % 4;
3465 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3466 hf_dcerpc_cn_num_results, &num_results);
3471 col_append_fstr(pinfo->cinfo, COL_INFO, ", max_xmit: %u max_recv: %u, %u results:",
3472 max_xmit, max_recv, num_results);
3474 for (i = 0; i < num_results; i++) {
3475 proto_tree *ctx_tree = NULL;
3476 proto_item *ctx_item = NULL;
3479 ctx_item = proto_tree_add_text(dcerpc_tree, tvb, offset, 24, "Ctx Item[%u]:", i+1);
3480 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
3483 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree,
3484 hdr->drep, hf_dcerpc_cn_ack_result,
3487 /* [MS-RPCE] 3.3.1.5.3 check if this Ctx Item is the response to a Bind Time Feature Negotiation request */
3489 const int old_offset = offset;
3490 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree, hdr->drep, hf_dcerpc_cn_ack_btfn, &reason);
3491 proto_tree_add_boolean(ctx_tree, hf_dcerpc_cn_bind_trans_btfn_01, tvb, old_offset, 1, reason);
3492 proto_tree_add_boolean(ctx_tree, hf_dcerpc_cn_bind_trans_btfn_02, tvb, old_offset, 1, reason);
3493 } else if (result != 0) {
3494 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree,
3495 hdr->drep, hf_dcerpc_cn_ack_reason,
3499 * The reason for rejection isn't meaningful, and often isn't
3500 * set, when the syntax was accepted.
3505 result_str = val_to_str(result, p_cont_result_vals, "Unknown result (%u)");
3508 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &trans_id);
3509 uuid_name = guids_get_uuid_name(&trans_id);
3511 uuid_name = guid_to_str((e_guid_t *) &trans_id);
3513 proto_tree_add_guid_format(ctx_tree, hf_dcerpc_cn_ack_trans_id, tvb,
3514 offset, 16, (e_guid_t *) &trans_id, "Transfer Syntax: %s",
3516 proto_item_append_text(ctx_item, " %s, %s", result_str, uuid_name);
3520 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, ctx_tree, hdr->drep,
3521 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
3524 col_append_fstr(pinfo->cinfo, COL_INFO, ",");
3525 col_append_fstr(pinfo->cinfo, COL_INFO, " %s", result_str);
3529 * XXX - do we need to do anything with the authentication level
3530 * we get back from this?
3532 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
3536 dissect_dcerpc_cn_bind_nak(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3537 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
3540 guint8 num_protocols;
3543 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
3544 hdr->drep, hf_dcerpc_cn_reject_reason,
3547 col_append_fstr(pinfo->cinfo, COL_INFO, " reason: %s",
3548 val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
3550 if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
3551 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3552 hf_dcerpc_cn_num_protocols,
3555 for (i = 0; i < num_protocols; i++) {
3556 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
3557 hdr->drep, hf_dcerpc_cn_protocol_ver_major,
3559 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
3560 hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
3566 /* Return a string describing a DCE/RPC fragment as first, middle, or end
3569 #define PFC_FRAG_MASK 0x03
3572 fragment_type(guint8 flags)
3574 static const char* t[4] = {
3580 return t[flags & PFC_FRAG_MASK];
3583 /* Dissect stub data (payload) of a DCERPC packet. */
3586 dissect_dcerpc_cn_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
3587 proto_tree *dcerpc_tree, proto_tree *tree,
3588 e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
3589 dcerpc_auth_info *auth_info, guint32 alloc_hint _U_,
3592 gint length, reported_length;
3593 gboolean save_fragmented;
3594 fragment_head *fd_head = NULL;
3596 tvbuff_t *auth_tvb, *payload_tvb, *decrypted_tvb;
3598 proto_item *parent_pi;
3599 proto_item *dcerpc_tree_item;
3601 save_fragmented = pinfo->fragmented;
3603 length = tvb_length_remaining(tvb, offset);
3604 reported_length = tvb_reported_length_remaining(tvb, offset);
3605 if (reported_length < 0 ||
3606 (guint32)reported_length < auth_info->auth_size) {
3607 /* We don't even have enough bytes for the authentication
3611 reported_length -= auth_info->auth_size;
3612 if (length > reported_length)
3613 length = reported_length;
3614 payload_tvb = tvb_new_subset(tvb, offset, length, reported_length);
3617 /*don't bother if we don't have the entire tvb */
3618 /*XXX we should really make sure we calculate auth_info->auth_data
3619 and use that one instead of this auth_tvb hack
3621 if (tvb_length(tvb) == tvb_reported_length(tvb)) {
3622 if (tvb_length_remaining(tvb, offset+length) > 8) {
3623 auth_tvb = tvb_new_subset_remaining(tvb, offset+length+8);
3627 /* Decrypt the PDU if it is encrypted */
3629 if (auth_info->auth_type &&
3630 (auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)) {
3632 * We know the authentication type, and the authentication
3633 * level is "Packet privacy", meaning the payload is
3634 * encrypted; attempt to decrypt it.
3636 dcerpc_auth_subdissector_fns *auth_fns;
3638 /* Start out assuming we won't succeed in decrypting. */
3639 decrypted_tvb = NULL;
3640 /* Schannel needs information into the footer (verifier) in order to setup decryption keys
3641 * so we call it in order to have a chance to decipher the data
3643 if (DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN == auth_info->auth_type) {
3644 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, auth_info);
3647 if ((auth_fns = get_auth_subdissector_fns(
3648 auth_info->auth_level, auth_info->auth_type))) {
3651 result = decode_encrypted_data(
3652 payload_tvb, auth_tvb, pinfo, auth_fns,
3653 hdr->ptype == PDU_REQ, auth_info);
3657 proto_tree_add_text(
3658 dcerpc_tree, payload_tvb, 0, -1,
3659 "Encrypted stub data (%d byte%s)",
3660 tvb_reported_length(payload_tvb),
3662 plurality(tvb_length(payload_tvb), "", "s"));
3664 add_new_data_source(
3665 pinfo, result, "Decrypted stub data");
3668 decrypted_tvb = result;
3672 decrypted_tvb = payload_tvb;
3674 /* if this packet is not fragmented, just dissect it and exit */
3675 if (PFC_NOT_FRAGMENTED(hdr)) {
3676 pinfo->fragmented = FALSE;
3679 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
3680 hdr->drep, di, auth_info);
3682 pinfo->fragmented = save_fragmented;
3686 /* The packet is fragmented. */
3687 pinfo->fragmented = TRUE;
3689 /* debug output of essential fragment data. */
3690 /* leave it here for future debugging sessions */
3691 /*printf("DCE num:%u offset:%u frag_len:%u tvb_len:%u\n",
3692 pinfo->fd->num, offset, hdr->frag_len, tvb_length(decrypted_tvb));*/
3694 /* if we are not doing reassembly and this is the first fragment
3695 then just dissect it and exit
3696 XXX - if we're not doing reassembly, can we decrypt an
3699 if ( (!dcerpc_reassemble) && (hdr->flags & PFC_FIRST_FRAG) ) {
3702 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
3703 hdr->drep, di, auth_info);
3705 expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment, "%s fragment", fragment_type(hdr->flags));
3707 pinfo->fragmented = save_fragmented;
3711 /* if we have already seen this packet, see if it was reassembled
3712 and if so dissect the full pdu.
3715 if (pinfo->fd->flags.visited) {
3716 fd_head = fragment_get_reassembled(&dcerpc_co_reassembly_table, frame);
3720 /* if we are not doing reassembly and it was neither a complete PDU
3721 nor the first fragment then there is nothing more we can do
3722 so we just have to exit
3724 if ( !dcerpc_reassemble || (tvb_length(tvb) != tvb_reported_length(tvb)) )
3727 /* if we didn't get 'frame' we don't know where the PDU started and thus
3728 it is pointless to continue
3733 /* from now on we must attempt to reassemble the PDU
3736 /* if we get here we know it is the first time we see the packet
3737 and we also know it is only a fragment and not a full PDU,
3738 thus we must reassemble it.
3741 /* Do we have any non-encrypted data to reassemble? */
3742 if (decrypted_tvb == NULL) {
3743 /* No. We can't even try to reassemble. */
3747 /* defragmentation is a bit tricky, as there's no offset of the fragment
3748 * in the protocol data.
3750 * just use fragment_add_seq_next() and hope that TCP/SMB segments coming
3751 * in with the correct sequence.
3753 fd_head = fragment_add_seq_next(&dcerpc_co_reassembly_table,
3754 decrypted_tvb, 0, pinfo, frame, NULL,
3755 tvb_length(decrypted_tvb),
3756 hdr->flags&PFC_LAST_FRAG ? FALSE : TRUE /* more_frags */);
3760 /* if reassembly is complete and this is the last fragment
3761 * (multiple fragments in one PDU are possible!)
3762 * dissect the full PDU
3764 if (fd_head && (fd_head->flags & FD_DEFRAGMENTED) ) {
3766 if ((pinfo->fd->num == fd_head->reassembled_in) && (hdr->flags & PFC_LAST_FRAG) ) {
3768 proto_item *frag_tree_item;
3770 next_tvb = tvb_new_chain((decrypted_tvb)?decrypted_tvb:payload_tvb,
3773 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3774 show_fragment_tree(fd_head, &dcerpc_frag_items,
3775 tree, pinfo, next_tvb, &frag_tree_item);
3776 /* the toplevel fragment subtree is now behind all desegmented data,
3777 * move it right behind the DCE/RPC tree */
3778 dcerpc_tree_item = proto_tree_get_parent(dcerpc_tree);
3779 if (frag_tree_item && dcerpc_tree_item) {
3780 proto_tree_move_item(tree, dcerpc_tree_item, frag_tree_item);
3783 pinfo->fragmented = FALSE;
3785 expert_add_info_format(pinfo, frag_tree_item, &ei_dcerpc_fragment_reassembled, "%s fragment, reassembled", fragment_type(hdr->flags));
3787 dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb,
3788 next_tvb, hdr->drep, di, auth_info);
3791 if (decrypted_tvb) {
3792 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
3793 decrypted_tvb, 0, 0, fd_head->reassembled_in);
3795 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
3796 payload_tvb, 0, 0, fd_head->reassembled_in);
3798 PROTO_ITEM_SET_GENERATED(pi);
3799 parent_pi = proto_tree_get_parent(dcerpc_tree);
3800 if (parent_pi != NULL) {
3801 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
3803 col_append_fstr(pinfo->cinfo, COL_INFO,
3804 " [DCE/RPC %s fragment, reas: #%u]", fragment_type(hdr->flags), fd_head->reassembled_in);
3805 expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment_reassembled, "%s fragment, reassembled in #%u", fragment_type(hdr->flags), fd_head->reassembled_in);
3808 /* Reassembly not complete - some fragments
3809 are missing. Just show the stub data. */
3810 expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment, "%s fragment", fragment_type(hdr->flags));
3812 if (decrypted_tvb) {
3813 show_stub_data(decrypted_tvb, 0, tree, auth_info, FALSE);
3815 show_stub_data(payload_tvb, 0, tree, auth_info, TRUE);
3819 pinfo->fragmented = save_fragmented;
3823 dissect_dcerpc_cn_rqst(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3824 proto_tree *dcerpc_tree, proto_tree *tree,
3825 e_dce_cn_common_hdr_t *hdr)
3827 conversation_t *conv;
3830 e_uuid_t obj_id = DCERPC_UUID_NULL;
3831 dcerpc_auth_info auth_info;
3834 proto_item *parent_pi;
3835 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
3837 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3838 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3840 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3841 hf_dcerpc_cn_ctx_id, &ctx_id);
3842 parent_pi = proto_tree_get_parent(dcerpc_tree);
3843 if (parent_pi != NULL) {
3844 proto_item_append_text(parent_pi, ", Ctx: %u", ctx_id);
3847 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3848 hf_dcerpc_opnum, &opnum);
3850 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3851 decode_data->dcectxid = ctx_id;
3853 col_append_fstr(pinfo->cinfo, COL_INFO, ", opnum: %u, Ctx: %u",
3856 if (hdr->flags & PFC_OBJECT_UUID) {
3857 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &obj_id);
3859 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
3860 offset, 16, (e_guid_t *) &obj_id, "Object UUID: %s",
3861 guid_to_str((e_guid_t *) &obj_id));
3867 * XXX - what if this was set when the connection was set up,
3868 * and we just have a security context?
3870 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3872 conv = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3873 pinfo->srcport, pinfo->destport, 0);
3875 show_stub_data(tvb, offset, dcerpc_tree, &auth_info, TRUE);
3877 dcerpc_matched_key matched_key, *new_matched_key;
3878 dcerpc_call_value *value;
3880 /* !!! we can NOT check flags.visited here since this will interact
3881 badly with when SMB handles (i.e. calls the subdissector)
3882 and desegmented pdu's .
3883 Instead we check if this pdu is already in the matched table or not
3885 matched_key.frame = pinfo->fd->num;
3886 matched_key.call_id = hdr->call_id;
3887 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
3889 dcerpc_bind_key bind_key;
3890 dcerpc_bind_value *bind_value;
3892 bind_key.conv = conv;
3893 bind_key.ctx_id = ctx_id;
3894 bind_key.smb_fid = dcerpc_get_transport_salt(pinfo);
3896 if ((bind_value = (dcerpc_bind_value *)g_hash_table_lookup(dcerpc_binds, &bind_key)) ) {
3897 if (!(hdr->flags&PFC_FIRST_FRAG)) {
3898 dcerpc_cn_call_key call_key;
3899 dcerpc_call_value *call_value;
3901 call_key.conv = conv;
3902 call_key.call_id = hdr->call_id;
3903 call_key.smb_fid = dcerpc_get_transport_salt(pinfo);
3904 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_cn_calls, &call_key))) {
3905 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
3906 *new_matched_key = matched_key;
3907 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
3911 dcerpc_cn_call_key *call_key;
3912 dcerpc_call_value *call_value;
3914 /* We found the binding and it is the first fragment
3915 (or a complete PDU) of a dcerpc pdu so just add
3916 the call to both the call table and the
3919 call_key = (dcerpc_cn_call_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_cn_call_key));
3920 call_key->conv = conv;
3921 call_key->call_id = hdr->call_id;
3922 call_key->smb_fid = dcerpc_get_transport_salt(pinfo);
3924 /* if there is already a matching call in the table
3925 remove it so it is replaced with the new one */
3926 if (g_hash_table_lookup(dcerpc_cn_calls, call_key)) {
3927 g_hash_table_remove(dcerpc_cn_calls, call_key);
3930 call_value = (dcerpc_call_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_call_value));
3931 call_value->uuid = bind_value->uuid;
3932 call_value->ver = bind_value->ver;
3933 call_value->object_uuid = obj_id;
3934 call_value->opnum = opnum;
3935 call_value->req_frame = pinfo->fd->num;
3936 call_value->req_time = pinfo->fd->abs_ts;
3937 call_value->rep_frame = 0;
3938 call_value->max_ptr = 0;
3939 call_value->se_data = NULL;
3940 call_value->private_data = NULL;
3941 call_value->pol = NULL;
3942 call_value->flags = 0;
3943 if (!memcmp(&bind_value->transport, &uuid_ndr64, sizeof(uuid_ndr64))) {
3944 call_value->flags |= DCERPC_IS_NDR64;
3947 g_hash_table_insert(dcerpc_cn_calls, call_key, call_value);
3949 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
3950 *new_matched_key = matched_key;
3951 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
3961 /* handoff this call */
3963 di->call_id = hdr->call_id;
3964 di->smb_fid = dcerpc_get_transport_salt(pinfo);
3965 di->ptype = PDU_REQ;
3966 di->call_data = value;
3969 if (value->rep_frame != 0) {
3970 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
3971 tvb, 0, 0, value->rep_frame);
3972 PROTO_ITEM_SET_GENERATED(pi);
3973 if (parent_pi != NULL) {
3974 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
3978 dissect_dcerpc_cn_stub(tvb, offset, pinfo, dcerpc_tree, tree,
3979 hdr, di, &auth_info, alloc_hint,
3982 /* no bind information, simply show stub data */
3983 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);
3984 show_stub_data(tvb, offset, dcerpc_tree, &auth_info, TRUE);
3988 /* Dissect the verifier */
3989 dissect_dcerpc_verifier(tvb, pinfo, dcerpc_tree, hdr, &auth_info);
3994 dissect_dcerpc_cn_resp(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3995 proto_tree *dcerpc_tree, proto_tree *tree,
3996 e_dce_cn_common_hdr_t *hdr)
3998 dcerpc_call_value *value = NULL;
3999 conversation_t *conv;
4001 dcerpc_auth_info auth_info;
4004 proto_item *parent_pi;
4005 e_uuid_t obj_id_null = DCERPC_UUID_NULL;
4006 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
4008 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4009 hf_dcerpc_cn_alloc_hint, &alloc_hint);
4011 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4012 hf_dcerpc_cn_ctx_id, &ctx_id);
4013 parent_pi = proto_tree_get_parent(dcerpc_tree);
4014 if (parent_pi != NULL) {
4015 proto_item_append_text(parent_pi, ", Ctx: %u", ctx_id);
4018 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
4019 decode_data->dcectxid = ctx_id;
4021 col_append_fstr(pinfo->cinfo, COL_INFO, ", Ctx: %u", ctx_id);
4023 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4024 hf_dcerpc_cn_cancel_count, NULL);
4029 * XXX - what if this was set when the connection was set up,
4030 * and we just have a security context?
4032 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
4034 conv = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
4035 pinfo->srcport, pinfo->destport, 0);
4038 /* no point in creating one here, really */
4039 show_stub_data(tvb, offset, dcerpc_tree, &auth_info, TRUE);
4041 dcerpc_matched_key matched_key, *new_matched_key;
4043 /* !!! we can NOT check flags.visited here since this will interact
4044 badly with when SMB handles (i.e. calls the subdissector)
4045 and desegmented pdu's .
4046 Instead we check if this pdu is already in the matched table or not
4048 matched_key.frame = pinfo->fd->num;
4049 matched_key.call_id = hdr->call_id;
4050 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
4052 dcerpc_cn_call_key call_key;
4053 dcerpc_call_value *call_value;
4055 call_key.conv = conv;
4056 call_key.call_id = hdr->call_id;
4057 call_key.smb_fid = dcerpc_get_transport_salt(pinfo);
4059 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_cn_calls, &call_key))) {
4060 /* extra sanity check, only match them if the reply
4061 came after the request */
4062 if (call_value->req_frame<pinfo->fd->num) {
4063 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
4064 *new_matched_key = matched_key;
4065 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
4067 if (call_value->rep_frame == 0) {
4068 call_value->rep_frame = pinfo->fd->num;
4078 /* handoff this call */
4080 di->call_id = hdr->call_id;
4081 di->smb_fid = dcerpc_get_transport_salt(pinfo);
4082 di->ptype = PDU_RESP;
4083 di->call_data = value;
4085 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
4087 /* (optional) "Object UUID" from request */
4088 if (dcerpc_tree && (memcmp(&value->object_uuid, &obj_id_null, sizeof(obj_id_null)) != 0)) {
4089 pi = proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
4090 offset, 0, (e_guid_t *) &value->object_uuid, "Object UUID: %s",
4091 guid_to_str((e_guid_t *) &value->object_uuid));
4092 PROTO_ITEM_SET_GENERATED(pi);
4096 if (value->req_frame != 0) {
4098 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4099 tvb, 0, 0, value->req_frame);
4100 PROTO_ITEM_SET_GENERATED(pi);
4101 if (parent_pi != NULL) {
4102 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
4104 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
4105 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
4106 PROTO_ITEM_SET_GENERATED(pi);
4108 proto_tree_add_expert(dcerpc_tree, pinfo, &ei_dcerpc_no_request_found, tvb, 0, 0);
4111 dissect_dcerpc_cn_stub(tvb, offset, pinfo, dcerpc_tree, tree,
4112 hdr, di, &auth_info, alloc_hint,
4115 /* no bind information, simply show stub data */
4116 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);
4117 show_stub_data(tvb, offset, dcerpc_tree, &auth_info, TRUE);
4121 /* Dissect the verifier */
4122 dissect_dcerpc_verifier(tvb, pinfo, dcerpc_tree, hdr, &auth_info);
4126 dissect_dcerpc_cn_fault(tvbuff_t *tvb, gint offset, packet_info *pinfo,
4127 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
4129 dcerpc_call_value *value = NULL;
4130 conversation_t *conv;
4134 dcerpc_auth_info auth_info;
4135 proto_item *pi = NULL;
4136 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
4138 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4139 hf_dcerpc_cn_alloc_hint, &alloc_hint);
4141 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4142 hf_dcerpc_cn_ctx_id, &ctx_id);
4144 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4145 hf_dcerpc_cn_cancel_count, NULL);
4150 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4151 hf_dcerpc_cn_status, &status);
4153 status = ((hdr->drep[0] & DREP_LITTLE_ENDIAN)
4154 ? tvb_get_letohl(tvb, offset)
4155 : tvb_get_ntohl(tvb, offset));
4157 pi = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_status, tvb, offset, 4, DREP_ENC_INTEGER(hdr->drep));
4160 expert_add_info_format(pinfo, pi, &ei_dcerpc_cn_status, "Fault: %s", val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
4162 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
4163 decode_data->dcectxid = ctx_id;
4165 col_append_fstr(pinfo->cinfo, COL_INFO,
4166 ", Ctx: %u, status: %s", ctx_id,
4167 val_to_str(status, reject_status_vals,
4168 "Unknown (0x%08x)"));
4174 * XXX - what if this was set when the connection was set up,
4175 * and we just have a security context?
4177 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
4179 conv = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
4180 pinfo->srcport, pinfo->destport, 0);
4182 /* no point in creating one here, really */
4184 dcerpc_matched_key matched_key, *new_matched_key;
4186 /* !!! we can NOT check flags.visited here since this will interact
4187 badly with when SMB handles (i.e. calls the subdissector)
4188 and desegmented pdu's .
4189 Instead we check if this pdu is already in the matched table or not
4191 matched_key.frame = pinfo->fd->num;
4192 matched_key.call_id = hdr->call_id;
4193 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
4195 dcerpc_cn_call_key call_key;
4196 dcerpc_call_value *call_value;
4198 call_key.conv = conv;
4199 call_key.call_id = hdr->call_id;
4200 call_key.smb_fid = dcerpc_get_transport_salt(pinfo);
4202 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_cn_calls, &call_key))) {
4203 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
4204 *new_matched_key = matched_key;
4205 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
4208 if (call_value->rep_frame == 0) {
4209 call_value->rep_frame = pinfo->fd->num;
4216 int length, stub_length;
4218 proto_item *parent_pi;
4221 /* handoff this call */
4223 di->call_id = hdr->call_id;
4224 di->smb_fid = dcerpc_get_transport_salt(pinfo);
4225 di->ptype = PDU_FAULT;
4226 di->call_data = value;
4228 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
4229 if (value->req_frame != 0) {
4231 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4232 tvb, 0, 0, value->req_frame);
4233 PROTO_ITEM_SET_GENERATED(pi);
4234 parent_pi = proto_tree_get_parent(dcerpc_tree);
4235 if (parent_pi != NULL) {
4236 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
4238 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
4239 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
4240 PROTO_ITEM_SET_GENERATED(pi);
4242 proto_tree_add_expert(dcerpc_tree, pinfo, &ei_dcerpc_no_request_found, tvb, 0, 0);
4245 length = tvb_length_remaining(tvb, offset);
4246 /* as we now create a tvb in dissect_dcerpc_cn() containing only the
4247 * stub_data, the following calculation is no longer valid:
4248 * stub_length = hdr->frag_len - offset - auth_info.auth_size;
4249 * simply use the remaining length of the tvb instead.
4250 * XXX - or better use the reported_length?!?
4252 stub_length = length;
4253 if (length > stub_length)
4254 length = stub_length;
4256 /* If we don't have reassembly enabled, or this packet contains
4257 the entire PDU, or if we don't have all the data in this
4258 fragment, just call the handoff directly if this is the
4259 first fragment or the PDU isn't fragmented. */
4260 if ( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
4261 !tvb_bytes_exist(tvb, offset, stub_length) ) {
4262 if (hdr->flags&PFC_FIRST_FRAG) {
4263 /* First fragment, possibly the only fragment */
4265 * XXX - should there be a third routine for each
4266 * function in an RPC subdissector, to handle
4267 * fault responses? The DCE RPC 1.1 spec says
4268 * three's "stub data" here, which I infer means
4269 * that it's protocol-specific and call-specific.
4271 * It should probably get passed the status code
4272 * as well, as that might be protocol-specific.
4275 if (stub_length > 0) {
4276 tvb_ensure_bytes_exist(tvb, offset, stub_length);
4277 proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
4278 "Fault stub data (%d byte%s)",
4280 plurality(stub_length, "", "s"));
4284 /* PDU is fragmented and this isn't the first fragment */
4286 if (stub_length > 0) {
4287 tvb_ensure_bytes_exist(tvb, offset, stub_length);
4288 proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
4289 "Fragment data (%d byte%s)",
4291 plurality(stub_length, "", "s"));
4296 /* Reassembly is enabled, the PDU is fragmented, and
4297 we have all the data in the fragment; the first two
4298 of those mean we should attempt reassembly, and the
4299 third means we can attempt reassembly. */
4302 tvb_ensure_bytes_exist(tvb, offset, stub_length);
4303 proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
4304 "Fragment data (%d byte%s)",
4306 plurality(stub_length, "", "s"));
4309 if (hdr->flags&PFC_FIRST_FRAG) { /* FIRST fragment */
4310 if ( (!pinfo->fd->flags.visited) && value->rep_frame ) {
4311 fragment_add_seq_next(&dcerpc_co_reassembly_table,
4313 pinfo, value->rep_frame, NULL,
4317 } else if (hdr->flags&PFC_LAST_FRAG) { /* LAST fragment */
4318 if ( value->rep_frame ) {
4319 fragment_head *fd_head;
4321 fd_head = fragment_add_seq_next(&dcerpc_co_reassembly_table,
4323 pinfo, value->rep_frame, NULL,
4328 /* We completed reassembly */
4330 proto_item *frag_tree_item;
4332 next_tvb = tvb_new_chain(tvb, fd_head->tvb_data);
4333 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
4334 show_fragment_tree(fd_head, &dcerpc_frag_items,
4335 dcerpc_tree, pinfo, next_tvb, &frag_tree_item);
4338 * XXX - should there be a third routine for each
4339 * function in an RPC subdissector, to handle
4340 * fault responses? The DCE RPC 1.1 spec says
4341 * three's "stub data" here, which I infer means
4342 * that it's protocol-specific and call-specific.
4344 * It should probably get passed the status code
4345 * as well, as that might be protocol-specific.
4349 tvb_ensure_bytes_exist(tvb, offset, stub_length);
4350 proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
4351 "Fault stub data (%d byte%s)",
4353 plurality(stub_length, "", "s"));
4358 } else { /* MIDDLE fragment(s) */
4359 if ( (!pinfo->fd->flags.visited) && value->rep_frame ) {
4360 fragment_add_seq_next(&dcerpc_co_reassembly_table,
4362 pinfo, value->rep_frame, NULL,
4373 dissect_dcerpc_cn_rts(tvbuff_t *tvb, gint offset, packet_info *pinfo,
4374 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
4376 proto_item *tf = NULL;
4377 proto_item *parent_pi = NULL;
4378 proto_tree *cn_rts_pdu_tree = NULL;
4380 guint16 commands_nb = 0;
4383 const char *info_str = NULL;
4385 /* Dissect specific RTS header */
4386 rts_flags = dcerpc_tvb_get_ntohs(tvb, offset, hdr->drep);
4388 proto_tree *cn_rts_flags_tree;
4390 tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_rts_flags, tvb, offset, 2, rts_flags);
4391 cn_rts_flags_tree = proto_item_add_subtree(tf, ett_dcerpc_cn_rts_flags);
4392 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_none, tvb, offset, 1, rts_flags);
4393 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_ping, tvb, offset, 1, rts_flags);
4394 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_other_cmd, tvb, offset, 1, rts_flags);
4395 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_recycle_channel, tvb, offset, 1, rts_flags);
4396 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_in_channel, tvb, offset, 1, rts_flags);
4397 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_out_channel, tvb, offset, 1, rts_flags);
4398 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_eof, tvb, offset, 1, rts_flags);
4402 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4403 hf_dcerpc_cn_rts_commands_nb, &commands_nb);
4405 /* Create the RTS PDU tree - we do not yet know its name */
4406 tf = proto_tree_add_text(dcerpc_tree, tvb, offset, tvb_length_remaining(tvb, offset), "RTS PDU: %u commands", commands_nb);
4407 cn_rts_pdu_tree = proto_item_add_subtree(tf, ett_dcerpc_cn_rts_pdu);
4409 cmd = (guint32 *)wmem_alloc(wmem_packet_scope(), sizeof (guint32) * (commands_nb + 1));
4411 /* Dissect commands */
4412 for (i = 0; i < commands_nb; ++i) {
4413 proto_tree *cn_rts_command_tree = NULL;
4414 const guint32 command = dcerpc_tvb_get_ntohl(tvb, offset, hdr->drep);
4416 tf = proto_tree_add_uint(cn_rts_pdu_tree, hf_dcerpc_cn_rts_command, tvb, offset, 4, command);
4417 cn_rts_command_tree = proto_item_add_subtree(tf, ett_dcerpc_cn_rts_command);
4420 case RTS_CMD_RECEIVEWINDOWSIZE:
4421 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_receivewindowsize, NULL);
4423 case RTS_CMD_FLOWCONTROLACK:
4424 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_fack_bytesreceived, NULL);
4425 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_fack_availablewindow, NULL);
4426 offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_fack_channelcookie, NULL);
4428 case RTS_CMD_CONNECTIONTIMEOUT:
4429 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_connectiontimeout, NULL);
4431 case RTS_CMD_COOKIE:
4432 offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_cookie, NULL);
4434 case RTS_CMD_CHANNELLIFETIME:
4435 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_channellifetime, NULL);
4437 case RTS_CMD_CLIENTKEEPALIVE:
4438 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_clientkeepalive, NULL);
4440 case RTS_CMD_VERSION:
4441 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_version, NULL);
4445 case RTS_CMD_PADDING: {
4447 const guint32 conformance_count = dcerpc_tvb_get_ntohl(tvb, offset, hdr->drep);
4448 proto_tree_add_uint(cn_rts_command_tree, hf_dcerpc_cn_rts_command_conformancecount, tvb, offset, 4, conformance_count);
4450 padding = (guint8 *)tvb_memdup(NULL, tvb, offset, conformance_count);
4451 proto_tree_add_bytes(cn_rts_command_tree, hf_dcerpc_cn_rts_command_padding, tvb, offset, conformance_count, padding);
4452 offset += conformance_count;
4454 case RTS_CMD_NEGATIVEANCE:
4458 case RTS_CMD_CLIENTADDRESS: {
4460 const guint32 addrtype = dcerpc_tvb_get_ntohl(tvb, offset, hdr->drep);
4461 proto_tree_add_uint(cn_rts_command_tree, hf_dcerpc_cn_rts_command_addrtype, tvb, offset, 4, addrtype);
4465 const guint32 addr4 = tvb_get_ipv4(tvb, offset);
4466 proto_tree_add_text(cn_rts_command_tree, tvb, offset, 4, "%s", get_hostname(addr4));
4470 struct e_in6_addr addr6;
4471 tvb_get_ipv6(tvb, offset, &addr6);
4472 proto_tree_add_text(cn_rts_command_tree, tvb, offset, 16, "%s", get_hostname6(&addr6));
4476 padding = (guint8 *)tvb_memdup(NULL, tvb, offset, 12);
4477 proto_tree_add_bytes(cn_rts_command_tree, hf_dcerpc_cn_rts_command_padding, tvb, offset, 12, padding);
4480 case RTS_CMD_ASSOCIATIONGROUPID:
4481 offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_associationgroupid, NULL);
4483 case RTS_CMD_DESTINATION:
4484 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_forwarddestination, NULL);
4486 case RTS_CMD_PINGTRAFFICSENTNOTIFY:
4487 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_pingtrafficsentnotify, NULL);
4490 proto_tree_add_text(cn_rts_command_tree, tvb, offset, 0, "unknown RTS command number");
4495 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RPCH");
4497 /* Define which PDU Body we are dealing with */
4498 info_str = "unknown RTS PDU";
4500 switch (rts_flags) {
4502 switch (commands_nb) {
4504 if (cmd[0] == 0x2) {
4505 info_str = "CONN/A3";
4506 } else if (cmd[0] == 0x3) {
4507 info_str = "IN_R1/A5,IN_R1/A6,IN_R2/A2,IN_R2/A5,OUT_R2/A4";
4508 } else if (cmd[0] == 0x7) {
4509 info_str = "IN_R1/B1";
4510 } else if (cmd[0] == 0x0) {
4511 info_str = "IN_R1/B2";
4512 } else if (cmd[0] == 0xD) {
4513 info_str = "IN_R2/A3,IN_R2/A4";
4514 } else if (cmd[0] == 0xA) {
4515 info_str = "OUT_R1/A9,OUT_R1/A10,OUT_R1/A11,OUT_R2/B1,OUT_R2/B2";
4519 if ((cmd[0] == 0x0) && (cmd[1] == 0x6)) {
4520 info_str = "CONN/B3";
4521 } else if ((cmd[0] == 0xD) && (cmd[1] == 0xA)) {
4522 info_str = "OUT_R2/A5,OUT_R2/A6";
4526 if ((cmd[0] == 0x6) && (cmd[1] == 0x0) && (cmd[2] == 0x2)) {
4527 info_str = "CONN/C1,CONN/C2";
4531 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x0)) {
4532 info_str = "CONN/A1";
4533 } else if ((cmd[0] == 0xD) && (cmd[1] == 0x6) && (cmd[2] == 0x0) && (cmd[3] == 0x2)) {
4534 info_str = "IN_R1/A3,IN_R1/A4";
4538 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x4) && (cmd[4] == 0x5) && (cmd[5] == 0xC)) {
4539 info_str = "CONN/B1";
4547 switch (commands_nb) {
4552 if ((cmd[0] == 0x7) || (cmd[0] == 0x8)) {
4553 info_str = "OUT_R2/C1";
4560 case RTS_FLAG_OTHER_CMD:
4561 switch (commands_nb) {
4563 if (cmd[0] == 0x5) {
4564 info_str = "Keep-Alive";
4565 } else if (cmd[0] == 0xE) {
4566 info_str = "PingTrafficSentNotify";
4567 } else if (cmd[0] == 0x1) {
4568 info_str = "FlowControlAck";
4572 if ((cmd[0] == 0xD) && (cmd[1] == 0x1)) {
4573 info_str = "FlowControlAckWithDestination";
4580 case RTS_FLAG_RECYCLE_CHANNEL:
4581 switch (commands_nb) {
4583 if (cmd[0] == 0xD) {
4584 info_str = "OUT_R1/A1,OUT_R1/A2,OUT_R2/A1,OUT_R2/A2";
4588 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3)) {
4589 info_str = "IN_R1/A1,IN_R2/A1";
4593 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3) && (cmd[4] == 0x0)) {
4594 info_str = "OUT_R1/A3,OUT_R2/A3";
4601 case RTS_FLAG_IN_CHANNEL|RTS_FLAG_RECYCLE_CHANNEL:
4602 switch (commands_nb) {
4604 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3) && (cmd[4] == 0x0) && (cmd[5] == 0x2)) {
4605 info_str = "IN_R1/A2";
4611 case RTS_FLAG_IN_CHANNEL:
4612 switch (commands_nb) {
4614 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x0) && (cmd[4] == 0x2) && (cmd[5] == 0xC) && (cmd[6] == 0xB)) {
4615 info_str = "CONN/B2";
4621 case RTS_FLAG_OUT_CHANNEL|RTS_FLAG_RECYCLE_CHANNEL:
4622 switch (commands_nb) {
4624 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3) && (cmd[4] == 0x4) && (cmd[5] == 0) && (cmd[6] == 0x2)) {
4625 info_str = "OUT_R1/A4";
4632 case RTS_FLAG_OUT_CHANNEL:
4633 switch (commands_nb) {
4635 if ((cmd[0] == 0xD) && (cmd[1] == 0x3)) {
4636 info_str = "OUT_R1/A7,OUT_R1/A8,OUT_R2/A8";
4640 if ((cmd[0] == 0xD) && (cmd[1] == 0x6) && (cmd[2] == 0x2)) {
4641 info_str = "OUT_R1/A5,OUT_R1/A6";
4642 } else if ((cmd[0] == 0xD) && (cmd[1] == 0x3) && (cmd[2] == 0x6)) {
4643 info_str = "OUT_R2/A7";
4647 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x4) && (cmd[4] == 0x0)) {
4648 info_str = "CONN/A2";
4655 switch (commands_nb) {
4657 if (cmd[0] == 0xA) {
4658 info_str = "OUT_R2/B3";
4666 switch (commands_nb) {
4678 col_add_fstr(pinfo->cinfo, COL_INFO, "%s, ", info_str);
4679 col_set_fence(pinfo->cinfo,COL_INFO);
4681 parent_pi = proto_tree_get_parent(dcerpc_tree);
4682 if (parent_pi != NULL) {
4683 proto_item_append_text(parent_pi, ", %s", info_str);
4688 * DCERPC dissector for connection oriented calls.
4689 * We use transport type to later multiplex between what kind of
4690 * pinfo->private_data structure to expect.
4693 dissect_dcerpc_cn(tvbuff_t *tvb, int offset, packet_info *pinfo,
4694 proto_tree *tree, gboolean can_desegment, int *pkt_len)
4696 static const guint8 nulls[4] = { 0 };
4700 proto_item *ti = NULL;
4701 proto_item *tf = NULL;
4702 proto_tree *dcerpc_tree = NULL;
4703 proto_tree *cn_flags_tree = NULL;
4704 proto_tree *drep_tree = NULL;
4705 e_dce_cn_common_hdr_t hdr;
4706 dcerpc_auth_info auth_info;
4707 tvbuff_t *fragment_tvb;
4708 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
4711 * when done over nbt, dcerpc requests are padded with 4 bytes of null
4712 * data for some reason.
4714 * XXX - if that's always the case, the right way to do this would
4715 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
4716 * the 4 bytes of null padding, and make that the dissector
4717 * used for "netbios".
4719 if (tvb_memeql(tvb, offset, nulls, 4) == 0) {
4728 * Check if this looks like a C/O DCERPC call
4730 if (!tvb_bytes_exist(tvb, offset, sizeof (hdr))) {
4731 return FALSE; /* not enough information to check */
4733 start_offset = offset;
4734 hdr.rpc_ver = tvb_get_guint8(tvb, offset++);
4735 if (hdr.rpc_ver != 5)
4737 hdr.rpc_ver_minor = tvb_get_guint8(tvb, offset++);
4738 if ((hdr.rpc_ver_minor != 0) && (hdr.rpc_ver_minor != 1))
4740 hdr.ptype = tvb_get_guint8(tvb, offset++);
4741 if (hdr.ptype > PDU_RTS)
4744 hdr.flags = tvb_get_guint8(tvb, offset++);
4745 tvb_memcpy(tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
4746 offset += (int)sizeof (hdr.drep);
4748 hdr.frag_len = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
4750 hdr.auth_len = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
4752 hdr.call_id = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
4755 if (decode_data->dcectxid == 0) {
4756 col_append_fstr(pinfo->cinfo, COL_DCE_CALL, "%u", hdr.call_id);
4758 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
4759 * prepend a delimiter */
4760 col_append_fstr(pinfo->cinfo, COL_DCE_CALL, "#%u", hdr.call_id);
4763 if (can_desegment && pinfo->can_desegment
4764 && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
4765 pinfo->desegment_offset = start_offset;
4766 pinfo->desegment_len = hdr.frag_len - tvb_length_remaining(tvb, start_offset);
4767 *pkt_len = 0; /* desegmentation required */
4771 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCERPC");
4773 if (decode_data->dcectxid != 0) {
4774 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
4775 * append a delimiter and set a column fence */
4776 col_append_str(pinfo->cinfo, COL_INFO, " # ");
4777 col_set_fence(pinfo->cinfo,COL_INFO);
4779 col_add_fstr(pinfo->cinfo, COL_INFO, "%s: call_id: %u",
4780 pckt_vals[hdr.ptype].strptr, hdr.call_id);
4782 if (decode_data->dcectxid != 0) {
4783 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU */
4784 expert_add_info(pinfo, NULL, &ei_dcerpc_fragment_multiple);
4787 offset = start_offset;
4788 tvb_ensure_bytes_exist(tvb, offset, 16);
4790 ti = proto_tree_add_item(tree, proto_dcerpc, tvb, offset, hdr.frag_len, ENC_NA);
4791 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
4794 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
4797 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset, 1, hdr.rpc_ver_minor);
4800 tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
4803 #if 0 /* XXX - too much "output noise", removed for now */
4804 if (hdr.ptype == PDU_BIND || hdr.ptype == PDU_ALTER ||
4805 hdr.ptype == PDU_BIND_ACK || hdr.ptype == PDU_ALTER_ACK)
4806 expert_add_info_format(pinfo, tf, &ei_dcerpc_context_change, "Context change: %s", val_to_str(hdr.ptype, pckt_vals, "(0x%x)"));
4808 if (hdr.ptype == PDU_BIND_NAK)
4809 expert_add_info(pinfo, tf, &ei_dcerpc_bind_not_acknowledged);
4812 proto_item_append_text(ti, " %s, Fragment: %s",
4813 val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"),
4814 fragment_type(hdr.flags));
4816 tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
4817 cn_flags_tree = proto_item_add_subtree(tf, ett_dcerpc_cn_flags);
4819 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
4820 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
4821 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
4822 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
4823 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
4824 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
4825 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
4826 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
4829 col_append_fstr(pinfo->cinfo, COL_INFO, ", Fragment: %s", fragment_type(hdr.flags));
4832 tf = proto_tree_add_bytes(dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
4833 drep_tree = proto_item_add_subtree(tf, ett_dcerpc_drep);
4835 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
4836 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
4837 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
4838 offset += (int)sizeof (hdr.drep);
4840 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
4843 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
4846 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
4850 proto_item_append_text(ti, ", FragLen: %u, Call: %u", hdr.frag_len, hdr.call_id);
4854 * None of the stuff done above should throw an exception, because
4855 * we would have rejected this as "not DCE RPC" if we didn't have all
4856 * of it. (XXX - perhaps we should request reassembly if we have
4857 * enough of the header to consider it DCE RPC but not enough to
4858 * get the fragment length; in that case the stuff still wouldn't
4859 * throw an exception.)
4861 * The rest of the stuff might, so return the PDU length to our caller.
4862 * XXX - should we construct a tvbuff containing only the PDU and
4863 * use that? Or should we have separate "is this a DCE RPC PDU",
4864 * "how long is it", and "dissect it" routines - which might let us
4865 * do most of the work in "tcp_dissect_pdus()"?
4867 if (pkt_len != NULL)
4868 *pkt_len = hdr.frag_len + padding;
4870 /* The remaining bytes in the current tvb might contain multiple
4871 * DCE/RPC fragments, so create a new tvb subset for this fragment.
4872 * Only limit the end of the fragment, but not the offset start,
4873 * as the authentication function dissect_dcerpc_cn_auth() will fail
4874 * (and other functions might fail as well) computing the right start
4877 subtvb_len = MIN(hdr.frag_len, tvb_length(tvb));
4878 fragment_tvb = tvb_new_subset(tvb, start_offset,
4879 subtvb_len /* length */,
4880 hdr.frag_len /* reported_length */);
4883 * Packet type specific stuff is next.
4885 switch (hdr.ptype) {
4888 dissect_dcerpc_cn_bind(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
4893 dissect_dcerpc_cn_bind_ack(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
4898 * Nothing after the common header other than credentials.
4900 dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr, TRUE,
4905 dissect_dcerpc_cn_rqst(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, tree, &hdr);
4909 dissect_dcerpc_cn_resp(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, tree, &hdr);
4913 dissect_dcerpc_cn_fault(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
4917 dissect_dcerpc_cn_bind_nak(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
4923 * Nothing after the common header other than an authentication
4926 dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr, FALSE,
4932 * Nothing after the common header, not even an authentication
4937 dissect_dcerpc_cn_rts(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
4941 /* might as well dissect the auth info */
4942 dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr, FALSE,
4950 * DCERPC dissector for connection oriented calls over packet-oriented
4954 dissect_dcerpc_cn_pk(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
4956 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
4959 * Only one PDU per transport packet, and only one transport
4962 decode_data->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
4963 if (!dissect_dcerpc_cn(tvb, 0, pinfo, tree, FALSE, NULL)) {
4965 * It wasn't a DCERPC PDU.
4977 * DCERPC dissector for connection oriented calls over byte-stream
4979 * we need to distinguish here between SMB and non-TCP (more in the future?)
4980 * to be able to know what kind of private_data structure to expect.
4983 dissect_dcerpc_cn_bs_body(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4985 volatile int offset = 0;
4987 volatile int dcerpc_pdus = 0;
4988 volatile gboolean ret = FALSE;
4991 * There may be multiple PDUs per transport packet; keep
4994 while (tvb_reported_length_remaining(tvb, offset) != 0) {
4997 if (dissect_dcerpc_cn(tvb, offset, pinfo, tree,
4998 dcerpc_cn_desegment, &pdu_len)) {
5001 } CATCH_NONFATAL_ERRORS {
5003 * Somebody threw an exception that means that there
5004 * was a problem dissecting the payload; that means
5005 * that a dissector was found, so we don't need to
5006 * dissect the payload as data or update the protocol
5009 * Just show the exception and then continue dissecting
5012 show_exception(tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
5014 * Presumably it looked enough like a DCE RPC PDU that we
5015 * dissected enough of it to throw an exception.
5020 if (dcerpc_pdus == 0) {
5021 gboolean try_desegment = FALSE;
5022 if (dcerpc_cn_desegment && pinfo->can_desegment &&
5023 !tvb_bytes_exist(tvb, offset, sizeof(e_dce_cn_common_hdr_t))) {
5024 /* look for a previous occurence of the DCE-RPC protocol */
5025 wmem_list_frame_t *cur;
5026 cur = wmem_list_frame_prev(wmem_list_tail(pinfo->layers));
5027 while (cur != NULL) {
5028 if (proto_dcerpc == (gint)GPOINTER_TO_UINT(wmem_list_frame_data(cur))) {
5029 try_desegment = TRUE;
5032 cur = wmem_list_frame_prev(cur);
5036 if (try_desegment) {
5037 /* It didn't look like DCE-RPC but we already had one DCE-RPC
5038 * layer in this packet and what we have is short. Assume that
5039 * it was just too short to tell and ask the TCP layer for more
5041 pinfo->desegment_offset = offset;
5042 pinfo->desegment_len = (guint32)(sizeof(e_dce_cn_common_hdr_t) - tvb_length_remaining(tvb, offset));
5044 /* Really not DCE-RPC */
5050 * Well, we've seen at least one DCERPC PDU.
5054 /* if we had more than one Req/Resp in this PDU change the protocol column */
5055 /* this will formerly contain the last interface name, which may not be the same for all Req/Resp */
5056 if (dcerpc_pdus >= 2)
5057 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "%u*DCERPC", dcerpc_pdus);
5061 * Desegmentation required - bail now, but give the user a hint that desegmentation might be done later.
5063 proto_tree_add_uint_format(tree, hf_dcerpc_cn_deseg_req, tvb, offset,
5065 tvb_reported_length_remaining(tvb, offset),
5066 "[DCE RPC: %u byte%s left, desegmentation might follow]",
5067 tvb_reported_length_remaining(tvb, offset),
5068 plurality(tvb_reported_length_remaining(tvb, offset), "", "s"));
5073 * Step to the next PDU.
5081 dissect_dcerpc_cn_bs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5083 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
5085 decode_data->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
5086 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
5090 dissect_dcerpc_cn_smbpipe(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5092 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
5094 decode_data->dcetransporttype = DCE_CN_TRANSPORT_SMBPIPE;
5095 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
5099 dissect_dcerpc_cn_smb2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5101 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
5103 decode_data->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
5104 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
5110 dissect_dcerpc_dg_auth(tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
5111 e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
5113 proto_item *ti = NULL;
5114 proto_tree *auth_tree = NULL;
5115 guint8 protection_level;
5118 * Initially set "*auth_level_p" to -1 to indicate that we haven't
5119 * yet seen any authentication level information.
5121 if (auth_level_p != NULL)
5125 * The authentication information is at the *end* of the PDU; in
5126 * request and response PDUs, the request and response stub data
5129 * If the full packet is here, and there's data past the end of the
5130 * packet body, then dissect the auth info.
5132 offset += hdr->frag_len;
5133 if (tvb_length_remaining(tvb, offset) > 0) {
5134 switch (hdr->auth_proto) {
5136 case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
5137 ti = proto_tree_add_text(dcerpc_tree, tvb, offset, -1, "Kerberos authentication verifier");
5138 auth_tree = proto_item_add_subtree(ti, ett_dcerpc_krb5_auth_verf);
5139 protection_level = tvb_get_guint8(tvb, offset);
5140 if (auth_level_p != NULL)
5141 *auth_level_p = protection_level;
5142 proto_tree_add_uint(auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
5144 proto_tree_add_item(auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, ENC_BIG_ENDIAN);
5146 if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
5147 offset += 6; /* 6 bytes of padding */
5149 offset += 2; /* 2 bytes of padding */
5150 proto_tree_add_item(auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, ENC_NA);
5155 proto_tree_add_text(dcerpc_tree, tvb, offset, -1, "Authentication verifier");
5162 dissect_dcerpc_dg_cancel_ack(tvbuff_t *tvb, int offset, packet_info *pinfo,
5163 proto_tree *dcerpc_tree,
5164 e_dce_dg_common_hdr_t *hdr)
5168 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5169 hdr->drep, hf_dcerpc_dg_cancel_vers,
5175 /* The only version we know about */
5176 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5177 hdr->drep, hf_dcerpc_dg_cancel_id,
5179 /*offset = */dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
5180 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
5187 dissect_dcerpc_dg_cancel(tvbuff_t *tvb, int offset, packet_info *pinfo,
5188 proto_tree *dcerpc_tree,
5189 e_dce_dg_common_hdr_t *hdr)
5193 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5194 hdr->drep, hf_dcerpc_dg_cancel_vers,
5200 /* The only version we know about */
5201 /*offset = */dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5202 hdr->drep, hf_dcerpc_dg_cancel_id,
5204 /* XXX - are NDR Booleans 32 bits? */
5206 /* XXX - the RPC reference in chapter: "the cancel PDU" doesn't mention
5207 the accepting_cancels field (it's only in the cancel_ack PDU)! */
5208 /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
5209 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
5216 dissect_dcerpc_dg_fack(tvbuff_t *tvb, int offset, packet_info *pinfo,
5217 proto_tree *dcerpc_tree,
5218 e_dce_dg_common_hdr_t *hdr)
5225 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
5226 hdr->drep, hf_dcerpc_dg_fack_vers,
5233 case 0: /* The only version documented in the DCE RPC 1.1 spec */
5234 case 1: /* This appears to be the same */
5235 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
5236 hdr->drep, hf_dcerpc_dg_fack_window_size,
5238 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5239 hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
5241 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5242 hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
5244 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
5245 hdr->drep, hf_dcerpc_dg_fack_serial_num,
5247 col_append_fstr(pinfo->cinfo, COL_INFO, " serial: %u",
5249 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
5250 hdr->drep, hf_dcerpc_dg_fack_selack_len,
5252 for (i = 0; i < selack_len; i++) {
5253 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5254 hdr->drep, hf_dcerpc_dg_fack_selack,
5263 dissect_dcerpc_dg_reject_fault(tvbuff_t *tvb, int offset, packet_info *pinfo,
5264 proto_tree *dcerpc_tree,
5265 e_dce_dg_common_hdr_t *hdr)
5269 /*offset = */dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5270 hdr->drep, hf_dcerpc_dg_status,
5273 col_append_fstr (pinfo->cinfo, COL_INFO,
5275 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
5279 dissect_dcerpc_dg_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
5280 proto_tree *dcerpc_tree, proto_tree *tree,
5281 e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
5283 int length, reported_length, stub_length;
5284 gboolean save_fragmented;
5285 fragment_head *fd_head;
5288 proto_item *parent_pi;
5290 col_append_fstr(pinfo->cinfo, COL_INFO, " opnum: %u len: %u",
5291 di->call_data->opnum, hdr->frag_len );
5293 length = tvb_length_remaining(tvb, offset);
5294 reported_length = tvb_reported_length_remaining(tvb, offset);
5295 stub_length = hdr->frag_len;
5296 if (length > stub_length)
5297 length = stub_length;
5298 if (reported_length > stub_length)
5299 reported_length = stub_length;
5301 save_fragmented = pinfo->fragmented;
5303 /* If we don't have reassembly enabled, or this packet contains
5304 the entire PDU, or if this is a short frame (or a frame
5305 not reassembled at a lower layer) that doesn't include all
5306 the data in the fragment, just call the handoff directly if
5307 this is the first fragment or the PDU isn't fragmented. */
5308 if ( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
5309 !tvb_bytes_exist(tvb, offset, stub_length) ) {
5310 if (hdr->frag_num == 0) {
5313 /* First fragment, possibly the only fragment */
5316 * XXX - authentication info?
5318 pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
5319 next_tvb = tvb_new_subset(tvb, offset, length,
5321 dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb,
5322 next_tvb, hdr->drep, di, NULL);
5324 /* PDU is fragmented and this isn't the first fragment */
5327 tvb_ensure_bytes_exist(tvb, offset, stub_length);
5328 proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
5329 "Fragment data (%d byte%s)",
5331 plurality(stub_length, "", "s"));
5336 /* Reassembly is enabled, the PDU is fragmented, and
5337 we have all the data in the fragment; the first two
5338 of those mean we should attempt reassembly, and the
5339 third means we can attempt reassembly. */
5342 tvb_ensure_bytes_exist(tvb, offset, stub_length);
5343 proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
5344 "Fragment data (%d byte%s)", stub_length,
5345 plurality(stub_length, "", "s"));
5349 fd_head = fragment_add_seq(&dcerpc_cl_reassembly_table,
5351 pinfo, hdr->seqnum, (void *)hdr,
5352 hdr->frag_num, stub_length,
5353 !(hdr->flags1 & PFCL1_LASTFRAG), 0);
5354 if (fd_head != NULL) {
5355 /* We completed reassembly... */
5356 if (pinfo->fd->num == fd_head->reassembled_in) {
5357 /* ...and this is the reassembled RPC PDU */
5358 next_tvb = tvb_new_chain(tvb, fd_head->tvb_data);
5359 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
5360 show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
5361 tree, pinfo, next_tvb, &pi);
5364 * XXX - authentication info?
5366 pinfo->fragmented = FALSE;
5367 dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb,
5368 next_tvb, hdr->drep, di, NULL);
5370 /* ...and this isn't the reassembled RPC PDU */
5371 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
5372 tvb, 0, 0, fd_head->reassembled_in);
5373 PROTO_ITEM_SET_GENERATED(pi);
5374 parent_pi = proto_tree_get_parent(dcerpc_tree);
5375 if (parent_pi != NULL) {
5376 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
5378 col_append_fstr(pinfo->cinfo, COL_INFO,
5379 " [DCE/RPC fragment, reas: #%u]", fd_head->reassembled_in);
5383 pinfo->fragmented = save_fragmented;
5387 dissect_dcerpc_dg_rqst(tvbuff_t *tvb, int offset, packet_info *pinfo,
5388 proto_tree *dcerpc_tree, proto_tree *tree,
5389 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
5392 dcerpc_call_value *value, v;
5393 dcerpc_matched_key matched_key, *new_matched_key;
5395 proto_item *parent_pi;
5398 if (!(pinfo->fd->flags.visited)) {
5399 dcerpc_call_value *call_value;
5400 dcerpc_dg_call_key *call_key;
5402 call_key = (dcerpc_dg_call_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_dg_call_key));
5403 call_key->conv = conv;
5404 call_key->seqnum = hdr->seqnum;
5405 call_key->act_id = hdr->act_id;
5407 call_value = (dcerpc_call_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_call_value));
5408 call_value->uuid = hdr->if_id;
5409 call_value->ver = hdr->if_ver;
5410 call_value->object_uuid = hdr->obj_id;
5411 call_value->opnum = hdr->opnum;
5412 call_value->req_frame = pinfo->fd->num;
5413 call_value->req_time = pinfo->fd->abs_ts;
5414 call_value->rep_frame = 0;
5415 call_value->max_ptr = 0;
5416 call_value->se_data = NULL;
5417 call_value->private_data = NULL;
5418 call_value->pol = NULL;
5419 /* NDR64 is not available on dg transports ?*/
5420 call_value->flags = 0;
5422 g_hash_table_insert(dcerpc_dg_calls, call_key, call_value);
5424 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof(dcerpc_matched_key));
5425 new_matched_key->frame = pinfo->fd->num;
5426 new_matched_key->call_id = hdr->seqnum;
5427 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
5430 matched_key.frame = pinfo->fd->num;
5431 matched_key.call_id = hdr->seqnum;
5432 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
5434 v.uuid = hdr->if_id;
5435 v.ver = hdr->if_ver;
5436 v.object_uuid = hdr->obj_id;
5437 v.opnum = hdr->opnum;
5438 v.req_frame = pinfo->fd->num;
5442 v.private_data = NULL;
5447 di->call_id = hdr->seqnum;
5449 di->ptype = PDU_REQ;
5450 di->call_data = value;
5452 if (value->rep_frame != 0) {
5453 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
5454 tvb, 0, 0, value->rep_frame);
5455 PROTO_ITEM_SET_GENERATED(pi);
5456 parent_pi = proto_tree_get_parent(dcerpc_tree);
5457 if (parent_pi != NULL) {
5458 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
5461 dissect_dcerpc_dg_stub(tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
5465 dissect_dcerpc_dg_resp(tvbuff_t *tvb, int offset, packet_info *pinfo,
5466 proto_tree *dcerpc_tree, proto_tree *tree,
5467 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
5470 dcerpc_call_value *value, v;
5471 dcerpc_matched_key matched_key, *new_matched_key;
5473 proto_item *parent_pi;
5476 if (!(pinfo->fd->flags.visited)) {
5477 dcerpc_call_value *call_value;
5478 dcerpc_dg_call_key call_key;
5480 call_key.conv = conv;
5481 call_key.seqnum = hdr->seqnum;
5482 call_key.act_id = hdr->act_id;
5484 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_dg_calls, &call_key))) {
5485 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
5486 new_matched_key->frame = pinfo->fd->num;
5487 new_matched_key->call_id = hdr->seqnum;
5488 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
5489 if (call_value->rep_frame == 0) {
5490 call_value->rep_frame = pinfo->fd->num;
5495 matched_key.frame = pinfo->fd->num;
5496 matched_key.call_id = hdr->seqnum;
5497 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
5499 v.uuid = hdr->if_id;
5500 v.ver = hdr->if_ver;
5501 v.object_uuid = hdr->obj_id;
5502 v.opnum = hdr->opnum;
5504 v.rep_frame = pinfo->fd->num;
5506 v.private_data = NULL;
5513 di->ptype = PDU_RESP;
5514 di->call_data = value;
5516 if (value->req_frame != 0) {
5518 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
5519 tvb, 0, 0, value->req_frame);
5520 PROTO_ITEM_SET_GENERATED(pi);
5521 parent_pi = proto_tree_get_parent(dcerpc_tree);
5522 if (parent_pi != NULL) {
5523 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
5525 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
5526 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
5527 PROTO_ITEM_SET_GENERATED(pi);
5529 proto_tree_add_expert(dcerpc_tree, pinfo, &ei_dcerpc_no_request_found, tvb, 0, 0);
5531 dissect_dcerpc_dg_stub(tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
5535 dissect_dcerpc_dg_ping_ack(tvbuff_t *tvb, int offset, packet_info *pinfo,
5536 proto_tree *dcerpc_tree,
5537 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
5539 proto_item *parent_pi;
5540 /* if (!(pinfo->fd->flags.visited)) {*/
5541 dcerpc_call_value *call_value;
5542 dcerpc_dg_call_key call_key;
5544 call_key.conv = conv;
5545 call_key.seqnum = hdr->seqnum;
5546 call_key.act_id = hdr->act_id;
5548 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_dg_calls, &call_key))) {
5552 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
5553 tvb, 0, 0, call_value->req_frame);
5554 PROTO_ITEM_SET_GENERATED(pi);
5555 parent_pi = proto_tree_get_parent(dcerpc_tree);
5556 if (parent_pi != NULL) {
5557 proto_item_append_text(parent_pi, ", [Req: #%u]", call_value->req_frame);
5560 col_append_fstr(pinfo->cinfo, COL_INFO, " [req: #%u]", call_value->req_frame);
5562 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &call_value->req_time);
5563 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
5564 PROTO_ITEM_SET_GENERATED(pi);
5570 * DCERPC dissector for connectionless calls
5573 dissect_dcerpc_dg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5575 proto_item *ti = NULL;
5576 proto_item *tf = NULL;
5577 proto_tree *dcerpc_tree = NULL;
5578 proto_tree *dg_flags1_tree = NULL;
5579 proto_tree *dg_flags2_tree = NULL;
5580 proto_tree *drep_tree = NULL;
5581 e_dce_dg_common_hdr_t hdr;
5583 conversation_t *conv;
5586 const char *uuid_name = NULL;
5589 * Check if this looks like a CL DCERPC call. All dg packets
5590 * have an 80 byte header on them. Which starts with
5591 * version (4), pkt_type.
5593 if (tvb_length(tvb) < sizeof (hdr)) {
5597 /* Version must be 4 */
5598 hdr.rpc_ver = tvb_get_guint8(tvb, offset++);
5599 if (hdr.rpc_ver != 4)
5602 /* Type must be <= 19 or it's not DCE/RPC */
5603 hdr.ptype = tvb_get_guint8(tvb, offset++);
5607 /* flags1 has bit 1 and 8 as reserved so if any of them are set, it is
5608 probably not a DCE/RPC packet
5610 hdr.flags1 = tvb_get_guint8(tvb, offset++);
5611 if (hdr.flags1&0x81)
5614 /* flags2 has all bits except bit 2 as reserved so if any of them are set
5615 it is probably not DCE/RPC.
5617 hdr.flags2 = tvb_get_guint8(tvb, offset++);
5618 if (hdr.flags2&0xfd)
5622 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCERPC");
5623 col_add_str(pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
5625 tvb_memcpy(tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
5626 offset += (int)sizeof (hdr.drep);
5627 hdr.serial_hi = tvb_get_guint8(tvb, offset++);
5628 dcerpc_tvb_get_uuid(tvb, offset, hdr.drep, &hdr.obj_id);
5630 dcerpc_tvb_get_uuid(tvb, offset, hdr.drep, &hdr.if_id);
5632 dcerpc_tvb_get_uuid(tvb, offset, hdr.drep, &hdr.act_id);
5634 hdr.server_boot = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
5636 hdr.if_ver = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
5638 hdr.seqnum = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
5640 hdr.opnum = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5642 hdr.ihint = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5644 hdr.ahint = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5646 hdr.frag_len = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5648 hdr.frag_num = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5650 hdr.auth_proto = tvb_get_guint8(tvb, offset++);
5651 hdr.serial_lo = tvb_get_guint8(tvb, offset++);
5654 ti = proto_tree_add_item(tree, proto_dcerpc, tvb, 0, -1, ENC_NA);
5656 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
5657 proto_item_append_text(ti, " %s, Seq: %u, Serial: %u, Frag: %u, FragLen: %u",
5658 val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"),
5659 hdr.seqnum, hdr.serial_hi*256+hdr.serial_lo,
5660 hdr.frag_num, hdr.frag_len);
5666 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
5670 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
5674 tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
5675 dg_flags1_tree = proto_item_add_subtree(tf, ett_dcerpc_dg_flags1);
5676 if (dg_flags1_tree) {
5677 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
5678 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
5679 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
5680 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
5681 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
5682 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
5683 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
5684 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
5686 proto_item_append_text(tf, " %s%s%s%s%s%s",
5687 (hdr.flags1 & PFCL1_BROADCAST) ? "\"Broadcast\" " : "",
5688 (hdr.flags1 & PFCL1_IDEMPOTENT) ? "\"Idempotent\" " : "",
5689 (hdr.flags1 & PFCL1_MAYBE) ? "\"Maybe\" " : "",
5690 (hdr.flags1 & PFCL1_NOFACK) ? "\"No Fack\" " : "",
5691 (hdr.flags1 & PFCL1_FRAG) ? "\"Fragment\" " : "",
5692 (hdr.flags1 & PFCL1_LASTFRAG) ? "\"Last Fragment\" " : "");
5699 tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
5700 dg_flags2_tree = proto_item_add_subtree(tf, ett_dcerpc_dg_flags2);
5701 if (dg_flags2_tree) {
5702 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
5703 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
5704 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
5705 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
5706 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
5707 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
5708 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
5709 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
5711 proto_item_append_text(tf, " %s",
5712 (hdr.flags2 & PFCL2_CANCEL_PENDING) ? "\"Cancel Pending\" " : "");
5719 tf = proto_tree_add_bytes(dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
5720 drep_tree = proto_item_add_subtree(tf, ett_dcerpc_drep);
5722 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
5723 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
5724 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
5725 proto_item_append_text(tf, " (Order: %s, Char: %s, Float: %s)",
5726 val_to_str_const(hdr.drep[0] >> 4, drep_byteorder_vals, "Unknown"),
5727 val_to_str_const(hdr.drep[0] & 0x0f, drep_character_vals, "Unknown"),
5728 val_to_str_const(hdr.drep[1], drep_fp_vals, "Unknown"));
5731 offset += (int)sizeof (hdr.drep);
5734 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
5738 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
5739 offset, 16, (e_guid_t *) &hdr.obj_id, "Object UUID: %s",
5740 guid_to_str((e_guid_t *) &hdr.obj_id));
5745 uuid_str = guid_to_str((e_guid_t*)&hdr.if_id);
5746 uuid_name = guids_get_uuid_name(&hdr.if_id);
5748 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
5749 offset, 16, (e_guid_t *) &hdr.if_id, "Interface: %s UUID: %s", uuid_name, uuid_str);
5751 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
5752 offset, 16, (e_guid_t *) &hdr.if_id, "Interface UUID: %s", uuid_str);
5758 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
5759 offset, 16, (e_guid_t *) &hdr.act_id, "Activity: %s",
5760 guid_to_str((e_guid_t *) &hdr.act_id));
5765 nstime_t server_boot;
5767 server_boot.secs = hdr.server_boot;
5768 server_boot.nsecs = 0;
5770 if (hdr.server_boot == 0)
5771 proto_tree_add_time_format_value(dcerpc_tree, hf_dcerpc_dg_server_boot,
5772 tvb, offset, 4, &server_boot,
5775 proto_tree_add_time(dcerpc_tree, hf_dcerpc_dg_server_boot,
5776 tvb, offset, 4, &server_boot);
5781 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
5785 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
5786 col_append_fstr(pinfo->cinfo, COL_INFO, ": seq: %u", hdr.seqnum);
5787 col_append_fstr(pinfo->cinfo, COL_DCE_CALL, "%u", hdr.seqnum);
5791 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
5795 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
5799 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
5803 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
5807 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
5808 if (hdr.flags1 & PFCL1_FRAG) {
5809 /* Fragmented - put the fragment number into the Info column */
5810 col_append_fstr(pinfo->cinfo, COL_INFO, " frag: %u",
5816 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
5820 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
5821 if (hdr.flags1 & PFCL1_FRAG) {
5822 /* Fragmented - put the serial number into the Info column */
5823 col_append_fstr(pinfo->cinfo, COL_INFO, " serial: %u",
5824 (hdr.serial_hi << 8) | hdr.serial_lo);
5830 * XXX - for Kerberos, we get a protection level; if it's
5831 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
5834 dissect_dcerpc_dg_auth(tvb, offset, dcerpc_tree, &hdr,
5839 * keeping track of the conversation shouldn't really be necessary
5840 * for connectionless packets, because everything we need to know
5841 * to dissect is in the header for each packet. Unfortunately,
5842 * Microsoft's implementation is buggy and often puts the
5843 * completely wrong if_id in the header. go figure. So, keep
5844 * track of the seqnum and use that if possible. Note: that's not
5845 * completely correct. It should really be done based on both the
5846 * activity_id and seqnum. I haven't seen anywhere that it would
5847 * make a difference, but for future reference...
5849 conv = find_or_create_conversation(pinfo);
5852 * Packet type specific stuff is next.
5855 switch (hdr.ptype) {
5857 case PDU_CANCEL_ACK:
5858 /* Body is optional */
5859 /* XXX - we assume "frag_len" is the length of the body */
5860 if (hdr.frag_len != 0)
5861 dissect_dcerpc_dg_cancel_ack(tvb, offset, pinfo, dcerpc_tree, &hdr);
5866 * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
5867 * but in at least one capture none of the Cl_cancel PDUs had a
5870 /* XXX - we assume "frag_len" is the length of the body */
5871 if (hdr.frag_len != 0)
5872 dissect_dcerpc_dg_cancel(tvb, offset, pinfo, dcerpc_tree, &hdr);
5876 /* Body is optional; if present, it's the same as PDU_FACK */
5877 /* XXX - we assume "frag_len" is the length of the body */
5878 if (hdr.frag_len != 0)
5879 dissect_dcerpc_dg_fack(tvb, offset, pinfo, dcerpc_tree, &hdr);
5883 /* Body is optional */
5884 /* XXX - we assume "frag_len" is the length of the body */
5885 if (hdr.frag_len != 0)
5886 dissect_dcerpc_dg_fack(tvb, offset, pinfo, dcerpc_tree, &hdr);
5891 dissect_dcerpc_dg_reject_fault(tvb, offset, pinfo, dcerpc_tree, &hdr);
5895 dissect_dcerpc_dg_rqst(tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
5899 dissect_dcerpc_dg_resp(tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
5902 /* these requests have no body */
5905 dissect_dcerpc_dg_ping_ack(tvb, offset, pinfo, dcerpc_tree, &hdr, conv);
5916 dcerpc_init_protocol(void)
5918 /* structures and data for BIND */
5920 g_hash_table_destroy(dcerpc_binds);
5921 dcerpc_binds = NULL;
5923 if (!dcerpc_binds) {
5924 dcerpc_binds = g_hash_table_new(dcerpc_bind_hash, dcerpc_bind_equal);
5927 /* structures and data for CALL */
5928 if (dcerpc_cn_calls) {
5929 g_hash_table_destroy(dcerpc_cn_calls);
5931 dcerpc_cn_calls = g_hash_table_new(dcerpc_cn_call_hash, dcerpc_cn_call_equal);
5932 if (dcerpc_dg_calls) {
5933 g_hash_table_destroy(dcerpc_dg_calls);
5935 dcerpc_dg_calls = g_hash_table_new(dcerpc_dg_call_hash, dcerpc_dg_call_equal);
5937 /* structure and data for MATCHED */
5938 if (dcerpc_matched) {
5939 g_hash_table_destroy(dcerpc_matched);
5941 dcerpc_matched = g_hash_table_new(dcerpc_matched_hash, dcerpc_matched_equal);
5943 decode_dcerpc_inject_bindings();
5947 proto_register_dcerpc(void)
5949 static hf_register_info hf[] = {
5950 { &hf_dcerpc_request_in,
5951 { "Request in frame", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE,
5952 NULL, 0, "This packet is a response to the packet with this number", HFILL }},
5953 { &hf_dcerpc_response_in,
5954 { "Response in frame", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
5955 NULL, 0, "This packet will be responded in the packet with this number", HFILL }},
5956 { &hf_dcerpc_referent_id,
5957 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
5958 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
5960 { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5961 { &hf_dcerpc_ver_minor,
5962 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5963 { &hf_dcerpc_packet_type,
5964 { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS(pckt_vals), 0x0, NULL, HFILL }},
5965 { &hf_dcerpc_cn_flags,
5966 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5967 { &hf_dcerpc_cn_flags_first_frag,
5968 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_FIRST_FRAG, NULL, HFILL }},
5969 { &hf_dcerpc_cn_flags_last_frag,
5970 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_LAST_FRAG, NULL, HFILL }},
5971 { &hf_dcerpc_cn_flags_cancel_pending,
5972 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_PENDING_CANCEL, NULL, HFILL }},
5973 { &hf_dcerpc_cn_flags_reserved,
5974 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_RESERVED_1, NULL, HFILL }},
5975 { &hf_dcerpc_cn_flags_mpx,
5976 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_CONC_MPX, NULL, HFILL }},
5977 { &hf_dcerpc_cn_flags_dne,
5978 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_DID_NOT_EXECUTE, NULL, HFILL }},
5979 { &hf_dcerpc_cn_flags_maybe,
5980 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_MAYBE, NULL, HFILL }},
5981 { &hf_dcerpc_cn_flags_object,
5982 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_OBJECT_UUID, NULL, HFILL }},
5984 { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5985 { &hf_dcerpc_drep_byteorder,
5986 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS(drep_byteorder_vals), 0x0, NULL, HFILL }},
5987 { &hf_dcerpc_drep_character,
5988 { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS(drep_character_vals), 0x0, NULL, HFILL }},
5989 { &hf_dcerpc_drep_fp,
5990 { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS(drep_fp_vals), 0x0, NULL, HFILL }},
5991 { &hf_dcerpc_cn_frag_len,
5992 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5993 { &hf_dcerpc_cn_auth_len,
5994 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5995 { &hf_dcerpc_cn_call_id,
5996 { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5997 { &hf_dcerpc_cn_max_xmit,
5998 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5999 { &hf_dcerpc_cn_max_recv,
6000 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6001 { &hf_dcerpc_cn_assoc_group,
6002 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6003 { &hf_dcerpc_cn_num_ctx_items,
6004 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6005 { &hf_dcerpc_cn_ctx_item,
6006 { "Ctx Item", "dcerpc.cn_ctx_item", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6007 { &hf_dcerpc_cn_ctx_id,
6008 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6009 { &hf_dcerpc_cn_num_trans_items,
6010 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6011 { &hf_dcerpc_cn_bind_abstract_syntax,
6012 { "Abstract Syntax", "dcerpc.cn_bind_abstract_syntax", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6013 { &hf_dcerpc_cn_bind_if_id,
6014 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6015 { &hf_dcerpc_cn_bind_if_ver,
6016 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6017 { &hf_dcerpc_cn_bind_if_ver_minor,
6018 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6019 { &hf_dcerpc_cn_bind_trans_syntax,
6020 { "Transfer Syntax", "dcerpc.cn_bind_trans", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6021 { &hf_dcerpc_cn_bind_trans_id,
6022 { "ID", "dcerpc.cn_bind_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6023 { &hf_dcerpc_cn_bind_trans_ver,
6024 { "ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6025 { &hf_dcerpc_cn_bind_trans_btfn_01, /* [MS-RPCE] 2.2.2.14 */
6026 { "Security Context Multiplexing Supported", "dcerpc.cn_bind_trans_btfn.01", FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x01, NULL, HFILL }},
6027 { &hf_dcerpc_cn_bind_trans_btfn_02,
6028 { "Keep Connection On Orphan Supported", "dcerpc.cn_bind_trans_btfn.02", FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x02, NULL, HFILL }},
6029 { &hf_dcerpc_cn_alloc_hint,
6030 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6031 { &hf_dcerpc_cn_sec_addr_len,
6032 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6033 { &hf_dcerpc_cn_sec_addr,
6034 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6035 { &hf_dcerpc_cn_num_results,
6036 { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6037 { &hf_dcerpc_cn_ack_result,
6038 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, NULL, HFILL }},
6039 { &hf_dcerpc_cn_ack_reason,
6040 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, NULL, HFILL }},
6041 { &hf_dcerpc_cn_ack_trans_id,
6042 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6043 { &hf_dcerpc_cn_ack_trans_ver,
6044 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6045 { &hf_dcerpc_cn_ack_btfn,
6046 { "Bind Time Feature Negotiation Bitmask", "dcerpc.cn_ack_btfn", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6047 { &hf_dcerpc_cn_reject_reason,
6048 { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, NULL, HFILL }},
6049 { &hf_dcerpc_cn_num_protocols,
6050 { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6051 { &hf_dcerpc_cn_protocol_ver_major,
6052 { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6053 { &hf_dcerpc_cn_protocol_ver_minor,
6054 { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6055 { &hf_dcerpc_cn_cancel_count,
6056 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6057 { &hf_dcerpc_cn_status,
6058 { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, NULL, HFILL }},
6059 { &hf_dcerpc_cn_deseg_req,
6060 { "Desegmentation Required", "dcerpc.cn_deseg_req", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6061 { &hf_dcerpc_auth_type,
6062 { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS(authn_protocol_vals), 0x0, NULL, HFILL }},
6063 { &hf_dcerpc_auth_level,
6064 { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, NULL, HFILL }},
6065 { &hf_dcerpc_auth_pad_len,
6066 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6067 { &hf_dcerpc_auth_rsrvd,
6068 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6069 { &hf_dcerpc_auth_ctx_id,
6070 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6071 { &hf_dcerpc_dg_flags1,
6072 { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6073 { &hf_dcerpc_dg_flags1_rsrvd_01,
6074 { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_RESERVED_01, NULL, HFILL }},
6075 { &hf_dcerpc_dg_flags1_last_frag,
6076 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_LASTFRAG, NULL, HFILL }},
6077 { &hf_dcerpc_dg_flags1_frag,
6078 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_FRAG, NULL, HFILL }},
6079 { &hf_dcerpc_dg_flags1_nofack,
6080 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_NOFACK, NULL, HFILL }},
6081 { &hf_dcerpc_dg_flags1_maybe,
6082 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_MAYBE, NULL, HFILL }},
6083 { &hf_dcerpc_dg_flags1_idempotent,
6084 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_IDEMPOTENT, NULL, HFILL }},
6085 { &hf_dcerpc_dg_flags1_broadcast,
6086 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_BROADCAST, NULL, HFILL }},
6087 { &hf_dcerpc_dg_flags1_rsrvd_80,
6088 { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_RESERVED_80, NULL, HFILL }},
6089 { &hf_dcerpc_dg_flags2,
6090 { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6091 { &hf_dcerpc_dg_flags2_rsrvd_01,
6092 { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_01, NULL, HFILL }},
6093 { &hf_dcerpc_dg_flags2_cancel_pending,
6094 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_CANCEL_PENDING, NULL, HFILL }},
6095 { &hf_dcerpc_dg_flags2_rsrvd_04,
6096 { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_04, NULL, HFILL }},
6097 { &hf_dcerpc_dg_flags2_rsrvd_08,
6098 { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_08, NULL, HFILL }},
6099 { &hf_dcerpc_dg_flags2_rsrvd_10,
6100 { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_10, NULL, HFILL }},
6101 { &hf_dcerpc_dg_flags2_rsrvd_20,
6102 { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_20, NULL, HFILL }},
6103 { &hf_dcerpc_dg_flags2_rsrvd_40,
6104 { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_40, NULL, HFILL }},
6105 { &hf_dcerpc_dg_flags2_rsrvd_80,
6106 { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_80, NULL, HFILL }},
6107 { &hf_dcerpc_dg_serial_lo,
6108 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6109 { &hf_dcerpc_dg_serial_hi,
6110 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6111 { &hf_dcerpc_dg_ahint,
6112 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6113 { &hf_dcerpc_dg_ihint,
6114 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6115 { &hf_dcerpc_dg_frag_len,
6116 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6117 { &hf_dcerpc_dg_frag_num,
6118 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6119 { &hf_dcerpc_dg_auth_proto,
6120 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS(authn_protocol_vals), 0x0, NULL, HFILL }},
6121 { &hf_dcerpc_dg_seqnum,
6122 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6123 { &hf_dcerpc_dg_server_boot,
6124 { "Server boot time", "dcerpc.dg_server_boot", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0, NULL, HFILL }},
6125 { &hf_dcerpc_dg_if_ver,
6126 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6127 { &hf_dcerpc_krb5_av_prot_level,
6128 { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, NULL, HFILL }},
6129 { &hf_dcerpc_krb5_av_key_vers_num,
6130 { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6131 { &hf_dcerpc_krb5_av_key_auth_verifier,
6132 { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6133 { &hf_dcerpc_obj_id,
6134 { "Object", "dcerpc.obj_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6135 { &hf_dcerpc_dg_if_id,
6136 { "Interface", "dcerpc.dg_if_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6137 { &hf_dcerpc_dg_act_id,
6138 { "Activity", "dcerpc.dg_act_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6140 { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6142 { &hf_dcerpc_dg_cancel_vers,
6143 { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6145 { &hf_dcerpc_dg_cancel_id,
6146 { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6148 { &hf_dcerpc_dg_server_accepting_cancels,
6149 { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6151 { &hf_dcerpc_dg_fack_vers,
6152 { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6154 { &hf_dcerpc_dg_fack_window_size,
6155 { "Window Size", "dcerpc.fack_window_size", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6157 { &hf_dcerpc_dg_fack_max_tsdu,
6158 { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6160 { &hf_dcerpc_dg_fack_max_frag_size,
6161 { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6163 { &hf_dcerpc_dg_fack_serial_num,
6164 { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6166 { &hf_dcerpc_dg_fack_selack_len,
6167 { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6169 { &hf_dcerpc_dg_fack_selack,
6170 { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6172 { &hf_dcerpc_dg_status,
6173 { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, NULL, HFILL }},
6175 { &hf_dcerpc_array_max_count,
6176 { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
6178 { &hf_dcerpc_array_offset,
6179 { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
6181 { &hf_dcerpc_array_actual_count,
6182 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
6184 { &hf_dcerpc_array_buffer,
6185 { "Buffer", "dcerpc.array.buffer", FT_BYTES, BASE_NONE, NULL, 0x0, "Buffer: Buffer containing elements of the array", HFILL }},
6188 { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6190 { &hf_dcerpc_fragments,
6191 { "Reassembled DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
6192 NULL, 0x0, "DCE/RPC Fragments", HFILL }},
6194 { &hf_dcerpc_fragment,
6195 { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM, BASE_NONE,
6196 NULL, 0x0, NULL, HFILL }},
6198 { &hf_dcerpc_fragment_overlap,
6199 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE,
6200 NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
6202 { &hf_dcerpc_fragment_overlap_conflict,
6203 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE,
6204 NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
6206 { &hf_dcerpc_fragment_multiple_tails,
6207 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE,
6208 NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
6210 { &hf_dcerpc_fragment_too_long_fragment,
6211 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE,
6212 NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
6214 { &hf_dcerpc_fragment_error,
6215 { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE,
6216 NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
6218 { &hf_dcerpc_fragment_count,
6219 { "Fragment count", "dcerpc.fragment.count", FT_UINT32, BASE_DEC,
6220 NULL, 0x0, NULL, HFILL }},
6223 { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE,
6224 NULL, 0, "Time between Request and Response for DCE-RPC calls", HFILL }},
6226 { &hf_dcerpc_reassembled_in,
6227 { "Reassembled PDU in frame", "dcerpc.reassembled_in", FT_FRAMENUM, BASE_NONE,
6228 NULL, 0x0, "The DCE/RPC PDU is completely reassembled in the packet with this number", HFILL }},
6230 { &hf_dcerpc_reassembled_length,
6231 { "Reassembled DCE/RPC length", "dcerpc.reassembled.length", FT_UINT32, BASE_DEC,
6232 NULL, 0x0, "The total length of the reassembled payload", HFILL }},
6234 { &hf_dcerpc_unknown_if_id,
6235 { "Unknown DCERPC interface id", "dcerpc.unknown_if_id", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6237 { &hf_dcerpc_cn_rts_flags,
6238 { "RTS Flags", "dcerpc.cn_rts_flags", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6239 { &hf_dcerpc_cn_rts_flags_none,
6240 {"None", "dcerpc.cn_rts_flags.none", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_NONE, NULL, HFILL }},
6241 { &hf_dcerpc_cn_rts_flags_ping,
6242 { "Ping", "dcerpc.cn_rts.flags.ping", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_PING, NULL, HFILL }},
6243 { &hf_dcerpc_cn_rts_flags_other_cmd,
6244 { "Other Cmd", "dcerpc.cn_rts_flags.other_cmd", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_OTHER_CMD, NULL, HFILL }},
6245 { &hf_dcerpc_cn_rts_flags_recycle_channel,
6246 { "Recycle Channel", "dcerpc.cn_rts_flags.recycle_channel", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_RECYCLE_CHANNEL, NULL, HFILL }},
6247 { &hf_dcerpc_cn_rts_flags_in_channel,
6248 { "In Channel", "dcerpc.cn_rts_flags.in_channel", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_IN_CHANNEL, NULL, HFILL }},
6249 { &hf_dcerpc_cn_rts_flags_out_channel,
6250 { "Out Channel", "dcerpc.cn_rts_flags.out_channel", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_OUT_CHANNEL, NULL, HFILL }},
6251 { &hf_dcerpc_cn_rts_flags_eof,
6252 { "EOF", "dcerpc.cn_rts_flags.eof", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_EOF, NULL, HFILL }},
6253 { &hf_dcerpc_cn_rts_commands_nb,
6254 { "RTS Number of Commands", "dcerpc.cn_rts_commands_nb", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6255 { &hf_dcerpc_cn_rts_command,
6256 { "RTS Command", "dcerpc.cn_rts_command", FT_UINT32, BASE_HEX, VALS(rts_command_vals), 0x0, NULL, HFILL }},
6257 { &hf_dcerpc_cn_rts_command_receivewindowsize,
6258 {"Receive Window Size", "dcerpc.cn_rts_command.receivewindowsize", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6259 { &hf_dcerpc_cn_rts_command_fack_bytesreceived,
6260 {"Bytes Received", "dcerpc.cn_rts_command.fack.bytesreceived", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6261 { &hf_dcerpc_cn_rts_command_fack_availablewindow,
6262 {"Available Window", "dcerpc.cn_rts_command.fack.availablewindow", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6263 { &hf_dcerpc_cn_rts_command_fack_channelcookie,
6264 {"Channel Cookie", "dcerpc.cn_rts_command.fack.channelcookie", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6265 { &hf_dcerpc_cn_rts_command_connectiontimeout,
6266 {"Connection Timeout", "dcerpc.cn_rts_command.connectiontimeout", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6267 { &hf_dcerpc_cn_rts_command_cookie,
6268 {"Cookie", "dcerpc.cn_rts_command.cookie", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6269 { &hf_dcerpc_cn_rts_command_channellifetime,
6270 {"Channel Lifetime", "dcerpc.cn_rts_command.channellifetime", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6271 { &hf_dcerpc_cn_rts_command_clientkeepalive,
6272 {"Client Keepalive", "dcerpc.cn_rts_command.clientkeepalive", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6273 { &hf_dcerpc_cn_rts_command_version,
6274 {"Version", "dcerpc.cn_rts_command.version", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6275 { &hf_dcerpc_cn_rts_command_conformancecount,
6276 {"Conformance Count", "dcerpc.cn_rts_command.padding.conformancecount", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6277 { &hf_dcerpc_cn_rts_command_padding,
6278 { "Padding", "dcerpc.cn_rts_command.padding.padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
6279 { &hf_dcerpc_cn_rts_command_addrtype,
6280 { "Address Type", "dcerpc.cn_rts_command.addrtype", FT_UINT32, BASE_DEC, VALS(rts_addresstype_vals), 0x0, NULL, HFILL }},
6281 { &hf_dcerpc_cn_rts_command_associationgroupid,
6282 {"Association Group ID", "dcerpc.cn_rts_command.associationgroupid", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6283 { &hf_dcerpc_cn_rts_command_forwarddestination,
6284 {"Forward Destination", "dcerpc.cn_rts_command.forwarddestination", FT_UINT32, BASE_DEC, VALS(rts_forward_destination_vals), 0x0, NULL, HFILL }},
6285 { &hf_dcerpc_cn_rts_command_pingtrafficsentnotify,
6286 {"Ping Traffic Sent Notify", "dcerpc.cn_rts_command.pingtrafficsentnotify", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6288 static gint *ett[] = {
6290 &ett_dcerpc_cn_flags,
6292 &ett_dcerpc_cn_iface,
6293 &ett_dcerpc_cn_trans_syntax,
6294 &ett_dcerpc_cn_trans_btfn,
6295 &ett_dcerpc_cn_rts_flags,
6296 &ett_dcerpc_cn_rts_command,
6297 &ett_dcerpc_cn_rts_pdu,
6299 &ett_dcerpc_dg_flags1,
6300 &ett_dcerpc_dg_flags2,
6301 &ett_dcerpc_pointer_data,
6303 &ett_dcerpc_fragments,
6304 &ett_dcerpc_fragment,
6305 &ett_dcerpc_krb5_auth_verf,
6308 static ei_register_info ei[] = {
6309 { &ei_dcerpc_fragment, { "dcerpc.fragment", PI_REASSEMBLE, PI_CHAT, "%s fragment", EXPFILL }},
6310 { &ei_dcerpc_fragment_reassembled, { "dcerpc.fragment_reassembled", PI_REASSEMBLE, PI_CHAT, "%s fragment, reassembled", EXPFILL }},
6311 { &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 }},
6312 { &ei_dcerpc_no_request_found, { "dcerpc.no_request_found", PI_SEQUENCE, PI_NOTE, "No request to this DCE/RPC call found", EXPFILL }},
6313 { &ei_dcerpc_cn_status, { "dcerpc.cn_status.expert", PI_RESPONSE_CODE, PI_NOTE, "Fault: %s", EXPFILL }},
6314 { &ei_dcerpc_fragment_multiple, { "dcerpc.fragment_multiple", PI_SEQUENCE, PI_CHAT, "Multiple DCE/RPC fragments/PDU's in one packet", EXPFILL }},
6315 { &ei_dcerpc_context_change, { "dcerpc.context_change", PI_SEQUENCE, PI_CHAT, "Context change: %s", EXPFILL }},
6316 { &ei_dcerpc_bind_not_acknowledged, { "dcerpc.bind_not_acknowledged", PI_SEQUENCE, PI_WARN, "Bind not acknowledged", EXPFILL }},
6319 /* Decode As handling */
6320 static build_valid_func dcerpc_da_build_value[1] = {dcerpc_value};
6321 static decode_as_value_t dcerpc_da_values = {dcerpc_prompt, 1, dcerpc_da_build_value};
6322 static decode_as_t dcerpc_da = {"dcerpc", "DCE-RPC",
6323 /* XXX - DCE/RPC doesn't have a true (sub)dissector table, so
6324 provide a "fake" one to fit the Decode As algorithm */
6326 1, 0, &dcerpc_da_values, NULL, NULL,
6327 dcerpc_populate_list, decode_dcerpc_binding_reset, dcerpc_decode_as_change, dcerpc_decode_as_free};
6329 module_t *dcerpc_module;
6330 expert_module_t* expert_dcerpc;
6332 proto_dcerpc = proto_register_protocol("Distributed Computing Environment / Remote Procedure Call (DCE/RPC)", "DCERPC", "dcerpc");
6333 proto_register_field_array(proto_dcerpc, hf, array_length(hf));
6334 proto_register_subtree_array(ett, array_length(ett));
6335 expert_dcerpc = expert_register_protocol(proto_dcerpc);
6336 expert_register_field_array(expert_dcerpc, ei, array_length(ei));
6338 register_init_routine(dcerpc_init_protocol);
6339 dcerpc_module = prefs_register_protocol(proto_dcerpc, NULL);
6340 prefs_register_bool_preference(dcerpc_module,
6342 "Reassemble DCE/RPC messages spanning multiple TCP segments",
6343 "Whether the DCE/RPC dissector should reassemble messages"
6344 " spanning multiple TCP segments."
6345 " To use this option, you must also enable"
6346 " \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
6347 &dcerpc_cn_desegment);
6348 prefs_register_bool_preference(dcerpc_module,
6349 "reassemble_dcerpc",
6350 "Reassemble DCE/RPC fragments",
6351 "Whether the DCE/RPC dissector should reassemble fragmented DCE/RPC PDUs",
6352 &dcerpc_reassemble);
6353 register_init_routine(dcerpc_reassemble_init);
6354 dcerpc_uuids = g_hash_table_new(dcerpc_uuid_hash, dcerpc_uuid_equal);
6355 dcerpc_tap = register_tap("dcerpc");
6357 register_decode_as(&dcerpc_da);
6361 proto_reg_handoff_dcerpc(void)
6363 heur_dissector_add("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
6364 heur_dissector_add("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
6365 heur_dissector_add("udp", dissect_dcerpc_dg, proto_dcerpc);
6366 heur_dissector_add("smb_transact", dissect_dcerpc_cn_smbpipe, proto_dcerpc);
6367 heur_dissector_add("smb2_heur_subdissectors", dissect_dcerpc_cn_smb2, proto_dcerpc);
6368 heur_dissector_add("http", dissect_dcerpc_cn_bs, proto_dcerpc);
6369 dcerpc_smb_init(proto_dcerpc);
6371 guids_add_uuid(&uuid_data_repr_proto, "32bit NDR");
6372 guids_add_uuid(&uuid_ndr64, "64bit NDR");
6373 guids_add_uuid(&uuid_bind_time_feature_nego_00, "bind time feature negotiation");
6374 guids_add_uuid(&uuid_bind_time_feature_nego_01, "bind time feature negotiation");
6375 guids_add_uuid(&uuid_bind_time_feature_nego_02, "bind time feature negotiation");
6376 guids_add_uuid(&uuid_bind_time_feature_nego_03, "bind time feature negotiation");
6377 guids_add_uuid(&uuid_asyncemsmdb, "async MAPI");
6381 * Editor modelines - http://www.wireshark.org/tools/modelines.html
6386 * indent-tabs-mode: nil
6389 * vi: set shiftwidth=4 tabstop=8 expandtab:
6390 * :indentSize=4:tabSize=8:noTabs=true: