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 {
638 * Registers a conversation/UUID binding association, so that
639 * we can invoke the proper sub-dissector for a given DCERPC
642 * @param binding all values needed to create and bind a new conversation
644 * @return Pointer to newly-added UUID/conversation binding.
646 static struct _dcerpc_bind_value *
647 dcerpc_add_conv_to_bind_table(decode_dcerpc_bind_values_t *binding)
649 dcerpc_bind_value *bind_value;
650 dcerpc_bind_key *key;
651 conversation_t *conv;
653 conv = find_conversation(
663 conv = conversation_new(
673 bind_value = (dcerpc_bind_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_value));
674 bind_value->uuid = binding->uuid;
675 bind_value->ver = binding->ver;
676 /* For now, assume all DCE/RPC we pick from "decode as" is using
677 standard ndr and not ndr64.
678 We should make this selectable from the dialog in the future
680 bind_value->transport = uuid_data_repr_proto;
682 key = (dcerpc_bind_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_key));
684 key->ctx_id = binding->ctx_id;
685 key->smb_fid = binding->smb_fid;
687 /* add this entry to the bind table */
688 g_hash_table_insert(dcerpc_binds, key, bind_value);
694 /* inject one of our bindings into the dcerpc binding table */
696 decode_dcerpc_inject_binding(gpointer data, gpointer user_data _U_)
698 dcerpc_add_conv_to_bind_table((decode_dcerpc_bind_values_t *) data);
701 /* inject all of our bindings into the dcerpc binding table */
703 decode_dcerpc_inject_bindings(void) {
704 g_slist_foreach(decode_dcerpc_bindings, decode_dcerpc_inject_binding, NULL /* user_data */);
709 decode_dcerpc_binding_free(void *binding_in)
711 decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t *)binding_in;
713 g_free((void *) binding->addr_a.data);
714 g_free((void *) binding->addr_b.data);
716 g_string_free(binding->ifname, TRUE);
721 dcerpc_decode_as_free(gpointer value)
723 decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t *)value;
725 decode_dcerpc_binding_free(binding);
728 /* removes all bindings */
730 decode_dcerpc_reset_all(void)
732 decode_dcerpc_bind_values_t *binding;
734 while(decode_dcerpc_bindings) {
735 binding = (decode_dcerpc_bind_values_t *)decode_dcerpc_bindings->data;
737 decode_dcerpc_binding_free(binding);
738 decode_dcerpc_bindings = g_slist_remove(
739 decode_dcerpc_bindings,
740 decode_dcerpc_bindings->data);
746 decode_dcerpc_add_show_list(decode_add_show_list_func func, gpointer user_data)
748 g_slist_foreach(decode_dcerpc_bindings, func, user_data);
752 dcerpc_prompt(packet_info *pinfo, gchar* result)
754 GString *str = g_string_new("Replace binding between:\r\n"),
755 *address_str = g_string_new("");
757 switch(pinfo->ptype) {
759 g_string_append(address_str, "Address: ToBeDone TCP port");
762 g_string_append(address_str, "Address: ToBeDone UDP port");
765 g_string_append(address_str, "Address: ToBeDone Unknown port type");
768 g_string_append_printf(str, "%s: %u\r\n", address_str->str, pinfo->srcport);
769 g_string_append(str, "&\r\n");
770 g_string_append_printf(str, "%s: %u\r\n", address_str->str, pinfo->destport);
771 g_string_append_printf(str, "&\r\nContext ID: %u\r\n", pinfo->dcectxid);
772 g_string_append_printf(str, "&\r\nSMB FID: %u\r\n", dcerpc_get_transport_salt(pinfo));
773 g_string_append(str, "with:\r\n");
775 g_strlcpy(result, str->str, MAX_DECODE_AS_PROMPT_LEN);
776 g_string_free(str, TRUE);
777 g_string_free(address_str, TRUE);
781 dcerpc_value(packet_info *pinfo)
783 decode_dcerpc_bind_values_t *binding;
786 binding = g_new(decode_dcerpc_bind_values_t,1);
787 COPY_ADDRESS(&binding->addr_a, &pinfo->src);
788 COPY_ADDRESS(&binding->addr_b, &pinfo->dst);
789 binding->ptype = pinfo->ptype;
790 binding->port_a = pinfo->srcport;
791 binding->port_b = pinfo->destport;
792 binding->ctx_id = pinfo->dcectxid;
793 binding->smb_fid = dcerpc_get_transport_salt(pinfo);
794 binding->ifname = NULL;
795 /*binding->uuid = NULL;*/
801 struct dcerpc_decode_as_populate
803 decode_as_add_to_list_func add_to_list;
808 decode_dcerpc_add_to_list(gpointer key, gpointer value, gpointer user_data)
810 struct dcerpc_decode_as_populate* populate = (struct dcerpc_decode_as_populate*)user_data;
812 /*dcerpc_uuid_key *k = key;*/
813 dcerpc_uuid_value *v = (dcerpc_uuid_value *)value;
815 if(strcmp(v->name, "(none)"))
816 populate->add_to_list("DCE-RPC", v->name, key, populate->ui_element);
820 dcerpc_populate_list(const gchar *table_name _U_, decode_as_add_to_list_func add_to_list, gpointer ui_element)
822 struct dcerpc_decode_as_populate populate;
824 populate.add_to_list = add_to_list;
825 populate.ui_element = ui_element;
827 g_hash_table_foreach(dcerpc_uuids, decode_dcerpc_add_to_list, &populate);
830 /* compare two bindings (except the interface related things, e.g. uuid) */
832 decode_dcerpc_binding_cmp(gconstpointer a, gconstpointer b)
834 const decode_dcerpc_bind_values_t *binding_a = (const decode_dcerpc_bind_values_t *)a;
835 const decode_dcerpc_bind_values_t *binding_b = (const decode_dcerpc_bind_values_t *)b;
838 /* don't compare uuid and ver! */
840 ADDRESSES_EQUAL(&binding_a->addr_a, &binding_b->addr_a) &&
841 ADDRESSES_EQUAL(&binding_a->addr_b, &binding_b->addr_b) &&
842 binding_a->ptype == binding_b->ptype &&
843 binding_a->port_a == binding_b->port_a &&
844 binding_a->port_b == binding_b->port_b &&
845 binding_a->ctx_id == binding_b->ctx_id &&
846 binding_a->smb_fid == binding_b->smb_fid)
856 /* remove a binding (looking the same way as the given one) */
858 decode_dcerpc_binding_reset(const char *name _U_, const gpointer pattern)
860 decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t*)pattern;
862 decode_dcerpc_bind_values_t *old_binding;
864 /* find the old binding (if it exists) */
865 le = g_slist_find_custom(decode_dcerpc_bindings,
867 decode_dcerpc_binding_cmp);
871 old_binding = (decode_dcerpc_bind_values_t *)le->data;
873 decode_dcerpc_bindings = g_slist_remove(decode_dcerpc_bindings, le->data);
875 g_free((void *) old_binding->addr_a.data);
876 g_free((void *) old_binding->addr_b.data);
877 g_string_free(old_binding->ifname, TRUE);
883 dcerpc_decode_as_change(const char *name, const gpointer pattern, gpointer handle, gchar* list_name)
885 decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t*)pattern;
886 decode_dcerpc_bind_values_t *stored_binding;
887 dcerpc_uuid_key *key = *((dcerpc_uuid_key**)handle);
890 binding->ifname = g_string_new(list_name);
891 binding->uuid = key->uuid;
892 binding->ver = key->ver;
894 /* remove a probably existing old binding */
895 decode_dcerpc_binding_reset(name, binding);
897 /* clone the new binding and append it to the list */
898 stored_binding = g_new(decode_dcerpc_bind_values_t,1);
899 *stored_binding = *binding;
900 COPY_ADDRESS(&stored_binding->addr_a, &binding->addr_a);
901 COPY_ADDRESS(&stored_binding->addr_b, &binding->addr_b);
902 stored_binding->ifname = g_string_new(binding->ifname->str);
904 decode_dcerpc_bindings = g_slist_append (decode_dcerpc_bindings, stored_binding);
909 static const fragment_items dcerpc_frag_items = {
910 &ett_dcerpc_fragments,
911 &ett_dcerpc_fragment,
913 &hf_dcerpc_fragments,
915 &hf_dcerpc_fragment_overlap,
916 &hf_dcerpc_fragment_overlap_conflict,
917 &hf_dcerpc_fragment_multiple_tails,
918 &hf_dcerpc_fragment_too_long_fragment,
919 &hf_dcerpc_fragment_error,
920 &hf_dcerpc_fragment_count,
922 &hf_dcerpc_reassembled_length,
923 /* Reassembled data field */
928 /* list of hooks to be called when init_protocols is done */
929 GHookList dcerpc_hooks_init_protos;
934 static dcerpc_info di[20];
935 static int di_counter = 0;
938 if (di_counter >= 20) {
942 memset(&di[di_counter], 0, sizeof(dcerpc_info));
943 di[di_counter].dcerpc_procedure_name = "";
945 return &di[di_counter];
948 /* try to desegment big DCE/RPC packets over TCP? */
949 static gboolean dcerpc_cn_desegment = TRUE;
951 /* reassemble DCE/RPC fragments */
952 /* reassembly of cl dcerpc fragments will not work for the case where ONE frame
953 might contain multiple dcerpc fragments for different PDUs.
954 this case would be so unusual/weird so if you got captures like that:
957 reassembly of co dcerpc fragments will not work for the case where TCP/SMB frames
958 are coming in out of sequence, but that will hurt in a lot of other places as well.
960 static gboolean dcerpc_reassemble = TRUE;
961 static reassembly_table dcerpc_co_reassembly_table;
962 static reassembly_table dcerpc_cl_reassembly_table;
964 typedef struct _dcerpc_fragment_key {
969 } dcerpc_fragment_key;
972 dcerpc_fragment_hash(gconstpointer k)
974 const dcerpc_fragment_key* key = (const dcerpc_fragment_key*) k;
980 hash_val += key->act_id.Data1;
981 hash_val += key->act_id.Data2 << 16;
982 hash_val += key->act_id.Data3;
988 dcerpc_fragment_equal(gconstpointer k1, gconstpointer k2)
990 const dcerpc_fragment_key* key1 = (const dcerpc_fragment_key*) k1;
991 const dcerpc_fragment_key* key2 = (const dcerpc_fragment_key*) k2;
993 /*key.id is the first item to compare since item is most
994 likely to differ between sessions, thus shortcircuiting
995 the comparison of addresses.
997 return (((key1->id == key2->id)
998 && (ADDRESSES_EQUAL(&key1->src, &key2->src))
999 && (ADDRESSES_EQUAL(&key1->dst, &key2->dst))
1000 && (memcmp (&key1->act_id, &key2->act_id, sizeof (e_uuid_t)) == 0))
1004 /* allocate a persistent dcerpc fragment key to insert in the hash */
1006 dcerpc_fragment_temporary_key(const packet_info *pinfo, const guint32 id,
1009 dcerpc_fragment_key *key = g_slice_new(dcerpc_fragment_key);
1010 e_dce_dg_common_hdr_t *hdr = (e_dce_dg_common_hdr_t *)data;
1012 key->src = pinfo->src;
1013 key->dst = pinfo->dst;
1015 key->act_id = hdr->act_id;
1020 /* allocate a persistent dcerpc fragment key to insert in the hash */
1022 dcerpc_fragment_persistent_key(const packet_info *pinfo, const guint32 id,
1025 dcerpc_fragment_key *key = g_slice_new(dcerpc_fragment_key);
1026 e_dce_dg_common_hdr_t *hdr = (e_dce_dg_common_hdr_t *)data;
1028 COPY_ADDRESS(&key->src, &pinfo->src);
1029 COPY_ADDRESS(&key->dst, &pinfo->dst);
1031 key->act_id = hdr->act_id;
1037 dcerpc_fragment_free_temporary_key(gpointer ptr)
1039 dcerpc_fragment_key *key = (dcerpc_fragment_key *)ptr;
1042 g_slice_free(dcerpc_fragment_key, key);
1046 dcerpc_fragment_free_persistent_key(gpointer ptr)
1048 dcerpc_fragment_key *key = (dcerpc_fragment_key *)ptr;
1052 * Free up the copies of the addresses from the old key.
1054 g_free((gpointer)key->src.data);
1055 g_free((gpointer)key->dst.data);
1057 g_slice_free(dcerpc_fragment_key, key);
1061 static const reassembly_table_functions dcerpc_cl_reassembly_table_functions = {
1062 dcerpc_fragment_hash,
1063 dcerpc_fragment_equal,
1064 dcerpc_fragment_temporary_key,
1065 dcerpc_fragment_persistent_key,
1066 dcerpc_fragment_free_temporary_key,
1067 dcerpc_fragment_free_persistent_key
1071 dcerpc_reassemble_init(void)
1074 * XXX - addresses_ports_reassembly_table_functions?
1075 * Or can a single connection-oriented DCE RPC session persist
1076 * over multiple transport layer connections?
1078 reassembly_table_init(&dcerpc_co_reassembly_table,
1079 &addresses_reassembly_table_functions);
1080 reassembly_table_init(&dcerpc_cl_reassembly_table,
1081 &dcerpc_cl_reassembly_table_functions);
1085 * Authentication subdissectors. Used to dissect authentication blobs in
1086 * DCERPC binds, requests and responses.
1089 typedef struct _dcerpc_auth_subdissector {
1092 dcerpc_auth_subdissector_fns auth_fns;
1093 } dcerpc_auth_subdissector;
1095 static GSList *dcerpc_auth_subdissector_list;
1097 static dcerpc_auth_subdissector_fns *get_auth_subdissector_fns(
1098 guint8 auth_level, guint8 auth_type)
1103 for (i = 0; (data = g_slist_nth_data(dcerpc_auth_subdissector_list, i)); i++) {
1104 dcerpc_auth_subdissector *asd = (dcerpc_auth_subdissector *)data;
1106 if ((asd->auth_level == auth_level) &&
1107 (asd->auth_type == auth_type))
1108 return &asd->auth_fns;
1114 void register_dcerpc_auth_subdissector(guint8 auth_level, guint8 auth_type,
1115 dcerpc_auth_subdissector_fns *fns)
1117 dcerpc_auth_subdissector *d;
1119 if (get_auth_subdissector_fns(auth_level, auth_type))
1122 d = (dcerpc_auth_subdissector *)g_malloc(sizeof(dcerpc_auth_subdissector));
1124 d->auth_level = auth_level;
1125 d->auth_type = auth_type;
1126 memcpy(&d->auth_fns, fns, sizeof(dcerpc_auth_subdissector_fns));
1128 dcerpc_auth_subdissector_list = g_slist_append(dcerpc_auth_subdissector_list, d);
1131 /* Hand off verifier data to a registered dissector */
1133 static void dissect_auth_verf(tvbuff_t *auth_tvb, packet_info *pinfo,
1135 dcerpc_auth_subdissector_fns *auth_fns,
1136 e_dce_cn_common_hdr_t *hdr,
1137 dcerpc_auth_info *auth_info)
1139 dcerpc_dissect_fnct_t *volatile fn = NULL;
1140 /* XXX - "stub" a fake DCERPC INFO STRUCTURE
1141 If a dcerpc_info is really needed, update
1142 the call stacks to include it
1144 FAKE_DCERPC_INFO_STRUCTURE
1146 switch (hdr->ptype) {
1149 fn = auth_fns->bind_fn;
1153 fn = auth_fns->bind_ack_fn;
1156 fn = auth_fns->auth3_fn;
1159 fn = auth_fns->req_verf_fn;
1162 fn = auth_fns->resp_verf_fn;
1165 /* Don't know how to handle authentication data in this
1169 g_warning("attempt to dissect %s pdu authentication data",
1170 val_to_str(hdr->ptype, pckt_vals, "Unknown (%u)"));
1175 fn(auth_tvb, 0, pinfo, tree, &di, hdr->drep);
1177 tvb_ensure_bytes_exist(auth_tvb, 0, hdr->auth_len);
1178 proto_tree_add_text(tree, auth_tvb, 0, hdr->auth_len,
1180 val_to_str(auth_info->auth_type,
1181 authn_protocol_vals,
1186 /* Hand off payload data to a registered dissector */
1188 static tvbuff_t *decode_encrypted_data(tvbuff_t *data_tvb,
1191 dcerpc_auth_subdissector_fns *auth_fns,
1192 gboolean is_request,
1193 dcerpc_auth_info *auth_info)
1195 dcerpc_decode_data_fnct_t *fn;
1198 fn = auth_fns->req_data_fn;
1200 fn = auth_fns->resp_data_fn;
1203 return fn(data_tvb, auth_tvb, 0, pinfo, auth_info);
1212 /* the registered subdissectors */
1213 GHashTable *dcerpc_uuids = NULL;
1216 dcerpc_uuid_equal(gconstpointer k1, gconstpointer k2)
1218 const dcerpc_uuid_key *key1 = (const dcerpc_uuid_key *)k1;
1219 const dcerpc_uuid_key *key2 = (const dcerpc_uuid_key *)k2;
1220 return ((memcmp(&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
1221 && (key1->ver == key2->ver));
1225 dcerpc_uuid_hash(gconstpointer k)
1227 const dcerpc_uuid_key *key = (const dcerpc_uuid_key *)k;
1228 /* This isn't perfect, but the Data1 part of these is almost always
1230 return key->uuid.Data1;
1234 dcerpc_init_uuid(int proto, int ett, e_uuid_t *uuid, guint16 ver,
1235 dcerpc_sub_dissector *procs, int opnum_hf)
1237 dcerpc_uuid_key *key = (dcerpc_uuid_key *)g_malloc(sizeof (*key));
1238 dcerpc_uuid_value *value = (dcerpc_uuid_value *)g_malloc(sizeof (*value));
1239 header_field_info *hf_info;
1240 module_t *samr_module;
1241 const char *filter_name = proto_get_protocol_filter_name(proto);
1246 value->proto = find_protocol_by_id(proto);
1247 value->proto_id = proto;
1249 value->name = proto_get_protocol_short_name(value->proto);
1250 value->procs = procs;
1251 value->opnum_hf = opnum_hf;
1253 g_hash_table_insert(dcerpc_uuids, key, value);
1255 hf_info = proto_registrar_get_nth(opnum_hf);
1256 hf_info->strings = value_string_from_subdissectors(procs);
1258 /* add this GUID to the global name resolving */
1259 guids_add_uuid(uuid, proto_get_protocol_short_name(value->proto));
1261 /* Register the samr.nt_password preference as obsolete */
1262 /* This should be in packet-dcerpc-samr.c */
1263 if (strcmp(filter_name, "samr") == 0) {
1264 samr_module = prefs_register_protocol(proto, NULL);
1265 prefs_register_obsolete_preference(samr_module, "nt_password");
1269 /* Function to find the name of a registered protocol
1270 * or NULL if the protocol/version is not known to wireshark.
1273 dcerpc_get_proto_name(e_uuid_t *uuid, guint16 ver)
1275 dcerpc_uuid_key key;
1276 dcerpc_uuid_value *sub_proto;
1280 if (!(sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key))) {
1283 return sub_proto->name;
1286 /* Function to find the opnum hf-field of a registered protocol
1287 * or -1 if the protocol/version is not known to wireshark.
1290 dcerpc_get_proto_hf_opnum(e_uuid_t *uuid, guint16 ver)
1292 dcerpc_uuid_key key;
1293 dcerpc_uuid_value *sub_proto;
1297 if (!(sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key))) {
1300 return sub_proto->opnum_hf;
1303 /* Create a value_string consisting of DCERPC opnum and name from a
1304 subdissector array. */
1306 value_string *value_string_from_subdissectors(dcerpc_sub_dissector *sd)
1308 value_string *vs = NULL;
1313 for (i = 0; sd[i].name; i++) {
1315 vs[i].value = sd[i].num;
1316 vs[i].strptr = sd[i].name;
1322 vs = (value_string *)wmem_alloc(wmem_epan_scope(), (num_sd + 1) * sizeof(value_string));
1326 vs[num_sd].value = 0;
1327 vs[num_sd].strptr = NULL;
1332 /* Function to find the subdissector table of a registered protocol
1333 * or NULL if the protocol/version is not known to wireshark.
1335 dcerpc_sub_dissector *
1336 dcerpc_get_proto_sub_dissector(e_uuid_t *uuid, guint16 ver)
1338 dcerpc_uuid_key key;
1339 dcerpc_uuid_value *sub_proto;
1343 if (!(sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key))) {
1346 return sub_proto->procs;
1352 dcerpc_bind_equal(gconstpointer k1, gconstpointer k2)
1354 const dcerpc_bind_key *key1 = (const dcerpc_bind_key *)k1;
1355 const dcerpc_bind_key *key2 = (const dcerpc_bind_key *)k2;
1356 return ((key1->conv == key2->conv)
1357 && (key1->ctx_id == key2->ctx_id)
1358 && (key1->smb_fid == key2->smb_fid));
1362 dcerpc_bind_hash(gconstpointer k)
1364 const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
1367 hash = GPOINTER_TO_UINT(key->conv) + key->ctx_id + key->smb_fid;
1373 * To keep track of callid mappings. Should really use some generic
1374 * conversation support instead.
1376 static GHashTable *dcerpc_cn_calls = NULL;
1377 static GHashTable *dcerpc_dg_calls = NULL;
1379 typedef struct _dcerpc_cn_call_key {
1380 conversation_t *conv;
1383 } dcerpc_cn_call_key;
1385 typedef struct _dcerpc_dg_call_key {
1386 conversation_t *conv;
1389 } dcerpc_dg_call_key;
1393 dcerpc_cn_call_equal(gconstpointer k1, gconstpointer k2)
1395 const dcerpc_cn_call_key *key1 = (const dcerpc_cn_call_key *)k1;
1396 const dcerpc_cn_call_key *key2 = (const dcerpc_cn_call_key *)k2;
1397 return ((key1->conv == key2->conv)
1398 && (key1->call_id == key2->call_id)
1399 && (key1->smb_fid == key2->smb_fid));
1403 dcerpc_dg_call_equal(gconstpointer k1, gconstpointer k2)
1405 const dcerpc_dg_call_key *key1 = (const dcerpc_dg_call_key *)k1;
1406 const dcerpc_dg_call_key *key2 = (const dcerpc_dg_call_key *)k2;
1407 return ((key1->conv == key2->conv)
1408 && (key1->seqnum == key2->seqnum)
1409 && ((memcmp(&key1->act_id, &key2->act_id, sizeof (e_uuid_t)) == 0)));
1413 dcerpc_cn_call_hash(gconstpointer k)
1415 const dcerpc_cn_call_key *key = (const dcerpc_cn_call_key *)k;
1416 return GPOINTER_TO_UINT(key->conv) + key->call_id + key->smb_fid;
1420 dcerpc_dg_call_hash(gconstpointer k)
1422 const dcerpc_dg_call_key *key = (const dcerpc_dg_call_key *)k;
1423 return (GPOINTER_TO_UINT(key->conv) + key->seqnum + key->act_id.Data1
1424 + (key->act_id.Data2 << 16) + key->act_id.Data3
1425 + (key->act_id.Data4[0] << 24) + (key->act_id.Data4[1] << 16)
1426 + (key->act_id.Data4[2] << 8) + (key->act_id.Data4[3] << 0)
1427 + (key->act_id.Data4[4] << 24) + (key->act_id.Data4[5] << 16)
1428 + (key->act_id.Data4[6] << 8) + (key->act_id.Data4[7] << 0));
1431 /* to keep track of matched calls/responses
1432 this one uses the same value struct as calls, but the key is the frame id
1433 and call id; there can be more than one call in a frame.
1435 XXX - why not just use the same keys as are used for calls?
1438 static GHashTable *dcerpc_matched = NULL;
1440 typedef struct _dcerpc_matched_key {
1443 } dcerpc_matched_key;
1446 dcerpc_matched_equal(gconstpointer k1, gconstpointer k2)
1448 const dcerpc_matched_key *key1 = (const dcerpc_matched_key *)k1;
1449 const dcerpc_matched_key *key2 = (const dcerpc_matched_key *)k2;
1450 return ((key1->frame == key2->frame)
1451 && (key1->call_id == key2->call_id));
1455 dcerpc_matched_hash(gconstpointer k)
1457 const dcerpc_matched_key *key = (const dcerpc_matched_key *)k;
1464 * Utility functions. Modeled after packet-rpc.c
1468 dissect_dcerpc_uint8(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1469 proto_tree *tree, guint8 *drep,
1470 int hfindex, guint8 *pdata)
1474 data = tvb_get_guint8(tvb, offset);
1476 proto_tree_add_item(tree, hfindex, tvb, offset, 1, DREP_ENC_INTEGER(drep));
1484 dissect_dcerpc_uint16(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1485 proto_tree *tree, guint8 *drep,
1486 int hfindex, guint16 *pdata)
1490 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1491 ? tvb_get_letohs(tvb, offset)
1492 : tvb_get_ntohs(tvb, offset));
1495 proto_tree_add_item(tree, hfindex, tvb, offset, 2, DREP_ENC_INTEGER(drep));
1503 dissect_dcerpc_uint32(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1504 proto_tree *tree, guint8 *drep,
1505 int hfindex, guint32 *pdata)
1509 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1510 ? tvb_get_letohl(tvb, offset)
1511 : tvb_get_ntohl(tvb, offset));
1514 proto_tree_add_item(tree, hfindex, tvb, offset, 4, DREP_ENC_INTEGER(drep));
1521 /* handles 32 bit unix time_t */
1523 dissect_dcerpc_time_t(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1524 proto_tree *tree, guint8 *drep,
1525 int hfindex, guint32 *pdata)
1530 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1531 ? tvb_get_letohl(tvb, offset)
1532 : tvb_get_ntohl(tvb, offset));
1537 if (data == 0xffffffff) {
1538 /* special case, no time specified */
1539 proto_tree_add_time_format_value(tree, hfindex, tvb, offset, 4, &tv, "No time specified");
1541 proto_tree_add_time(tree, hfindex, tvb, offset, 4, &tv);
1551 dissect_dcerpc_uint64(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1552 proto_tree *tree, guint8 *drep,
1553 int hfindex, guint64 *pdata)
1557 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1558 ? tvb_get_letoh64(tvb, offset)
1559 : tvb_get_ntoh64(tvb, offset));
1562 header_field_info *hfinfo;
1564 /* This might be a field that is either 32bit, in NDR or
1565 64 bits in NDR64. So we must be careful and call the right
1568 hfinfo = proto_registrar_get_nth(hfindex);
1570 switch (hfinfo->type) {
1572 proto_tree_add_uint64(tree, hfindex, tvb, offset, 8, data);
1575 proto_tree_add_int64(tree, hfindex, tvb, offset, 8, data);
1578 DISSECTOR_ASSERT(data <= G_MAXUINT32);
1579 proto_tree_add_uint(tree, hfindex, tvb, offset, 8, (guint32)data);
1589 dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1590 proto_tree *tree, guint8 *drep,
1591 int hfindex, gfloat *pdata)
1597 case(DCE_RPC_DREP_FP_IEEE):
1598 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1599 ? tvb_get_letohieee_float(tvb, offset)
1600 : tvb_get_ntohieee_float(tvb, offset));
1602 proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
1605 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
1606 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1607 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
1609 /* ToBeDone: non IEEE floating formats */
1610 /* Set data to a negative infinity value */
1613 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep[1]);
1623 dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1624 proto_tree *tree, guint8 *drep,
1625 int hfindex, gdouble *pdata)
1631 case(DCE_RPC_DREP_FP_IEEE):
1632 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1633 ? tvb_get_letohieee_double(tvb, offset)
1634 : tvb_get_ntohieee_double(tvb, offset));
1636 proto_tree_add_double(tree, hfindex, tvb, offset, 8, data);
1639 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
1640 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1641 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
1643 /* ToBeDone: non IEEE double formats */
1644 /* Set data to a negative infinity value */
1645 data = -G_MAXDOUBLE;
1647 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep[1]);
1657 dissect_dcerpc_uuid_t(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1658 proto_tree *tree, guint8 *drep,
1659 int hfindex, e_uuid_t *pdata)
1664 if (drep[0] & DREP_LITTLE_ENDIAN) {
1665 tvb_get_letohguid(tvb, offset, (e_guid_t *) &uuid);
1667 tvb_get_ntohguid(tvb, offset, (e_guid_t *) &uuid);
1670 proto_tree_add_guid(tree, hfindex, tvb, offset, 16, (e_guid_t *) &uuid);
1680 * a couple simpler things
1683 dcerpc_tvb_get_ntohs(tvbuff_t *tvb, gint offset, guint8 *drep)
1685 if (drep[0] & DREP_LITTLE_ENDIAN) {
1686 return tvb_get_letohs(tvb, offset);
1688 return tvb_get_ntohs(tvb, offset);
1693 dcerpc_tvb_get_ntohl(tvbuff_t *tvb, gint offset, guint8 *drep)
1695 if (drep[0] & DREP_LITTLE_ENDIAN) {
1696 return tvb_get_letohl(tvb, offset);
1698 return tvb_get_ntohl(tvb, offset);
1703 dcerpc_tvb_get_uuid(tvbuff_t *tvb, gint offset, guint8 *drep, e_uuid_t *uuid)
1705 if (drep[0] & DREP_LITTLE_ENDIAN) {
1706 tvb_get_letohguid(tvb, offset, (e_guid_t *) uuid);
1708 tvb_get_ntohguid(tvb, offset, (e_guid_t *) uuid);
1714 /* function to dissect a unidimensional conformant array */
1716 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1717 proto_tree *tree, dcerpc_info *di, guint8 *drep,
1718 dcerpc_dissect_fnct_t *fnct)
1722 int conformance_size = 4;
1724 if (di->call_data->flags & DCERPC_IS_NDR64) {
1725 conformance_size = 8;
1728 if (di->conformant_run) {
1731 /* conformant run, just dissect the max_count header */
1732 old_offset = offset;
1733 di->conformant_run = 0;
1734 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1735 hf_dcerpc_array_max_count, &val);
1736 di->array_max_count = (gint32)val;
1737 di->array_max_count_offset = offset-conformance_size;
1738 di->conformant_run = 1;
1739 di->conformant_eaten = offset-old_offset;
1741 /* we don't remember where in the bytestream this field was */
1742 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, conformance_size, di->array_max_count);
1744 /* real run, dissect the elements */
1745 for(i=0; i<di->array_max_count; i++) {
1746 offset = (*fnct)(tvb, offset, pinfo, tree, di, drep);
1753 /* function to dissect a unidimensional conformant and varying array
1754 * depending on the dissection function passed as a parameter,
1755 * content of the array will be dissected as a block or byte by byte
1758 dissect_ndr_ucvarray_core(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1759 proto_tree *tree, dcerpc_info *di, guint8 *drep,
1760 dcerpc_dissect_fnct_t *fnct_bytes,
1761 dcerpc_dissect_fnct_blk_t *fnct_block)
1765 int conformance_size = 4;
1767 if (di->call_data->flags & DCERPC_IS_NDR64) {
1768 conformance_size = 8;
1771 if (di->conformant_run) {
1774 /* conformant run, just dissect the max_count header */
1775 old_offset = offset;
1776 di->conformant_run = 0;
1777 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1778 hf_dcerpc_array_max_count, &val);
1779 DISSECTOR_ASSERT(val <= G_MAXUINT32);
1780 di->array_max_count = (guint32)val;
1781 di->array_max_count_offset = offset-conformance_size;
1782 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1783 hf_dcerpc_array_offset, &val);
1784 DISSECTOR_ASSERT(val <= G_MAXUINT32);
1785 di->array_offset = (guint32)val;
1786 di->array_offset_offset = offset-conformance_size;
1787 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1788 hf_dcerpc_array_actual_count, &val);
1789 DISSECTOR_ASSERT(val <= G_MAXUINT32);
1790 di->array_actual_count = (guint32)val;
1791 di->array_actual_count_offset = offset-conformance_size;
1792 di->conformant_run = 1;
1793 di->conformant_eaten = offset-old_offset;
1795 /* we don't remember where in the bytestream these fields were */
1796 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, conformance_size, di->array_max_count);
1797 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, conformance_size, di->array_offset);
1798 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, conformance_size, di->array_actual_count);
1800 /* real run, dissect the elements */
1802 offset = (*fnct_block)(tvb, offset, di->array_actual_count, pinfo, tree, drep);
1804 for(i=0 ;i<di->array_actual_count; i++) {
1805 old_offset = offset;
1806 offset = (*fnct_bytes)(tvb, offset, pinfo, tree, di, drep);
1807 if (offset <= old_offset)
1808 THROW(ReportedBoundsError);
1817 dissect_ndr_ucvarray_block(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1818 proto_tree *tree, dcerpc_info *di, guint8 *drep,
1819 dcerpc_dissect_fnct_blk_t *fnct)
1821 return dissect_ndr_ucvarray_core(tvb, offset, pinfo, tree, di, drep, NULL, fnct);
1825 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1826 proto_tree *tree, dcerpc_info *di, guint8 *drep,
1827 dcerpc_dissect_fnct_t *fnct)
1829 return dissect_ndr_ucvarray_core(tvb, offset, pinfo, tree, di, drep, fnct, NULL);
1831 /* function to dissect a unidimensional varying array */
1833 dissect_ndr_uvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1834 proto_tree *tree, dcerpc_info *di, guint8 *drep,
1835 dcerpc_dissect_fnct_t *fnct)
1839 int conformance_size = 4;
1841 if (di->call_data->flags & DCERPC_IS_NDR64) {
1842 conformance_size = 8;
1845 if (di->conformant_run) {
1848 /* conformant run, just dissect the max_count header */
1849 old_offset = offset;
1850 di->conformant_run = 0;
1851 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1852 hf_dcerpc_array_offset, &val);
1853 DISSECTOR_ASSERT(val <= G_MAXUINT32);
1854 di->array_offset = (guint32)val;
1855 di->array_offset_offset = offset-conformance_size;
1856 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1857 hf_dcerpc_array_actual_count, &val);
1858 DISSECTOR_ASSERT(val <= G_MAXUINT32);
1859 di->array_actual_count = (guint32)val;
1860 di->array_actual_count_offset = offset-conformance_size;
1861 di->conformant_run = 1;
1862 di->conformant_eaten = offset-old_offset;
1864 /* we don't remember where in the bytestream these fields were */
1865 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, conformance_size, di->array_offset);
1866 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, conformance_size, di->array_actual_count);
1868 /* real run, dissect the elements */
1869 for(i=0; i<di->array_actual_count; i++) {
1870 offset = (*fnct)(tvb, offset, pinfo, tree, di, drep);
1877 /* Dissect an string of bytes. This corresponds to
1878 IDL of the form '[string] byte *foo'.
1880 It can also be used for a conformant varying array of bytes if
1881 the contents of the array should be shown as a big blob, rather
1882 than showing each byte as an individual element.
1884 XXX - which of those is really the IDL type for, for example,
1885 the encrypted data in some MAPI packets? (Microsoft hasn't
1888 XXX - does this need to do all the conformant array stuff that
1889 "dissect_ndr_ucvarray()" does? These are presumably for strings
1890 that are conformant and varying - they're stored like conformant
1891 varying arrays of bytes. */
1893 dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo,
1894 proto_tree *tree, dcerpc_info *di, guint8 *drep)
1898 if (di->conformant_run) {
1899 /* just a run to handle conformant arrays, no scalars to dissect */
1903 /* NDR array header */
1905 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1906 hf_dcerpc_array_max_count, NULL);
1908 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1909 hf_dcerpc_array_offset, NULL);
1911 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1912 hf_dcerpc_array_actual_count, &len);
1914 DISSECTOR_ASSERT(len <= G_MAXUINT32);
1916 tvb_ensure_bytes_exist(tvb, offset, (guint32)len);
1917 proto_tree_add_item(tree, hf_dcerpc_array_buffer,
1918 tvb, offset, (guint32)len, ENC_NA);
1921 offset += (guint32)len;
1926 /* For dissecting arrays that are to be interpreted as strings. */
1928 /* Dissect an NDR conformant varying string of elements.
1929 The length of each element is given by the 'size_is' parameter;
1930 the elements are assumed to be characters or wide characters.
1932 XXX - does this need to do all the conformant array stuff that
1933 "dissect_ndr_ucvarray()" does? */
1935 dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1936 proto_tree *tree, dcerpc_info *di, guint8 *drep, int size_is,
1937 int hfindex, gboolean add_subtree, char **data)
1939 proto_item *string_item;
1940 proto_tree *string_tree;
1944 header_field_info *hfinfo;
1946 if (di->conformant_run) {
1947 /* just a run to handle conformant arrays, no scalars to dissect */
1952 string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1953 proto_registrar_get_name(hfindex));
1954 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1960 /* NDR array header */
1962 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
1963 hf_dcerpc_array_max_count, NULL);
1965 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
1966 hf_dcerpc_array_offset, NULL);
1968 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
1969 hf_dcerpc_array_actual_count, &len);
1971 DISSECTOR_ASSERT(len <= G_MAXUINT32);
1972 buffer_len = size_is * (guint32)len;
1975 if (!di->no_align && (offset % size_is))
1976 offset += size_is - (offset % size_is);
1978 if (size_is == sizeof(guint16)) {
1979 /* XXX - use drep to determine the byte order? */
1980 /* XXX - once we have an ENC_ value for UTF-16, just use
1981 proto_tree_add_item() with the appropriate ENC_ value? */
1982 /* XXX - should this ever be used with something that's *not*
1984 s = tvb_get_unicode_string(wmem_packet_scope(), tvb, offset, buffer_len, ENC_LITTLE_ENDIAN);
1985 if (tree && buffer_len) {
1986 hfinfo = proto_registrar_get_nth(hfindex);
1987 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1988 if (hfinfo->type == FT_STRING) {
1989 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1992 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1993 buffer_len, DREP_ENC_INTEGER(drep));
1999 * "tvb_get_string()" throws an exception if the entire string
2000 * isn't in the tvbuff. If the length is bogus, this should
2001 * keep us from trying to allocate an immensely large buffer.
2002 * (It won't help if the length is *valid* but immensely large,
2003 * but that's another matter; in any case, that would happen only
2004 * if we had an immensely large tvbuff....)
2006 * XXX - if this is an octet string, does the byte order
2007 * matter? Will this ever be anything *other* than an
2008 * octet string? What if size_is is neither 1 nor 2?
2010 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
2011 s = tvb_get_string(wmem_packet_scope(), tvb, offset, buffer_len);
2012 if (tree && buffer_len)
2013 proto_tree_add_item(string_tree, hfindex, tvb, offset,
2014 buffer_len, DREP_ENC_INTEGER(drep));
2017 if (string_item != NULL)
2018 proto_item_append_text(string_item, ": %s", s);
2023 offset += buffer_len;
2025 proto_item_set_end(string_item, tvb, offset);
2031 dissect_ndr_cstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2032 proto_tree *tree, dcerpc_info *di, guint8 *drep, int size_is,
2033 int hfindex, gboolean add_subtree, char **data)
2035 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep, size_is, hfindex, add_subtree, data);
2038 /* Dissect an conformant varying string of chars.
2039 This corresponds to IDL of the form '[string] char *foo'.
2041 XXX - at least according to the DCE RPC 1.1 spec, a string has
2042 a null terminator, which isn't necessary as a terminator for
2043 the transfer language (as there's a length), but is presumably
2044 there for the benefit of null-terminated-string languages
2045 such as C. Is this ever used for purely counted strings?
2046 (Not that it matters if it is.) */
2048 dissect_ndr_char_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2049 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2051 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep,
2052 sizeof(guint8), di->hf_index,
2056 /* Dissect a conformant varying string of wchars (wide characters).
2057 This corresponds to IDL of the form '[string] wchar *foo'
2059 XXX - at least according to the DCE RPC 1.1 spec, a string has
2060 a null terminator, which isn't necessary as a terminator for
2061 the transfer language (as there's a length), but is presumably
2062 there for the benefit of null-terminated-string languages
2063 such as C. Is this ever used for purely counted strings?
2064 (Not that it matters if it is.) */
2066 dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2067 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2069 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep,
2070 sizeof(guint16), di->hf_index,
2074 /* This function is aimed for PIDL usage and dissects a UNIQUE pointer to
2078 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)
2081 gint levels = CB_STR_ITEM_LEVELS(param);
2083 offset = dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep,
2087 if (!di->conformant_run) {
2088 /* Append string to COL_INFO */
2089 if (param & PIDL_SET_COL_INFO) {
2090 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", s);
2092 /* Save string to dcv->private_data */
2093 if ((param & PIDL_STR_SAVE)
2094 && (!pinfo->fd->flags.visited)) {
2095 dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2096 dcv->private_data = wmem_strdup(wmem_file_scope(), s);
2098 /* Append string to upper-level proto_items */
2099 if ((levels > 0) && tree && s && s[0]) {
2100 proto_item_append_text(tree, ": %s", s);
2101 tree = tree->parent;
2104 proto_item_append_text(tree, ": %s", s);
2105 tree = tree->parent;
2107 while (levels > 0) {
2108 proto_item_append_text(tree, " %s", s);
2109 tree = tree->parent;
2120 /* Dissect an NDR varying string of elements.
2121 The length of each element is given by the 'size_is' parameter;
2122 the elements are assumed to be characters or wide characters.
2125 dissect_ndr_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2126 proto_tree *tree, dcerpc_info *di, guint8 *drep, int size_is,
2127 int hfindex, gboolean add_subtree, char **data)
2129 proto_item *string_item;
2130 proto_tree *string_tree;
2134 header_field_info *hfinfo;
2136 if (di->conformant_run) {
2137 /* just a run to handle conformant arrays, no scalars to dissect */
2142 string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
2143 proto_registrar_get_name(hfindex));
2144 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
2150 /* NDR array header */
2151 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
2152 hf_dcerpc_array_offset, NULL);
2154 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
2155 hf_dcerpc_array_actual_count, &len);
2157 DISSECTOR_ASSERT(len <= G_MAXUINT32);
2158 buffer_len = size_is * (guint32)len;
2161 if (!di->no_align && (offset % size_is))
2162 offset += size_is - (offset % size_is);
2164 if (size_is == sizeof(guint16)) {
2165 /* XXX - use drep to determine the byte order? */
2166 /* XXX - once we have an ENC_ value for UTF-16, just use
2167 proto_tree_add_item() with the appropriate ENC_ value? */
2168 /* XXX - should this ever be used with something that's *not*
2170 s = tvb_get_unicode_string(wmem_packet_scope(), tvb, offset, buffer_len, ENC_LITTLE_ENDIAN);
2171 if (tree && buffer_len) {
2172 hfinfo = proto_registrar_get_nth(hfindex);
2173 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
2174 if (hfinfo->type == FT_STRING) {
2175 proto_tree_add_string(string_tree, hfindex, tvb, offset,
2178 proto_tree_add_item(string_tree, hfindex, tvb, offset,
2179 buffer_len, DREP_ENC_INTEGER(drep));
2185 * "tvb_get_string()" throws an exception if the entire string
2186 * isn't in the tvbuff. If the length is bogus, this should
2187 * keep us from trying to allocate an immensely large buffer.
2188 * (It won't help if the length is *valid* but immensely large,
2189 * but that's another matter; in any case, that would happen only
2190 * if we had an immensely large tvbuff....)
2192 * XXX - if this is an octet string, does the byte order
2193 * matter? Will this ever be anything *other* than an
2194 * octet string? What if size_is is neither 1 nor 2?
2196 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
2197 s = tvb_get_string(wmem_packet_scope(), tvb, offset, buffer_len);
2198 if (tree && buffer_len)
2199 proto_tree_add_item(string_tree, hfindex, tvb, offset,
2200 buffer_len, DREP_ENC_INTEGER(drep));
2203 if (string_item != NULL)
2204 proto_item_append_text(string_item, ": %s", s);
2209 offset += buffer_len;
2211 proto_item_set_end(string_item, tvb, offset);
2216 /* Dissect an varying string of chars.
2217 This corresponds to IDL of the form '[string] char *foo'.
2219 XXX - at least according to the DCE RPC 1.1 spec, a string has
2220 a null terminator, which isn't necessary as a terminator for
2221 the transfer language (as there's a length), but is presumably
2222 there for the benefit of null-terminated-string languages
2223 such as C. Is this ever used for purely counted strings?
2224 (Not that it matters if it is.) */
2226 dissect_ndr_char_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2227 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2229 return dissect_ndr_vstring(tvb, offset, pinfo, tree, di, drep,
2230 sizeof(guint8), di->hf_index,
2234 /* Dissect a varying string of wchars (wide characters).
2235 This corresponds to IDL of the form '[string] wchar *foo'
2237 XXX - at least according to the DCE RPC 1.1 spec, a string has
2238 a null terminator, which isn't necessary as a terminator for
2239 the transfer language (as there's a length), but is presumably
2240 there for the benefit of null-terminated-string languages
2241 such as C. Is this ever used for purely counted strings?
2242 (Not that it matters if it is.) */
2244 dissect_ndr_wchar_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2245 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2247 return dissect_ndr_vstring(tvb, offset, pinfo, tree, di, drep,
2248 sizeof(guint16), di->hf_index,
2253 /* ndr pointer handling */
2254 /* list of pointers encountered so far */
2255 static GSList *ndr_pointer_list = NULL;
2257 /* position where in the list to insert newly encountered pointers */
2258 static int ndr_pointer_list_pos = 0;
2260 /* Boolean controlling whether pointers are top-level or embedded */
2261 static gboolean pointers_are_top_level = TRUE;
2263 /* as a kludge, we represent all embedded reference pointers as id == -1
2264 hoping that his will not collide with any non-ref pointers */
2265 typedef struct ndr_pointer_data {
2267 proto_item *item; /* proto_item for pointer */
2268 proto_tree *tree; /* subtree of above item */
2269 dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
2271 dcerpc_callback_fnct_t *callback;
2272 void *callback_args;
2273 } ndr_pointer_data_t;
2276 init_ndr_pointer_list(dcerpc_info *di)
2278 di->conformant_run = 0;
2280 while (ndr_pointer_list) {
2281 ndr_pointer_data_t *npd = (ndr_pointer_data_t *)g_slist_nth_data(ndr_pointer_list, 0);
2282 ndr_pointer_list = g_slist_remove(ndr_pointer_list, npd);
2286 ndr_pointer_list = NULL;
2287 ndr_pointer_list_pos = 0;
2288 pointers_are_top_level = TRUE;
2292 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, dcerpc_info *di, guint8 *drep)
2294 int found_new_pointer;
2303 found_new_pointer = 0;
2304 len = g_slist_length(ndr_pointer_list);
2305 for(i=next_pointer; i<len; i++) {
2306 ndr_pointer_data_t *tnpd = (ndr_pointer_data_t *)g_slist_nth_data(ndr_pointer_list, i);
2308 dcerpc_dissect_fnct_t *fnct;
2311 found_new_pointer = 1;
2314 ndr_pointer_list_pos = i+1;
2315 di->hf_index = tnpd->hf_index;
2316 /* first a run to handle any conformant
2318 di->conformant_run = 1;
2319 di->conformant_eaten = 0;
2320 old_offset = offset;
2321 offset = (*(fnct))(tvb, offset, pinfo, NULL, di, drep);
2323 DISSECTOR_ASSERT((offset-old_offset) == di->conformant_eaten);
2324 /* This is to check for any bugs in the dissectors.
2326 * Basically, the NDR representation will store all
2327 * arrays in two blocks, one block with the dimension
2328 * description, like size, number of elements and such,
2329 * and another block that contains the actual data stored
2331 * If the array is embedded directly inside another,
2332 * encapsulating aggregate type, like a union or struct,
2333 * then these two blocks will be stored at different places
2334 * in the bytestream, with other data between the blocks.
2336 * For this reason, all pointers to types (both aggregate
2337 * and scalar, for simplicity no distinction is made)
2338 * will have its dissector called twice.
2339 * The dissector will first be called with conformant_run == 1
2340 * in which mode the dissector MUST NOT consume any data from
2341 * the tvbuff (i.e. may not dissect anything) except the
2342 * initial control block for arrays.
2343 * The second time the dissector is called, with
2344 * conformant_run == 0, all other data for the type will be
2347 * All dissect_ndr_<type> dissectors are already prepared
2348 * for this and knows when it should eat data from the tvb
2349 * and when not to, so implementors of dissectors will
2350 * normally not need to worry about this or even know about
2351 * it. However, if a dissector for an aggregate type calls
2352 * a subdissector from outside packet-dcerpc.c, such as
2353 * the dissector in packet-smb.c for NT Security Descriptors
2354 * as an example, then it is VERY important to encapsulate
2355 * this call to an external subdissector with the appropriate
2356 * test for conformant_run, i.e. it will need something like
2358 * dcerpc_info *di (received as function parameter)
2360 * if (di->conformant_run) {
2364 * to make sure it makes the right thing.
2365 * This assert will signal when someone has forgotten to
2366 * make the dissector aware of this requirement.
2369 /* now we dissect the actual pointer */
2370 di->conformant_run = 0;
2371 old_offset = offset;
2372 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, di, drep);
2374 tnpd->callback(pinfo, tnpd->tree, tnpd->item, di, tvb, old_offset, offset, tnpd->callback_args);
2375 proto_item_set_len(tnpd->item, offset - old_offset);
2379 } while (found_new_pointer);
2386 add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
2387 dcerpc_info *di, dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index,
2388 dcerpc_callback_fnct_t *callback, void *callback_args)
2390 ndr_pointer_data_t *npd;
2392 /* check if this pointer is valid */
2393 if (id != 0xffffffff) {
2394 dcerpc_call_value *value;
2396 value = di->call_data;
2398 if (di->ptype == PDU_REQ) {
2399 if (!(pinfo->fd->flags.visited)) {
2400 if (id > value->max_ptr) {
2401 value->max_ptr = id;
2405 /* if we haven't seen the request bail out since we cant
2406 know whether this is the first non-NULL instance
2408 if (value->req_frame == 0) {
2409 /* XXX THROW EXCEPTION */
2412 /* We saw this one in the request frame, nothing to
2414 if (id <= value->max_ptr) {
2420 npd = (ndr_pointer_data_t *)g_malloc(sizeof(ndr_pointer_data_t));
2425 npd->hf_index = hf_index;
2426 npd->callback = callback;
2427 npd->callback_args = callback_args;
2428 ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
2429 ndr_pointer_list_pos);
2430 ndr_pointer_list_pos++;
2435 find_pointer_index(guint32 id)
2437 ndr_pointer_data_t *npd;
2440 len = g_slist_length(ndr_pointer_list);
2441 for(i=0; i<len; i++) {
2442 npd = (ndr_pointer_data_t *)g_slist_nth_data(ndr_pointer_list, i);
2444 if (npd->id == id) {
2453 /* This function dissects an NDR pointer and stores the callback for later
2454 * deferred dissection.
2456 * fnct is the callback function for when we have reached this object in
2459 * type is what type of pointer.
2461 * this is text is what text we should put in any created tree node.
2463 * hf_index is what hf value we want to pass to the callback function when
2464 * it is called, the callback can later pick this one up from di->hf_index.
2466 * callback is executed after the pointer has been dereferenced.
2468 * callback_args is passed as an argument to the callback function
2470 * See packet-dcerpc-samr.c for examples
2473 dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2474 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2475 int type, const char *text, int hf_index,
2476 dcerpc_callback_fnct_t *callback, void *callback_args)
2478 proto_tree *tr = NULL;
2479 gint start_offset = offset;
2480 int pointer_size = 4;
2482 if (di->conformant_run) {
2483 /* this call was only for dissecting the header for any
2484 embedded conformant array. we will not parse any
2485 pointers in this mode.
2489 if (di->call_data->flags & DCERPC_IS_NDR64) {
2494 /*TOP LEVEL REFERENCE POINTER*/
2495 if ( pointers_are_top_level
2496 && (type == NDR_POINTER_REF) ) {
2499 /* we must find out a nice way to do the length here */
2500 item = proto_tree_add_text(tree, tvb, offset, 0,
2502 tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2504 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
2505 hf_index, callback, callback_args);
2509 /*TOP LEVEL FULL POINTER*/
2510 if ( pointers_are_top_level
2511 && (type == NDR_POINTER_PTR) ) {
2516 /* get the referent id */
2517 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
2519 tvb_ensure_bytes_exist(tvb, offset-pointer_size, pointer_size);
2520 /* we got a NULL pointer */
2522 proto_tree_add_text(tree, tvb, offset-pointer_size,
2524 "(NULL pointer) %s",text);
2528 /* see if we have seen this pointer before */
2529 DISSECTOR_ASSERT(id <= G_MAXUINT32);
2530 idx = find_pointer_index((guint32)id);
2532 /* we have seen this pointer before */
2534 proto_tree_add_text(tree, tvb, offset-pointer_size,
2536 "(duplicate PTR) %s",text);
2541 item = proto_tree_add_text(tree, tvb, offset-pointer_size,
2544 tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2545 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb,
2546 offset-pointer_size, pointer_size, (guint32)id);
2547 add_pointer_to_list(pinfo, tr, item, di, fnct, (guint32)id, hf_index,
2548 callback, callback_args);
2551 /*TOP LEVEL UNIQUE POINTER*/
2552 if ( pointers_are_top_level
2553 && (type == NDR_POINTER_UNIQUE) ) {
2557 /* get the referent id */
2558 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
2560 tvb_ensure_bytes_exist(tvb, offset-pointer_size, pointer_size);
2561 /* we got a NULL pointer */
2563 proto_tree_add_text(tree, tvb, offset-pointer_size,
2565 "(NULL pointer) %s",text);
2570 DISSECTOR_ASSERT(id <= G_MAXUINT32);
2571 item = proto_tree_add_text(tree, tvb, offset-pointer_size,
2574 tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2575 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb,
2576 offset-pointer_size, pointer_size, (guint32)id);
2577 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
2578 hf_index, callback, callback_args);
2582 /*EMBEDDED REFERENCE POINTER*/
2583 if ( (!pointers_are_top_level)
2584 && (type == NDR_POINTER_REF) ) {
2588 /* get the referent id */
2589 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
2591 tvb_ensure_bytes_exist(tvb, offset-pointer_size, pointer_size);
2593 item = proto_tree_add_text(tree, tvb, offset-pointer_size,
2596 tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2597 DISSECTOR_ASSERT(id <= G_MAXUINT32);
2598 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb,
2599 offset-pointer_size, pointer_size, (guint32)id);
2600 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
2601 hf_index, callback, callback_args);
2605 /*EMBEDDED UNIQUE POINTER*/
2606 if ( (!pointers_are_top_level)
2607 && (type == NDR_POINTER_UNIQUE) ) {
2611 /* get the referent id */
2612 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
2614 tvb_ensure_bytes_exist(tvb, offset-pointer_size, pointer_size);
2615 /* we got a NULL pointer */
2617 proto_tree_add_text(tree, tvb, offset-pointer_size,
2619 "(NULL pointer) %s", text);
2624 item = proto_tree_add_text(tree, tvb, offset-pointer_size,
2627 tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2628 DISSECTOR_ASSERT(id <= G_MAXUINT32);
2629 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb,
2630 offset-pointer_size, pointer_size, (guint32)id);
2631 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
2632 hf_index, callback, callback_args);
2636 /*EMBEDDED FULL POINTER*/
2637 if ( (!pointers_are_top_level)
2638 && (type == NDR_POINTER_PTR) ) {
2643 /* get the referent id */
2644 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
2646 tvb_ensure_bytes_exist(tvb, offset-pointer_size, pointer_size);
2647 /* we got a NULL pointer */
2649 proto_tree_add_text(tree, tvb, offset-pointer_size,
2651 "(NULL pointer) %s",text);
2655 /* see if we have seen this pointer before */
2656 DISSECTOR_ASSERT(id <= G_MAXUINT32);
2657 idx = find_pointer_index((guint32)id);
2659 /* we have seen this pointer before */
2661 proto_tree_add_text(tree, tvb, offset-pointer_size,
2663 "(duplicate PTR) %s",text);
2668 item = proto_tree_add_text(tree, tvb, offset-pointer_size,
2671 tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2672 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb,
2673 offset-pointer_size, pointer_size, (guint32)id);
2674 add_pointer_to_list(pinfo, tr, item, di, fnct, (guint32)id, hf_index,
2675 callback, callback_args);
2681 /* After each top level pointer we have dissected we have to
2682 dissect all deferrals before we move on to the next top level
2684 if (pointers_are_top_level == TRUE) {
2685 pointers_are_top_level = FALSE;
2686 offset = dissect_deferred_pointers(pinfo, tvb, offset, di, drep);
2687 pointers_are_top_level = TRUE;
2690 /* Set the length for the new subtree */
2692 proto_item_set_len(tr, offset-start_offset);
2698 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2699 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2700 int type, const char *text, int hf_index)
2702 return dissect_ndr_pointer_cb(
2703 tvb, offset, pinfo, tree, di, drep, fnct, type, text, hf_index,
2707 dissect_ndr_toplevel_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2708 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2709 int type, const char *text, int hf_index)
2713 pointers_are_top_level = TRUE;
2714 ret = dissect_ndr_pointer_cb(
2715 tvb, offset, pinfo, tree, di, drep, fnct, type, text, hf_index,
2720 dissect_ndr_embedded_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2721 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2722 int type, const char *text, int hf_index)
2726 pointers_are_top_level = FALSE;
2727 ret = dissect_ndr_pointer_cb(
2728 tvb, offset, pinfo, tree, di, drep, fnct, type, text, hf_index,
2734 show_stub_data(tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
2735 dcerpc_auth_info *auth_info, gboolean is_encrypted)
2737 int length, plain_length, auth_pad_len;
2738 guint auth_pad_offset;
2741 * We don't show stub data unless we have some in the tvbuff;
2742 * however, in the protocol tree, we show, as the number of
2743 * bytes, the reported number of bytes, not the number of bytes
2744 * that happen to be in the tvbuff.
2746 if (tvb_length_remaining(tvb, offset) > 0) {
2747 auth_pad_len = auth_info?auth_info->auth_pad_len:0;
2748 length = tvb_reported_length_remaining(tvb, offset);
2750 /* if auth_pad_len is larger than length then we ignore auth_pad_len totally */
2751 plain_length = length - auth_pad_len;
2752 if (plain_length < 1) {
2753 plain_length = length;
2756 auth_pad_offset = offset + plain_length;
2758 if ((auth_info != NULL) &&
2759 (auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)) {
2761 tvb_ensure_bytes_exist(tvb, offset, length);
2762 proto_tree_add_text(dcerpc_tree, tvb, offset, length,
2763 "Encrypted stub data (%d byte%s)",
2764 length, plurality(length, "", "s"));
2765 /* is the padding is still inside the encrypted blob, don't display it explicit */
2768 tvb_ensure_bytes_exist(tvb, offset, plain_length);
2769 proto_tree_add_text(dcerpc_tree, tvb, offset, plain_length,
2770 "Decrypted stub data (%d byte%s)",
2771 plain_length, plurality(plain_length, "", "s"));
2774 tvb_ensure_bytes_exist(tvb, offset, plain_length);
2775 proto_tree_add_text(dcerpc_tree, tvb, offset, plain_length,
2776 "Stub data (%d byte%s)", plain_length,
2777 plurality(plain_length, "", "s"));
2779 /* If there is auth padding at the end of the stub, display it */
2780 if (auth_pad_len != 0) {
2781 tvb_ensure_bytes_exist(tvb, auth_pad_offset, auth_pad_len);
2782 proto_tree_add_text(dcerpc_tree, tvb, auth_pad_offset,
2784 "Auth Padding (%u byte%s)",
2786 plurality(auth_pad_len, "", "s"));
2792 dcerpc_try_handoff(packet_info *pinfo, proto_tree *tree,
2793 proto_tree *dcerpc_tree,
2794 tvbuff_t *volatile tvb, tvbuff_t *decrypted_tvb,
2795 guint8 *drep, dcerpc_info *info,
2796 dcerpc_auth_info *auth_info)
2798 volatile gint offset = 0;
2799 dcerpc_uuid_key key;
2800 dcerpc_uuid_value *sub_proto;
2801 proto_tree *volatile sub_tree = NULL;
2802 dcerpc_sub_dissector *proc;
2803 const gchar *name = NULL;
2804 const char *volatile saved_proto;
2805 guint length = 0, reported_length = 0;
2806 tvbuff_t *volatile stub_tvb;
2807 volatile guint auth_pad_len;
2808 volatile int auth_pad_offset;
2809 proto_item *sub_item = NULL;
2810 proto_item *pi, *hidden_item;
2812 dcerpc_dissect_fnct_t *volatile sub_dissect;
2814 key.uuid = info->call_data->uuid;
2815 key.ver = info->call_data->ver;
2817 if ((sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key)) == NULL
2818 || !proto_is_protocol_enabled(sub_proto->proto)) {
2820 * We don't have a dissector for this UUID, or the protocol
2821 * for that UUID is disabled.
2824 hidden_item = proto_tree_add_boolean(dcerpc_tree, hf_dcerpc_unknown_if_id,
2825 tvb, offset, 0, TRUE);
2826 PROTO_ITEM_SET_HIDDEN(hidden_item);
2827 col_append_fstr(pinfo->cinfo, COL_INFO, " %s V%u",
2828 guids_resolve_uuid_to_str(&info->call_data->uuid), info->call_data->ver);
2830 if (decrypted_tvb != NULL) {
2831 show_stub_data(decrypted_tvb, 0, dcerpc_tree, auth_info,
2834 show_stub_data(tvb, 0, dcerpc_tree, auth_info, TRUE);
2838 for (proc = sub_proto->procs; proc->name; proc++) {
2839 if (proc->num == info->call_data->opnum) {
2845 col_set_str(pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
2848 col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown operation %u %s",
2849 info->call_data->opnum,
2850 (info->ptype == PDU_REQ) ? "request" : "response");
2852 col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
2853 name, (info->ptype == PDU_REQ) ? "request" : "response");
2855 sub_dissect = (info->ptype == PDU_REQ) ?
2856 proc->dissect_rqst : proc->dissect_resp;
2859 sub_item = proto_tree_add_item(tree, sub_proto->proto_id,
2860 (decrypted_tvb != NULL)?decrypted_tvb:tvb,
2864 sub_tree = proto_item_add_subtree(sub_item, sub_proto->ett);
2866 proto_item_append_text(sub_item, ", unknown operation %u",
2867 info->call_data->opnum);
2869 proto_item_append_text(sub_item, ", %s", name);
2873 * Put the operation number into the tree along with
2874 * the operation's name.
2876 if (sub_proto->opnum_hf != -1)
2877 proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
2878 tvb, 0, 0, info->call_data->opnum,
2879 "Operation: %s (%u)",
2880 name ? name : "Unknown operation",
2881 info->call_data->opnum);
2883 proto_tree_add_uint_format_value(sub_tree, hf_dcerpc_op, tvb,
2884 0, 0, info->call_data->opnum,
2886 name ? name : "Unknown operation",
2887 info->call_data->opnum);
2889 if ((info->ptype == PDU_REQ) && (info->call_data->rep_frame != 0)) {
2890 pi = proto_tree_add_uint(sub_tree, hf_dcerpc_response_in,
2891 tvb, 0, 0, info->call_data->rep_frame);
2892 PROTO_ITEM_SET_GENERATED(pi);
2894 if ((info->ptype == PDU_RESP) && (info->call_data->req_frame != 0)) {
2895 pi = proto_tree_add_uint(sub_tree, hf_dcerpc_request_in,
2896 tvb, 0, 0, info->call_data->req_frame);
2897 PROTO_ITEM_SET_GENERATED(pi);
2901 if (decrypted_tvb != NULL) {
2902 /* Either there was no encryption or we successfully decrypted
2903 the encrypted payload. */
2905 /* We have a subdissector - call it. */
2906 saved_proto = pinfo->current_proto;
2907 pinfo->current_proto = sub_proto->name;
2909 init_ndr_pointer_list(info);
2911 length = tvb_length(decrypted_tvb);
2912 reported_length = tvb_reported_length(decrypted_tvb);
2915 * Remove the authentication padding from the stub data.
2917 if ((auth_info != NULL) && (auth_info->auth_pad_len != 0)) {
2918 if (reported_length >= auth_info->auth_pad_len) {
2920 * OK, the padding length isn't so big that it
2921 * exceeds the stub length. Trim the reported
2922 * length of the tvbuff.
2924 reported_length -= auth_info->auth_pad_len;
2927 * If that exceeds the actual amount of data in
2928 * the tvbuff (which means we have at least one
2929 * byte of authentication padding in the tvbuff),
2930 * trim the actual amount.
2932 if (length > reported_length)
2933 length = reported_length;
2935 stub_tvb = tvb_new_subset(decrypted_tvb, 0, length, reported_length);
2936 auth_pad_len = auth_info->auth_pad_len;
2937 auth_pad_offset = reported_length;
2940 * The padding length exceeds the stub length.
2941 * Don't bother dissecting the stub, trim the padding
2942 * length to what's in the stub data, and show the
2943 * entire stub as authentication padding.
2946 auth_pad_len = reported_length;
2947 auth_pad_offset = 0;
2952 * No authentication padding.
2954 stub_tvb = decrypted_tvb;
2956 auth_pad_offset = 0;
2960 proto_item_set_len(sub_item, length);
2963 if (stub_tvb != NULL) {
2965 * Catch all exceptions other than BoundsError, so that even
2966 * if the stub data is bad, we still show the authentication
2969 * If we get BoundsError, it means the frame was cut short
2970 * by a snapshot length, so there's nothing more to
2971 * dissect; just re-throw that exception.
2976 offset = sub_dissect(stub_tvb, 0, pinfo, sub_tree,
2979 /* If we have a subdissector and it didn't dissect all
2980 data in the tvb, make a note of it. */
2981 remaining = tvb_reported_length_remaining(stub_tvb, offset);
2982 if (remaining > 0) {
2983 proto_tree_add_text(sub_tree, stub_tvb, offset,
2985 "[Long frame (%d byte%s)]",
2987 plurality(remaining, "", "s"));
2988 col_append_fstr(pinfo->cinfo, COL_INFO,
2989 "[Long frame (%d byte%s)]",
2991 plurality(remaining, "", "s"));
2994 } CATCH_NONFATAL_ERRORS {
2996 * Somebody threw an exception that means that there
2997 * was a problem dissecting the payload; that means
2998 * that a dissector was found, so we don't need to
2999 * dissect the payload as data or update the protocol
3002 * Just show the exception and then drive on to show
3003 * the authentication padding.
3005 show_exception(stub_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
3009 /* If there is auth padding at the end of the stub, display it */
3010 if (auth_pad_len != 0) {
3011 tvb_ensure_bytes_exist(tvb, auth_pad_offset, auth_pad_len);
3012 proto_tree_add_text(sub_tree, decrypted_tvb, auth_pad_offset,
3014 "Auth Padding (%u byte%s)",
3016 plurality(auth_pad_len, "", "s"));
3019 pinfo->current_proto = saved_proto;
3021 /* No subdissector - show it as stub data. */
3022 if (decrypted_tvb) {
3023 show_stub_data(decrypted_tvb, 0, sub_tree, auth_info, FALSE);
3025 show_stub_data(tvb, 0, sub_tree, auth_info, TRUE);
3029 show_stub_data(tvb, 0, sub_tree, auth_info, TRUE);
3031 tap_queue_packet(dcerpc_tap, pinfo, info);
3036 dissect_dcerpc_verifier(tvbuff_t *tvb, packet_info *pinfo,
3037 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
3038 dcerpc_auth_info *auth_info)
3042 auth_info->auth_data = NULL;
3044 if (auth_info->auth_size != 0) {
3045 dcerpc_auth_subdissector_fns *auth_fns;
3048 auth_offset = hdr->frag_len - hdr->auth_len;
3050 auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
3053 auth_info->auth_data = auth_tvb;
3055 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
3056 auth_info->auth_type))) {
3058 * Catch all bounds-error exceptions, so that even if the
3059 * verifier is bad or we don't have all of it, we still
3060 * show the stub data.
3063 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
3065 } CATCH_BOUNDS_ERRORS {
3066 show_exception(auth_tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
3069 tvb_ensure_bytes_exist(tvb, 0, hdr->auth_len);
3070 proto_tree_add_text(dcerpc_tree, auth_tvb, 0, hdr->auth_len,
3075 return hdr->auth_len;
3079 dissect_dcerpc_cn_auth(tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
3080 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
3081 gboolean are_credentials, dcerpc_auth_info *auth_info)
3083 volatile int offset;
3086 * Initially set auth_level and auth_type to zero to indicate that we
3087 * haven't yet seen any authentication level information.
3089 auth_info->auth_level = 0;
3090 auth_info->auth_type = 0;
3091 auth_info->auth_size = 0;
3092 auth_info->auth_pad_len = 0;
3095 * The authentication information is at the *end* of the PDU; in
3096 * request and response PDUs, the request and response stub data
3099 * Is there any authentication data (i.e., is the authentication length
3100 * non-zero), and is the authentication length valid (i.e., is it, plus
3101 * 8 bytes for the type/level/pad length/reserved/context id, less than
3102 * or equal to the fragment length minus the starting offset of the
3107 && ((hdr->auth_len + 8) <= (hdr->frag_len - stub_offset))) {
3110 * Yes, there is authentication data, and the length is valid.
3111 * Do we have all the bytes of stub data?
3112 * (If not, we'd throw an exception dissecting *that*, so don't
3113 * bother trying to dissect the authentication information and
3114 * throwing another exception there.)
3116 offset = hdr->frag_len - (hdr->auth_len + 8);
3117 if (offset == 0 || tvb_offset_exists(tvb, offset - 1)) {
3119 * Either there's no stub data, or the last byte of the stub
3120 * data is present in the captured data, so we shouldn't
3121 * get a BoundsError dissecting the stub data.
3123 * Try dissecting the authentication data.
3124 * Catch all exceptions, so that even if the auth info is bad
3125 * or we don't have all of it, we still show the stuff we
3126 * dissect after this, such as stub data.
3129 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3130 hf_dcerpc_auth_type,
3131 &auth_info->auth_type);
3132 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3133 hf_dcerpc_auth_level,
3134 &auth_info->auth_level);
3136 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3137 hf_dcerpc_auth_pad_len,
3138 &auth_info->auth_pad_len);
3139 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3140 hf_dcerpc_auth_rsrvd, NULL);
3141 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3142 hf_dcerpc_auth_ctx_id, NULL);
3145 * Dissect the authentication data.
3147 if (are_credentials) {
3149 dcerpc_auth_subdissector_fns *auth_fns;
3151 auth_tvb = tvb_new_subset(tvb, offset,
3152 MIN(hdr->auth_len,tvb_length_remaining(tvb, offset)),
3155 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
3156 auth_info->auth_type)))
3157 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
3160 proto_tree_add_text(dcerpc_tree, tvb, offset, hdr->auth_len,
3161 "Auth Credentials");
3164 /* Compute the size of the auth block. Note that this should not
3165 include auth padding, since when NTLMSSP encryption is used, the
3166 padding is actually inside the encrypted stub */
3167 auth_info->auth_size = hdr->auth_len + 8;
3168 } CATCH_BOUNDS_ERRORS {
3169 show_exception(tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
3176 /* We need to hash in the SMB fid number to generate a unique hash table
3177 * key as DCERPC over SMB allows several pipes over the same TCP/IP
3179 * We pass this function the transport type here to make sure we only look
3180 * at this function if it came across an SMB pipe.
3181 * Other transports might need to mix in their own extra multiplexing data
3182 * as well in the future.
3185 guint16 dcerpc_get_transport_salt(packet_info *pinfo)
3187 switch (pinfo->dcetransporttype) {
3188 case DCE_CN_TRANSPORT_SMBPIPE:
3189 /* DCERPC over smb */
3190 return pinfo->dcetransportsalt;
3193 /* Some other transport... */
3198 * Connection oriented packet types
3202 dissect_dcerpc_cn_bind(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3203 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
3205 conversation_t *conv = find_or_create_conversation(pinfo);
3206 guint8 num_ctx_items = 0;
3209 guint8 num_trans_items;
3214 guint16 if_ver, if_ver_minor;
3215 dcerpc_auth_info auth_info;
3217 const char *uuid_name = NULL;
3218 proto_item *iface_item = NULL;
3220 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3221 hf_dcerpc_cn_max_xmit, NULL);
3223 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3224 hf_dcerpc_cn_max_recv, NULL);
3226 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3227 hf_dcerpc_cn_assoc_group, NULL);
3229 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3230 hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
3235 col_append_fstr(pinfo->cinfo, COL_INFO, ", %u context items:", num_ctx_items);
3237 for (i = 0; i < num_ctx_items; i++) {
3238 proto_item *ctx_item = NULL;
3239 proto_tree *ctx_tree = NULL, *iface_tree = NULL;
3240 gint ctx_offset = offset;
3242 dissect_dcerpc_uint16(tvb, offset, pinfo, NULL, hdr->drep,
3243 hf_dcerpc_cn_ctx_id, &ctx_id);
3245 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3246 /* (if we have multiple contexts, this might cause "decode as"
3247 * to behave unpredictably) */
3248 pinfo->dcectxid = ctx_id;
3251 ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_item,
3254 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
3257 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree, hdr->drep,
3258 hf_dcerpc_cn_ctx_id, &ctx_id);
3259 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, ctx_tree, hdr->drep,
3260 hf_dcerpc_cn_num_trans_items, &num_trans_items);
3263 proto_item_append_text(ctx_item, "[%u]: Context ID:%u", i+1, ctx_id);
3269 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &if_id);
3272 iface_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_abstract_syntax, tvb, offset, 0, ENC_NA);
3273 iface_tree = proto_item_add_subtree(iface_item, ett_dcerpc_cn_iface);
3275 uuid_str = guid_to_str((e_guid_t*)&if_id);
3276 uuid_name = guids_get_uuid_name(&if_id);
3278 proto_tree_add_guid_format(iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
3279 offset, 16, (e_guid_t *) &if_id, "Interface: %s UUID: %s", uuid_name, uuid_str);
3280 proto_item_append_text(iface_item, ": %s", uuid_name);
3281 proto_item_append_text(ctx_item, ", %s", uuid_name);
3283 proto_tree_add_guid_format(iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
3284 offset, 16, (e_guid_t *) &if_id, "Interface UUID: %s", uuid_str);
3285 proto_item_append_text(iface_item, ": %s", uuid_str);
3286 proto_item_append_text(ctx_item, ", %s", uuid_str);
3291 if (hdr->drep[0] & DREP_LITTLE_ENDIAN) {
3292 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
3293 hf_dcerpc_cn_bind_if_ver, &if_ver);
3294 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
3295 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
3297 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
3298 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
3299 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
3300 hf_dcerpc_cn_bind_if_ver, &if_ver);
3304 proto_item_append_text(iface_item, " V%u.%u", if_ver, if_ver_minor);
3305 proto_item_set_len(iface_item, 20);
3308 memset(&trans_id, 0, sizeof(trans_id));
3309 for (j = 0; j < num_trans_items; j++) {
3310 proto_tree *trans_tree = NULL;
3311 proto_item *trans_item = NULL;
3312 proto_item *uuid_item = NULL;
3314 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &trans_id);
3317 trans_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_trans_syntax, tvb, offset, 0, ENC_NA);
3318 trans_tree = proto_item_add_subtree(trans_item, ett_dcerpc_cn_trans_syntax);
3320 uuid_str = guid_to_str((e_guid_t *) &trans_id);
3321 uuid_name = guids_get_uuid_name(&trans_id);
3324 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);
3325 proto_item_append_text(trans_item, "[%u]: %s", j+1, uuid_name);
3326 proto_item_append_text(ctx_item, ", %s", uuid_name);
3328 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);
3329 proto_item_append_text(trans_item, "[%u]: %s", j+1, uuid_str);
3330 proto_item_append_text(ctx_item, ", %s", uuid_str);
3333 /* check for [MS-RPCE] 3.3.1.5.3 Bind Time Feature Negotiation */
3334 if (trans_id.Data1 == 0x6cb71c2c && trans_id.Data2 == 0x9812 && trans_id.Data3 == 0x4540) {
3335 proto_tree *uuid_tree = proto_item_add_subtree(uuid_item, ett_dcerpc_cn_trans_btfn);
3336 proto_tree_add_boolean(uuid_tree, hf_dcerpc_cn_bind_trans_btfn_01, tvb, offset+8, 1, trans_id.Data4[0]);
3337 proto_tree_add_boolean(uuid_tree, hf_dcerpc_cn_bind_trans_btfn_02, tvb, offset+8, 1, trans_id.Data4[0]);
3342 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, trans_tree, hdr->drep,
3343 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
3345 proto_item_set_len(trans_item, 20);
3346 proto_item_append_text(trans_item, " V%u", trans_ver);
3350 /* if this is the first time we've seen this packet, we need to
3351 update the dcerpc_binds table so that any later calls can
3352 match to the interface.
3353 XXX We assume that BINDs will NEVER be fragmented.
3355 if (!(pinfo->fd->flags.visited)) {
3356 dcerpc_bind_key *key;
3357 dcerpc_bind_value *value;
3359 key = (dcerpc_bind_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_key));
3361 key->ctx_id = ctx_id;
3362 key->smb_fid = dcerpc_get_transport_salt(pinfo);
3364 value = (dcerpc_bind_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_value));
3365 value->uuid = if_id;
3366 value->ver = if_ver;
3367 value->transport = trans_id;
3369 /* add this entry to the bind table */
3370 g_hash_table_insert(dcerpc_binds, key, value);
3374 col_append_fstr(pinfo->cinfo, COL_INFO, ",");
3375 col_append_fstr(pinfo->cinfo, COL_INFO, " %s V%u.%u (%s)",
3376 guids_resolve_uuid_to_str(&if_id), if_ver, if_ver_minor,
3377 guids_resolve_uuid_to_str(&trans_id));
3380 proto_item_set_len(ctx_item, offset - ctx_offset);
3385 * XXX - we should save the authentication type *if* we have
3386 * an authentication header, and associate it with an authentication
3387 * context, so subsequent PDUs can use that context.
3389 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
3393 dissect_dcerpc_cn_bind_ack(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3394 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
3396 guint16 max_xmit, max_recv;
3397 guint16 sec_addr_len;
3404 dcerpc_auth_info auth_info;
3405 const char *uuid_name = NULL;
3406 const char *result_str = NULL;
3408 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3409 hf_dcerpc_cn_max_xmit, &max_xmit);
3411 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3412 hf_dcerpc_cn_max_recv, &max_recv);
3414 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3415 hf_dcerpc_cn_assoc_group, NULL);
3417 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3418 hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
3419 if (sec_addr_len != 0) {
3420 tvb_ensure_bytes_exist(tvb, offset, sec_addr_len);
3421 proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
3422 sec_addr_len, ENC_ASCII|ENC_NA);
3423 offset += sec_addr_len;
3427 offset += 4 - offset % 4;
3430 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3431 hf_dcerpc_cn_num_results, &num_results);
3436 col_append_fstr(pinfo->cinfo, COL_INFO, ", max_xmit: %u max_recv: %u, %u results:",
3437 max_xmit, max_recv, num_results);
3439 for (i = 0; i < num_results; i++) {
3440 proto_tree *ctx_tree = NULL;
3441 proto_item *ctx_item = NULL;
3444 ctx_item = proto_tree_add_text(dcerpc_tree, tvb, offset, 24, "Ctx Item[%u]:", i+1);
3445 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
3448 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree,
3449 hdr->drep, hf_dcerpc_cn_ack_result,
3452 /* [MS-RPCE] 3.3.1.5.3 check if this Ctx Item is the response to a Bind Time Feature Negotiation request */
3454 const int old_offset = offset;
3455 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree, hdr->drep, hf_dcerpc_cn_ack_btfn, &reason);
3456 proto_tree_add_boolean(ctx_tree, hf_dcerpc_cn_bind_trans_btfn_01, tvb, old_offset, 1, reason);
3457 proto_tree_add_boolean(ctx_tree, hf_dcerpc_cn_bind_trans_btfn_02, tvb, old_offset, 1, reason);
3458 } else if (result != 0) {
3459 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree,
3460 hdr->drep, hf_dcerpc_cn_ack_reason,
3464 * The reason for rejection isn't meaningful, and often isn't
3465 * set, when the syntax was accepted.
3470 result_str = val_to_str(result, p_cont_result_vals, "Unknown result (%u)");
3473 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &trans_id);
3474 uuid_name = guids_get_uuid_name(&trans_id);
3476 uuid_name = guid_to_str((e_guid_t *) &trans_id);
3478 proto_tree_add_guid_format(ctx_tree, hf_dcerpc_cn_ack_trans_id, tvb,
3479 offset, 16, (e_guid_t *) &trans_id, "Transfer Syntax: %s",
3481 proto_item_append_text(ctx_item, " %s, %s", result_str, uuid_name);
3485 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, ctx_tree, hdr->drep,
3486 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
3489 col_append_fstr(pinfo->cinfo, COL_INFO, ",");
3490 col_append_fstr(pinfo->cinfo, COL_INFO, " %s", result_str);
3494 * XXX - do we need to do anything with the authentication level
3495 * we get back from this?
3497 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
3501 dissect_dcerpc_cn_bind_nak(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3502 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
3505 guint8 num_protocols;
3508 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
3509 hdr->drep, hf_dcerpc_cn_reject_reason,
3512 col_append_fstr(pinfo->cinfo, COL_INFO, " reason: %s",
3513 val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
3515 if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
3516 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3517 hf_dcerpc_cn_num_protocols,
3520 for (i = 0; i < num_protocols; i++) {
3521 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
3522 hdr->drep, hf_dcerpc_cn_protocol_ver_major,
3524 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
3525 hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
3531 /* Return a string describing a DCE/RPC fragment as first, middle, or end
3534 #define PFC_FRAG_MASK 0x03
3537 fragment_type(guint8 flags)
3539 static const char* t[4] = {
3545 return t[flags & PFC_FRAG_MASK];
3548 /* Dissect stub data (payload) of a DCERPC packet. */
3551 dissect_dcerpc_cn_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
3552 proto_tree *dcerpc_tree, proto_tree *tree,
3553 e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
3554 dcerpc_auth_info *auth_info, guint32 alloc_hint _U_,
3557 gint length, reported_length;
3558 gboolean save_fragmented;
3559 fragment_head *fd_head = NULL;
3561 tvbuff_t *auth_tvb, *payload_tvb, *decrypted_tvb;
3563 proto_item *parent_pi;
3564 proto_item *dcerpc_tree_item;
3566 save_fragmented = pinfo->fragmented;
3568 length = tvb_length_remaining(tvb, offset);
3569 reported_length = tvb_reported_length_remaining(tvb, offset);
3570 if (reported_length < 0 ||
3571 (guint32)reported_length < auth_info->auth_size) {
3572 /* We don't even have enough bytes for the authentication
3576 reported_length -= auth_info->auth_size;
3577 if (length > reported_length)
3578 length = reported_length;
3579 payload_tvb = tvb_new_subset(tvb, offset, length, reported_length);
3582 /*don't bother if we don't have the entire tvb */
3583 /*XXX we should really make sure we calculate auth_info->auth_data
3584 and use that one instead of this auth_tvb hack
3586 if (tvb_length(tvb) == tvb_reported_length(tvb)) {
3587 if (tvb_length_remaining(tvb, offset+length) > 8) {
3588 auth_tvb = tvb_new_subset_remaining(tvb, offset+length+8);
3592 /* Decrypt the PDU if it is encrypted */
3594 if (auth_info->auth_type &&
3595 (auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)) {
3597 * We know the authentication type, and the authentication
3598 * level is "Packet privacy", meaning the payload is
3599 * encrypted; attempt to decrypt it.
3601 dcerpc_auth_subdissector_fns *auth_fns;
3603 /* Start out assuming we won't succeed in decrypting. */
3604 decrypted_tvb = NULL;
3605 /* Schannel needs information into the footer (verifier) in order to setup decryption keys
3606 * so we call it in order to have a chance to decipher the data
3608 if (DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN == auth_info->auth_type) {
3609 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, auth_info);
3612 if ((auth_fns = get_auth_subdissector_fns(
3613 auth_info->auth_level, auth_info->auth_type))) {
3616 result = decode_encrypted_data(
3617 payload_tvb, auth_tvb, pinfo, auth_fns,
3618 hdr->ptype == PDU_REQ, auth_info);
3622 proto_tree_add_text(
3623 dcerpc_tree, payload_tvb, 0, -1,
3624 "Encrypted stub data (%d byte%s)",
3625 tvb_reported_length(payload_tvb),
3627 plurality(tvb_length(payload_tvb), "", "s"));
3629 add_new_data_source(
3630 pinfo, result, "Decrypted stub data");
3633 decrypted_tvb = result;
3637 decrypted_tvb = payload_tvb;
3639 /* if this packet is not fragmented, just dissect it and exit */
3640 if (PFC_NOT_FRAGMENTED(hdr)) {
3641 pinfo->fragmented = FALSE;
3644 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
3645 hdr->drep, di, auth_info);
3647 pinfo->fragmented = save_fragmented;
3651 /* The packet is fragmented. */
3652 pinfo->fragmented = TRUE;
3654 /* debug output of essential fragment data. */
3655 /* leave it here for future debugging sessions */
3656 /*printf("DCE num:%u offset:%u frag_len:%u tvb_len:%u\n",
3657 pinfo->fd->num, offset, hdr->frag_len, tvb_length(decrypted_tvb));*/
3659 /* if we are not doing reassembly and this is the first fragment
3660 then just dissect it and exit
3661 XXX - if we're not doing reassembly, can we decrypt an
3664 if ( (!dcerpc_reassemble) && (hdr->flags & PFC_FIRST_FRAG) ) {
3667 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
3668 hdr->drep, di, auth_info);
3670 expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment, "%s fragment", fragment_type(hdr->flags));
3672 pinfo->fragmented = save_fragmented;
3676 /* if we have already seen this packet, see if it was reassembled
3677 and if so dissect the full pdu.
3680 if (pinfo->fd->flags.visited) {
3681 fd_head = fragment_get_reassembled(&dcerpc_co_reassembly_table, frame);
3685 /* if we are not doing reassembly and it was neither a complete PDU
3686 nor the first fragment then there is nothing more we can do
3687 so we just have to exit
3689 if ( !dcerpc_reassemble || (tvb_length(tvb) != tvb_reported_length(tvb)) )
3692 /* if we didn't get 'frame' we don't know where the PDU started and thus
3693 it is pointless to continue
3698 /* from now on we must attempt to reassemble the PDU
3701 /* if we get here we know it is the first time we see the packet
3702 and we also know it is only a fragment and not a full PDU,
3703 thus we must reassemble it.
3706 /* Do we have any non-encrypted data to reassemble? */
3707 if (decrypted_tvb == NULL) {
3708 /* No. We can't even try to reassemble. */
3712 /* defragmentation is a bit tricky, as there's no offset of the fragment
3713 * in the protocol data.
3715 * just use fragment_add_seq_next() and hope that TCP/SMB segments coming
3716 * in with the correct sequence.
3718 fd_head = fragment_add_seq_next(&dcerpc_co_reassembly_table,
3719 decrypted_tvb, 0, pinfo, frame, NULL,
3720 tvb_length(decrypted_tvb),
3721 hdr->flags&PFC_LAST_FRAG ? FALSE : TRUE /* more_frags */);
3725 /* if reassembly is complete and this is the last fragment
3726 * (multiple fragments in one PDU are possible!)
3727 * dissect the full PDU
3729 if (fd_head && (fd_head->flags & FD_DEFRAGMENTED) ) {
3731 if ((pinfo->fd->num == fd_head->reassembled_in) && (hdr->flags & PFC_LAST_FRAG) ) {
3733 proto_item *frag_tree_item;
3735 next_tvb = tvb_new_chain((decrypted_tvb)?decrypted_tvb:payload_tvb,
3738 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3739 show_fragment_tree(fd_head, &dcerpc_frag_items,
3740 tree, pinfo, next_tvb, &frag_tree_item);
3741 /* the toplevel fragment subtree is now behind all desegmented data,
3742 * move it right behind the DCE/RPC tree */
3743 dcerpc_tree_item = proto_tree_get_parent(dcerpc_tree);
3744 if (frag_tree_item && dcerpc_tree_item) {
3745 proto_tree_move_item(tree, dcerpc_tree_item, frag_tree_item);
3748 pinfo->fragmented = FALSE;
3750 expert_add_info_format(pinfo, frag_tree_item, &ei_dcerpc_fragment_reassembled, "%s fragment, reassembled", fragment_type(hdr->flags));
3752 dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb,
3753 next_tvb, hdr->drep, di, auth_info);
3756 if (decrypted_tvb) {
3757 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
3758 decrypted_tvb, 0, 0, fd_head->reassembled_in);
3760 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
3761 payload_tvb, 0, 0, fd_head->reassembled_in);
3763 PROTO_ITEM_SET_GENERATED(pi);
3764 parent_pi = proto_tree_get_parent(dcerpc_tree);
3765 if (parent_pi != NULL) {
3766 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
3768 col_append_fstr(pinfo->cinfo, COL_INFO,
3769 " [DCE/RPC %s fragment, reas: #%u]", fragment_type(hdr->flags), fd_head->reassembled_in);
3770 expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment_reassembled, "%s fragment, reassembled in #%u", fragment_type(hdr->flags), fd_head->reassembled_in);
3773 /* Reassembly not complete - some fragments
3774 are missing. Just show the stub data. */
3775 expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment, "%s fragment", fragment_type(hdr->flags));
3777 if (decrypted_tvb) {
3778 show_stub_data(decrypted_tvb, 0, tree, auth_info, FALSE);
3780 show_stub_data(payload_tvb, 0, tree, auth_info, TRUE);
3784 pinfo->fragmented = save_fragmented;
3788 dissect_dcerpc_cn_rqst(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3789 proto_tree *dcerpc_tree, proto_tree *tree,
3790 e_dce_cn_common_hdr_t *hdr)
3792 conversation_t *conv;
3795 e_uuid_t obj_id = DCERPC_UUID_NULL;
3796 dcerpc_auth_info auth_info;
3799 proto_item *parent_pi;
3801 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3802 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3804 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3805 hf_dcerpc_cn_ctx_id, &ctx_id);
3806 parent_pi = proto_tree_get_parent(dcerpc_tree);
3807 if (parent_pi != NULL) {
3808 proto_item_append_text(parent_pi, ", Ctx: %u", ctx_id);
3811 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3812 hf_dcerpc_opnum, &opnum);
3814 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3815 pinfo->dcectxid = ctx_id;
3817 col_append_fstr(pinfo->cinfo, COL_INFO, ", opnum: %u, Ctx: %u",
3820 if (hdr->flags & PFC_OBJECT_UUID) {
3821 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &obj_id);
3823 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
3824 offset, 16, (e_guid_t *) &obj_id, "Object UUID: %s",
3825 guid_to_str((e_guid_t *) &obj_id));
3831 * XXX - what if this was set when the connection was set up,
3832 * and we just have a security context?
3834 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3836 conv = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3837 pinfo->srcport, pinfo->destport, 0);
3839 show_stub_data(tvb, offset, dcerpc_tree, &auth_info, TRUE);
3841 dcerpc_matched_key matched_key, *new_matched_key;
3842 dcerpc_call_value *value;
3844 /* !!! we can NOT check flags.visited here since this will interact
3845 badly with when SMB handles (i.e. calls the subdissector)
3846 and desegmented pdu's .
3847 Instead we check if this pdu is already in the matched table or not
3849 matched_key.frame = pinfo->fd->num;
3850 matched_key.call_id = hdr->call_id;
3851 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
3853 dcerpc_bind_key bind_key;
3854 dcerpc_bind_value *bind_value;
3856 bind_key.conv = conv;
3857 bind_key.ctx_id = ctx_id;
3858 bind_key.smb_fid = dcerpc_get_transport_salt(pinfo);
3860 if ((bind_value = (dcerpc_bind_value *)g_hash_table_lookup(dcerpc_binds, &bind_key)) ) {
3861 if (!(hdr->flags&PFC_FIRST_FRAG)) {
3862 dcerpc_cn_call_key call_key;
3863 dcerpc_call_value *call_value;
3865 call_key.conv = conv;
3866 call_key.call_id = hdr->call_id;
3867 call_key.smb_fid = dcerpc_get_transport_salt(pinfo);
3868 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_cn_calls, &call_key))) {
3869 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
3870 *new_matched_key = matched_key;
3871 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
3875 dcerpc_cn_call_key *call_key;
3876 dcerpc_call_value *call_value;
3878 /* We found the binding and it is the first fragment
3879 (or a complete PDU) of a dcerpc pdu so just add
3880 the call to both the call table and the
3883 call_key = (dcerpc_cn_call_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_cn_call_key));
3884 call_key->conv = conv;
3885 call_key->call_id = hdr->call_id;
3886 call_key->smb_fid = dcerpc_get_transport_salt(pinfo);
3888 /* if there is already a matching call in the table
3889 remove it so it is replaced with the new one */
3890 if (g_hash_table_lookup(dcerpc_cn_calls, call_key)) {
3891 g_hash_table_remove(dcerpc_cn_calls, call_key);
3894 call_value = (dcerpc_call_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_call_value));
3895 call_value->uuid = bind_value->uuid;
3896 call_value->ver = bind_value->ver;
3897 call_value->object_uuid = obj_id;
3898 call_value->opnum = opnum;
3899 call_value->req_frame = pinfo->fd->num;
3900 call_value->req_time = pinfo->fd->abs_ts;
3901 call_value->rep_frame = 0;
3902 call_value->max_ptr = 0;
3903 call_value->se_data = NULL;
3904 call_value->private_data = NULL;
3905 call_value->pol = NULL;
3906 call_value->flags = 0;
3907 if (!memcmp(&bind_value->transport, &uuid_ndr64, sizeof(uuid_ndr64))) {
3908 call_value->flags |= DCERPC_IS_NDR64;
3911 g_hash_table_insert(dcerpc_cn_calls, call_key, call_value);
3913 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
3914 *new_matched_key = matched_key;
3915 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
3925 /* handoff this call */
3927 di->call_id = hdr->call_id;
3928 di->smb_fid = dcerpc_get_transport_salt(pinfo);
3929 di->ptype = PDU_REQ;
3930 di->call_data = value;
3933 if (value->rep_frame != 0) {
3934 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
3935 tvb, 0, 0, value->rep_frame);
3936 PROTO_ITEM_SET_GENERATED(pi);
3937 if (parent_pi != NULL) {
3938 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
3942 dissect_dcerpc_cn_stub(tvb, offset, pinfo, dcerpc_tree, tree,
3943 hdr, di, &auth_info, alloc_hint,
3946 /* no bind information, simply show stub data */
3947 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);
3948 show_stub_data(tvb, offset, dcerpc_tree, &auth_info, TRUE);
3952 /* Dissect the verifier */
3953 dissect_dcerpc_verifier(tvb, pinfo, dcerpc_tree, hdr, &auth_info);
3958 dissect_dcerpc_cn_resp(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3959 proto_tree *dcerpc_tree, proto_tree *tree,
3960 e_dce_cn_common_hdr_t *hdr)
3962 dcerpc_call_value *value = NULL;
3963 conversation_t *conv;
3965 dcerpc_auth_info auth_info;
3968 proto_item *parent_pi;
3969 e_uuid_t obj_id_null = DCERPC_UUID_NULL;
3971 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3972 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3974 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3975 hf_dcerpc_cn_ctx_id, &ctx_id);
3976 parent_pi = proto_tree_get_parent(dcerpc_tree);
3977 if (parent_pi != NULL) {
3978 proto_item_append_text(parent_pi, ", Ctx: %u", ctx_id);
3981 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3982 pinfo->dcectxid = ctx_id;
3984 col_append_fstr(pinfo->cinfo, COL_INFO, ", Ctx: %u", ctx_id);
3986 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3987 hf_dcerpc_cn_cancel_count, NULL);
3992 * XXX - what if this was set when the connection was set up,
3993 * and we just have a security context?
3995 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3997 conv = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3998 pinfo->srcport, pinfo->destport, 0);
4001 /* no point in creating one here, really */
4002 show_stub_data(tvb, offset, dcerpc_tree, &auth_info, TRUE);
4004 dcerpc_matched_key matched_key, *new_matched_key;
4006 /* !!! we can NOT check flags.visited here since this will interact
4007 badly with when SMB handles (i.e. calls the subdissector)
4008 and desegmented pdu's .
4009 Instead we check if this pdu is already in the matched table or not
4011 matched_key.frame = pinfo->fd->num;
4012 matched_key.call_id = hdr->call_id;
4013 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
4015 dcerpc_cn_call_key call_key;
4016 dcerpc_call_value *call_value;
4018 call_key.conv = conv;
4019 call_key.call_id = hdr->call_id;
4020 call_key.smb_fid = dcerpc_get_transport_salt(pinfo);
4022 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_cn_calls, &call_key))) {
4023 /* extra sanity check, only match them if the reply
4024 came after the request */
4025 if (call_value->req_frame<pinfo->fd->num) {
4026 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
4027 *new_matched_key = matched_key;
4028 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
4030 if (call_value->rep_frame == 0) {
4031 call_value->rep_frame = pinfo->fd->num;
4041 /* handoff this call */
4043 di->call_id = hdr->call_id;
4044 di->smb_fid = dcerpc_get_transport_salt(pinfo);
4045 di->ptype = PDU_RESP;
4046 di->call_data = value;
4048 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
4050 /* (optional) "Object UUID" from request */
4051 if (dcerpc_tree && (memcmp(&value->object_uuid, &obj_id_null, sizeof(obj_id_null)) != 0)) {
4052 pi = proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
4053 offset, 0, (e_guid_t *) &value->object_uuid, "Object UUID: %s",
4054 guid_to_str((e_guid_t *) &value->object_uuid));
4055 PROTO_ITEM_SET_GENERATED(pi);
4059 if (value->req_frame != 0) {
4061 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4062 tvb, 0, 0, value->req_frame);
4063 PROTO_ITEM_SET_GENERATED(pi);
4064 if (parent_pi != NULL) {
4065 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
4067 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
4068 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
4069 PROTO_ITEM_SET_GENERATED(pi);
4071 proto_tree_add_expert(dcerpc_tree, pinfo, &ei_dcerpc_no_request_found, tvb, 0, 0);
4074 dissect_dcerpc_cn_stub(tvb, offset, pinfo, dcerpc_tree, tree,
4075 hdr, di, &auth_info, alloc_hint,
4078 /* no bind information, simply show stub data */
4079 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);
4080 show_stub_data(tvb, offset, dcerpc_tree, &auth_info, TRUE);
4084 /* Dissect the verifier */
4085 dissect_dcerpc_verifier(tvb, pinfo, dcerpc_tree, hdr, &auth_info);
4089 dissect_dcerpc_cn_fault(tvbuff_t *tvb, gint offset, packet_info *pinfo,
4090 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
4092 dcerpc_call_value *value = NULL;
4093 conversation_t *conv;
4097 dcerpc_auth_info auth_info;
4098 proto_item *pi = NULL;
4100 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4101 hf_dcerpc_cn_alloc_hint, &alloc_hint);
4103 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4104 hf_dcerpc_cn_ctx_id, &ctx_id);
4106 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4107 hf_dcerpc_cn_cancel_count, NULL);
4112 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4113 hf_dcerpc_cn_status, &status);
4115 status = ((hdr->drep[0] & DREP_LITTLE_ENDIAN)
4116 ? tvb_get_letohl(tvb, offset)
4117 : tvb_get_ntohl(tvb, offset));
4119 pi = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_status, tvb, offset, 4, DREP_ENC_INTEGER(hdr->drep));
4122 expert_add_info_format(pinfo, pi, &ei_dcerpc_cn_status, "Fault: %s", val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
4124 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
4125 pinfo->dcectxid = ctx_id;
4127 col_append_fstr(pinfo->cinfo, COL_INFO,
4128 ", Ctx: %u, status: %s", ctx_id,
4129 val_to_str(status, reject_status_vals,
4130 "Unknown (0x%08x)"));
4136 * XXX - what if this was set when the connection was set up,
4137 * and we just have a security context?
4139 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
4141 conv = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
4142 pinfo->srcport, pinfo->destport, 0);
4144 /* no point in creating one here, really */
4146 dcerpc_matched_key matched_key, *new_matched_key;
4148 /* !!! we can NOT check flags.visited here since this will interact
4149 badly with when SMB handles (i.e. calls the subdissector)
4150 and desegmented pdu's .
4151 Instead we check if this pdu is already in the matched table or not
4153 matched_key.frame = pinfo->fd->num;
4154 matched_key.call_id = hdr->call_id;
4155 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
4157 dcerpc_cn_call_key call_key;
4158 dcerpc_call_value *call_value;
4160 call_key.conv = conv;
4161 call_key.call_id = hdr->call_id;
4162 call_key.smb_fid = dcerpc_get_transport_salt(pinfo);
4164 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_cn_calls, &call_key))) {
4165 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
4166 *new_matched_key = matched_key;
4167 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
4170 if (call_value->rep_frame == 0) {
4171 call_value->rep_frame = pinfo->fd->num;
4178 int length, stub_length;
4180 proto_item *parent_pi;
4183 /* handoff this call */
4185 di->call_id = hdr->call_id;
4186 di->smb_fid = dcerpc_get_transport_salt(pinfo);
4187 di->ptype = PDU_FAULT;
4188 di->call_data = value;
4190 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
4191 if (value->req_frame != 0) {
4193 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4194 tvb, 0, 0, value->req_frame);
4195 PROTO_ITEM_SET_GENERATED(pi);
4196 parent_pi = proto_tree_get_parent(dcerpc_tree);
4197 if (parent_pi != NULL) {
4198 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
4200 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
4201 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
4202 PROTO_ITEM_SET_GENERATED(pi);
4204 proto_tree_add_expert(dcerpc_tree, pinfo, &ei_dcerpc_no_request_found, tvb, 0, 0);
4207 length = tvb_length_remaining(tvb, offset);
4208 /* as we now create a tvb in dissect_dcerpc_cn() containing only the
4209 * stub_data, the following calculation is no longer valid:
4210 * stub_length = hdr->frag_len - offset - auth_info.auth_size;
4211 * simply use the remaining length of the tvb instead.
4212 * XXX - or better use the reported_length?!?
4214 stub_length = length;
4215 if (length > stub_length)
4216 length = stub_length;
4218 /* If we don't have reassembly enabled, or this packet contains
4219 the entire PDU, or if we don't have all the data in this
4220 fragment, just call the handoff directly if this is the
4221 first fragment or the PDU isn't fragmented. */
4222 if ( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
4223 !tvb_bytes_exist(tvb, offset, stub_length) ) {
4224 if (hdr->flags&PFC_FIRST_FRAG) {
4225 /* First fragment, possibly the only fragment */
4227 * XXX - should there be a third routine for each
4228 * function in an RPC subdissector, to handle
4229 * fault responses? The DCE RPC 1.1 spec says
4230 * three's "stub data" here, which I infer means
4231 * that it's protocol-specific and call-specific.
4233 * It should probably get passed the status code
4234 * as well, as that might be protocol-specific.
4237 if (stub_length > 0) {
4238 tvb_ensure_bytes_exist(tvb, offset, stub_length);
4239 proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
4240 "Fault stub data (%d byte%s)",
4242 plurality(stub_length, "", "s"));
4246 /* PDU is fragmented and this isn't the first fragment */
4248 if (stub_length > 0) {
4249 tvb_ensure_bytes_exist(tvb, offset, stub_length);
4250 proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
4251 "Fragment data (%d byte%s)",
4253 plurality(stub_length, "", "s"));
4258 /* Reassembly is enabled, the PDU is fragmented, and
4259 we have all the data in the fragment; the first two
4260 of those mean we should attempt reassembly, and the
4261 third means we can attempt reassembly. */
4264 tvb_ensure_bytes_exist(tvb, offset, stub_length);
4265 proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
4266 "Fragment data (%d byte%s)",
4268 plurality(stub_length, "", "s"));
4271 if (hdr->flags&PFC_FIRST_FRAG) { /* FIRST fragment */
4272 if ( (!pinfo->fd->flags.visited) && value->rep_frame ) {
4273 fragment_add_seq_next(&dcerpc_co_reassembly_table,
4275 pinfo, value->rep_frame, NULL,
4279 } else if (hdr->flags&PFC_LAST_FRAG) { /* LAST fragment */
4280 if ( value->rep_frame ) {
4281 fragment_head *fd_head;
4283 fd_head = fragment_add_seq_next(&dcerpc_co_reassembly_table,
4285 pinfo, value->rep_frame, NULL,
4290 /* We completed reassembly */
4292 proto_item *frag_tree_item;
4294 next_tvb = tvb_new_chain(tvb, fd_head->tvb_data);
4295 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
4296 show_fragment_tree(fd_head, &dcerpc_frag_items,
4297 dcerpc_tree, pinfo, next_tvb, &frag_tree_item);
4300 * XXX - should there be a third routine for each
4301 * function in an RPC subdissector, to handle
4302 * fault responses? The DCE RPC 1.1 spec says
4303 * three's "stub data" here, which I infer means
4304 * that it's protocol-specific and call-specific.
4306 * It should probably get passed the status code
4307 * as well, as that might be protocol-specific.
4311 tvb_ensure_bytes_exist(tvb, offset, stub_length);
4312 proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
4313 "Fault stub data (%d byte%s)",
4315 plurality(stub_length, "", "s"));
4320 } else { /* MIDDLE fragment(s) */
4321 if ( (!pinfo->fd->flags.visited) && value->rep_frame ) {
4322 fragment_add_seq_next(&dcerpc_co_reassembly_table,
4324 pinfo, value->rep_frame, NULL,
4335 dissect_dcerpc_cn_rts(tvbuff_t *tvb, gint offset, packet_info *pinfo,
4336 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
4338 proto_item *tf = NULL;
4339 proto_item *parent_pi = NULL;
4340 proto_tree *cn_rts_pdu_tree = NULL;
4342 guint16 commands_nb = 0;
4345 const char *info_str = NULL;
4347 /* Dissect specific RTS header */
4348 rts_flags = dcerpc_tvb_get_ntohs(tvb, offset, hdr->drep);
4350 proto_tree *cn_rts_flags_tree;
4352 tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_rts_flags, tvb, offset, 2, rts_flags);
4353 cn_rts_flags_tree = proto_item_add_subtree(tf, ett_dcerpc_cn_rts_flags);
4354 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_none, tvb, offset, 1, rts_flags);
4355 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_ping, tvb, offset, 1, rts_flags);
4356 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_other_cmd, tvb, offset, 1, rts_flags);
4357 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_recycle_channel, tvb, offset, 1, rts_flags);
4358 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_in_channel, tvb, offset, 1, rts_flags);
4359 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_out_channel, tvb, offset, 1, rts_flags);
4360 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_eof, tvb, offset, 1, rts_flags);
4364 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4365 hf_dcerpc_cn_rts_commands_nb, &commands_nb);
4367 /* Create the RTS PDU tree - we do not yet know its name */
4368 tf = proto_tree_add_text(dcerpc_tree, tvb, offset, tvb_length_remaining(tvb, offset), "RTS PDU: %u commands", commands_nb);
4369 cn_rts_pdu_tree = proto_item_add_subtree(tf, ett_dcerpc_cn_rts_pdu);
4371 cmd = (guint32 *)wmem_alloc(wmem_packet_scope(), sizeof (guint32) * (commands_nb + 1));
4373 /* Dissect commands */
4374 for (i = 0; i < commands_nb; ++i) {
4375 proto_tree *cn_rts_command_tree = NULL;
4376 const guint32 command = dcerpc_tvb_get_ntohl(tvb, offset, hdr->drep);
4378 tf = proto_tree_add_uint(cn_rts_pdu_tree, hf_dcerpc_cn_rts_command, tvb, offset, 4, command);
4379 cn_rts_command_tree = proto_item_add_subtree(tf, ett_dcerpc_cn_rts_command);
4382 case RTS_CMD_RECEIVEWINDOWSIZE:
4383 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_receivewindowsize, NULL);
4385 case RTS_CMD_FLOWCONTROLACK:
4386 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_fack_bytesreceived, NULL);
4387 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_fack_availablewindow, NULL);
4388 offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_fack_channelcookie, NULL);
4390 case RTS_CMD_CONNECTIONTIMEOUT:
4391 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_connectiontimeout, NULL);
4393 case RTS_CMD_COOKIE:
4394 offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_cookie, NULL);
4396 case RTS_CMD_CHANNELLIFETIME:
4397 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_channellifetime, NULL);
4399 case RTS_CMD_CLIENTKEEPALIVE:
4400 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_clientkeepalive, NULL);
4402 case RTS_CMD_VERSION:
4403 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_version, NULL);
4407 case RTS_CMD_PADDING: {
4409 const guint32 conformance_count = dcerpc_tvb_get_ntohl(tvb, offset, hdr->drep);
4410 proto_tree_add_uint(cn_rts_command_tree, hf_dcerpc_cn_rts_command_conformancecount, tvb, offset, 4, conformance_count);
4412 padding = (guint8 *)tvb_memdup(NULL, tvb, offset, conformance_count);
4413 proto_tree_add_bytes(cn_rts_command_tree, hf_dcerpc_cn_rts_command_padding, tvb, offset, conformance_count, padding);
4414 offset += conformance_count;
4416 case RTS_CMD_NEGATIVEANCE:
4420 case RTS_CMD_CLIENTADDRESS: {
4422 const guint32 addrtype = dcerpc_tvb_get_ntohl(tvb, offset, hdr->drep);
4423 proto_tree_add_uint(cn_rts_command_tree, hf_dcerpc_cn_rts_command_addrtype, tvb, offset, 4, addrtype);
4427 const guint32 addr4 = tvb_get_ipv4(tvb, offset);
4428 proto_tree_add_text(cn_rts_command_tree, tvb, offset, 4, "%s", get_hostname(addr4));
4432 struct e_in6_addr addr6;
4433 tvb_get_ipv6(tvb, offset, &addr6);
4434 proto_tree_add_text(cn_rts_command_tree, tvb, offset, 16, "%s", get_hostname6(&addr6));
4438 padding = (guint8 *)tvb_memdup(NULL, tvb, offset, 12);
4439 proto_tree_add_bytes(cn_rts_command_tree, hf_dcerpc_cn_rts_command_padding, tvb, offset, 12, padding);
4442 case RTS_CMD_ASSOCIATIONGROUPID:
4443 offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_associationgroupid, NULL);
4445 case RTS_CMD_DESTINATION:
4446 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_forwarddestination, NULL);
4448 case RTS_CMD_PINGTRAFFICSENTNOTIFY:
4449 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_pingtrafficsentnotify, NULL);
4452 proto_tree_add_text(cn_rts_command_tree, tvb, offset, 0, "unknown RTS command number");
4457 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RPCH");
4459 /* Define which PDU Body we are dealing with */
4460 info_str = "unknown RTS PDU";
4462 switch (rts_flags) {
4464 switch (commands_nb) {
4466 if (cmd[0] == 0x2) {
4467 info_str = "CONN/A3";
4468 } else if (cmd[0] == 0x3) {
4469 info_str = "IN_R1/A5,IN_R1/A6,IN_R2/A2,IN_R2/A5,OUT_R2/A4";
4470 } else if (cmd[0] == 0x7) {
4471 info_str = "IN_R1/B1";
4472 } else if (cmd[0] == 0x0) {
4473 info_str = "IN_R1/B2";
4474 } else if (cmd[0] == 0xD) {
4475 info_str = "IN_R2/A3,IN_R2/A4";
4476 } else if (cmd[0] == 0xA) {
4477 info_str = "OUT_R1/A9,OUT_R1/A10,OUT_R1/A11,OUT_R2/B1,OUT_R2/B2";
4481 if ((cmd[0] == 0x0) && (cmd[1] == 0x6)) {
4482 info_str = "CONN/B3";
4483 } else if ((cmd[0] == 0xD) && (cmd[1] == 0xA)) {
4484 info_str = "OUT_R2/A5,OUT_R2/A6";
4488 if ((cmd[0] == 0x6) && (cmd[1] == 0x0) && (cmd[2] == 0x2)) {
4489 info_str = "CONN/C1,CONN/C2";
4493 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x0)) {
4494 info_str = "CONN/A1";
4495 } else if ((cmd[0] == 0xD) && (cmd[1] == 0x6) && (cmd[2] == 0x0) && (cmd[3] == 0x2)) {
4496 info_str = "IN_R1/A3,IN_R1/A4";
4500 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x4) && (cmd[4] == 0x5) && (cmd[5] == 0xC)) {
4501 info_str = "CONN/B1";
4509 switch (commands_nb) {
4514 if ((cmd[0] == 0x7) || (cmd[0] == 0x8)) {
4515 info_str = "OUT_R2/C1";
4522 case RTS_FLAG_OTHER_CMD:
4523 switch (commands_nb) {
4525 if (cmd[0] == 0x5) {
4526 info_str = "Keep-Alive";
4527 } else if (cmd[0] == 0xE) {
4528 info_str = "PingTrafficSentNotify";
4529 } else if (cmd[0] == 0x1) {
4530 info_str = "FlowControlAck";
4534 if ((cmd[0] == 0xD) && (cmd[1] == 0x1)) {
4535 info_str = "FlowControlAckWithDestination";
4542 case RTS_FLAG_RECYCLE_CHANNEL:
4543 switch (commands_nb) {
4545 if (cmd[0] == 0xD) {
4546 info_str = "OUT_R1/A1,OUT_R1/A2,OUT_R2/A1,OUT_R2/A2";
4550 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3)) {
4551 info_str = "IN_R1/A1,IN_R2/A1";
4555 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3) && (cmd[4] == 0x0)) {
4556 info_str = "OUT_R1/A3,OUT_R2/A3";
4563 case RTS_FLAG_IN_CHANNEL|RTS_FLAG_RECYCLE_CHANNEL:
4564 switch (commands_nb) {
4566 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3) && (cmd[4] == 0x0) && (cmd[5] == 0x2)) {
4567 info_str = "IN_R1/A2";
4573 case RTS_FLAG_IN_CHANNEL:
4574 switch (commands_nb) {
4576 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x0) && (cmd[4] == 0x2) && (cmd[5] == 0xC) && (cmd[6] == 0xB)) {
4577 info_str = "CONN/B2";
4583 case RTS_FLAG_OUT_CHANNEL|RTS_FLAG_RECYCLE_CHANNEL:
4584 switch (commands_nb) {
4586 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3) && (cmd[4] == 0x4) && (cmd[5] == 0) && (cmd[6] == 0x2)) {
4587 info_str = "OUT_R1/A4";
4594 case RTS_FLAG_OUT_CHANNEL:
4595 switch (commands_nb) {
4597 if ((cmd[0] == 0xD) && (cmd[1] == 0x3)) {
4598 info_str = "OUT_R1/A7,OUT_R1/A8,OUT_R2/A8";
4602 if ((cmd[0] == 0xD) && (cmd[1] == 0x6) && (cmd[2] == 0x2)) {
4603 info_str = "OUT_R1/A5,OUT_R1/A6";
4604 } else if ((cmd[0] == 0xD) && (cmd[1] == 0x3) && (cmd[2] == 0x6)) {
4605 info_str = "OUT_R2/A7";
4609 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x4) && (cmd[4] == 0x0)) {
4610 info_str = "CONN/A2";
4617 switch (commands_nb) {
4619 if (cmd[0] == 0xA) {
4620 info_str = "OUT_R2/B3";
4628 switch (commands_nb) {
4640 col_add_fstr(pinfo->cinfo, COL_INFO, "%s, ", info_str);
4641 col_set_fence(pinfo->cinfo,COL_INFO);
4643 parent_pi = proto_tree_get_parent(dcerpc_tree);
4644 if (parent_pi != NULL) {
4645 proto_item_append_text(parent_pi, ", %s", info_str);
4650 * DCERPC dissector for connection oriented calls.
4651 * We use transport type to later multiplex between what kind of
4652 * pinfo->private_data structure to expect.
4655 dissect_dcerpc_cn(tvbuff_t *tvb, int offset, packet_info *pinfo,
4656 proto_tree *tree, gboolean can_desegment, int *pkt_len)
4658 static const guint8 nulls[4] = { 0 };
4662 proto_item *ti = NULL;
4663 proto_item *tf = NULL;
4664 proto_tree *dcerpc_tree = NULL;
4665 proto_tree *cn_flags_tree = NULL;
4666 proto_tree *drep_tree = NULL;
4667 e_dce_cn_common_hdr_t hdr;
4668 dcerpc_auth_info auth_info;
4669 tvbuff_t *fragment_tvb;
4672 * when done over nbt, dcerpc requests are padded with 4 bytes of null
4673 * data for some reason.
4675 * XXX - if that's always the case, the right way to do this would
4676 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
4677 * the 4 bytes of null padding, and make that the dissector
4678 * used for "netbios".
4680 if (tvb_memeql(tvb, offset, nulls, 4) == 0) {
4689 * Check if this looks like a C/O DCERPC call
4691 if (!tvb_bytes_exist(tvb, offset, sizeof (hdr))) {
4692 return FALSE; /* not enough information to check */
4694 start_offset = offset;
4695 hdr.rpc_ver = tvb_get_guint8(tvb, offset++);
4696 if (hdr.rpc_ver != 5)
4698 hdr.rpc_ver_minor = tvb_get_guint8(tvb, offset++);
4699 if ((hdr.rpc_ver_minor != 0) && (hdr.rpc_ver_minor != 1))
4701 hdr.ptype = tvb_get_guint8(tvb, offset++);
4702 if (hdr.ptype > PDU_RTS)
4705 hdr.flags = tvb_get_guint8(tvb, offset++);
4706 tvb_memcpy(tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
4707 offset += (int)sizeof (hdr.drep);
4709 hdr.frag_len = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
4711 hdr.auth_len = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
4713 hdr.call_id = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
4716 if (pinfo->dcectxid == 0) {
4717 col_append_fstr(pinfo->cinfo, COL_DCE_CALL, "%u", hdr.call_id);
4719 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
4720 * prepend a delimiter */
4721 col_append_fstr(pinfo->cinfo, COL_DCE_CALL, "#%u", hdr.call_id);
4724 if (can_desegment && pinfo->can_desegment
4725 && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
4726 pinfo->desegment_offset = start_offset;
4727 pinfo->desegment_len = hdr.frag_len - tvb_length_remaining(tvb, start_offset);
4728 *pkt_len = 0; /* desegmentation required */
4732 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCERPC");
4734 if (pinfo->dcectxid != 0) {
4735 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
4736 * append a delimiter and set a column fence */
4737 col_append_str(pinfo->cinfo, COL_INFO, " # ");
4738 col_set_fence(pinfo->cinfo,COL_INFO);
4740 col_add_fstr(pinfo->cinfo, COL_INFO, "%s: call_id: %u",
4741 pckt_vals[hdr.ptype].strptr, hdr.call_id);
4743 if (pinfo->dcectxid != 0) {
4744 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU */
4745 expert_add_info(pinfo, NULL, &ei_dcerpc_fragment_multiple);
4748 offset = start_offset;
4749 tvb_ensure_bytes_exist(tvb, offset, 16);
4751 ti = proto_tree_add_item(tree, proto_dcerpc, tvb, offset, hdr.frag_len, ENC_NA);
4752 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
4755 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
4758 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset, 1, hdr.rpc_ver_minor);
4761 tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
4764 #if 0 /* XXX - too much "output noise", removed for now */
4765 if (hdr.ptype == PDU_BIND || hdr.ptype == PDU_ALTER ||
4766 hdr.ptype == PDU_BIND_ACK || hdr.ptype == PDU_ALTER_ACK)
4767 expert_add_info_format(pinfo, tf, &ei_dcerpc_context_change, "Context change: %s", val_to_str(hdr.ptype, pckt_vals, "(0x%x)"));
4769 if (hdr.ptype == PDU_BIND_NAK)
4770 expert_add_info(pinfo, tf, &ei_dcerpc_bind_not_acknowledged);
4773 proto_item_append_text(ti, " %s, Fragment: %s",
4774 val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"),
4775 fragment_type(hdr.flags));
4777 tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
4778 cn_flags_tree = proto_item_add_subtree(tf, ett_dcerpc_cn_flags);
4780 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
4781 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
4782 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
4783 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
4784 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
4785 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
4786 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
4787 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
4790 col_append_fstr(pinfo->cinfo, COL_INFO, ", Fragment: %s", fragment_type(hdr.flags));
4793 tf = proto_tree_add_bytes(dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
4794 drep_tree = proto_item_add_subtree(tf, ett_dcerpc_drep);
4796 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
4797 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
4798 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
4799 offset += (int)sizeof (hdr.drep);
4801 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
4804 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
4807 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
4811 proto_item_append_text(ti, ", FragLen: %u, Call: %u", hdr.frag_len, hdr.call_id);
4815 * None of the stuff done above should throw an exception, because
4816 * we would have rejected this as "not DCE RPC" if we didn't have all
4817 * of it. (XXX - perhaps we should request reassembly if we have
4818 * enough of the header to consider it DCE RPC but not enough to
4819 * get the fragment length; in that case the stuff still wouldn't
4820 * throw an exception.)
4822 * The rest of the stuff might, so return the PDU length to our caller.
4823 * XXX - should we construct a tvbuff containing only the PDU and
4824 * use that? Or should we have separate "is this a DCE RPC PDU",
4825 * "how long is it", and "dissect it" routines - which might let us
4826 * do most of the work in "tcp_dissect_pdus()"?
4828 if (pkt_len != NULL)
4829 *pkt_len = hdr.frag_len + padding;
4831 /* The remaining bytes in the current tvb might contain multiple
4832 * DCE/RPC fragments, so create a new tvb subset for this fragment.
4833 * Only limit the end of the fragment, but not the offset start,
4834 * as the authentication function dissect_dcerpc_cn_auth() will fail
4835 * (and other functions might fail as well) computing the right start
4838 subtvb_len = MIN(hdr.frag_len, tvb_length(tvb));
4839 fragment_tvb = tvb_new_subset(tvb, start_offset,
4840 subtvb_len /* length */,
4841 hdr.frag_len /* reported_length */);
4844 * Packet type specific stuff is next.
4846 switch (hdr.ptype) {
4849 dissect_dcerpc_cn_bind(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
4854 dissect_dcerpc_cn_bind_ack(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
4859 * Nothing after the common header other than credentials.
4861 dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr, TRUE,
4866 dissect_dcerpc_cn_rqst(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, tree, &hdr);
4870 dissect_dcerpc_cn_resp(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, tree, &hdr);
4874 dissect_dcerpc_cn_fault(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
4878 dissect_dcerpc_cn_bind_nak(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
4884 * Nothing after the common header other than an authentication
4887 dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr, FALSE,
4893 * Nothing after the common header, not even an authentication
4898 dissect_dcerpc_cn_rts(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
4902 /* might as well dissect the auth info */
4903 dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr, FALSE,
4911 * DCERPC dissector for connection oriented calls over packet-oriented
4915 dissect_dcerpc_cn_pk(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
4918 * Only one PDU per transport packet, and only one transport
4921 pinfo->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
4922 if (!dissect_dcerpc_cn(tvb, 0, pinfo, tree, FALSE, NULL)) {
4924 * It wasn't a DCERPC PDU.
4936 * DCERPC dissector for connection oriented calls over byte-stream
4938 * we need to distinguish here between SMB and non-TCP (more in the future?)
4939 * to be able to know what kind of private_data structure to expect.
4942 dissect_dcerpc_cn_bs_body(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4944 volatile int offset = 0;
4946 volatile int dcerpc_pdus = 0;
4947 volatile gboolean ret = FALSE;
4950 * There may be multiple PDUs per transport packet; keep
4953 while (tvb_reported_length_remaining(tvb, offset) != 0) {
4956 if (dissect_dcerpc_cn(tvb, offset, pinfo, tree,
4957 dcerpc_cn_desegment, &pdu_len)) {
4960 } CATCH_NONFATAL_ERRORS {
4962 * Somebody threw an exception that means that there
4963 * was a problem dissecting the payload; that means
4964 * that a dissector was found, so we don't need to
4965 * dissect the payload as data or update the protocol
4968 * Just show the exception and then continue dissecting
4971 show_exception(tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
4973 * Presumably it looked enough like a DCE RPC PDU that we
4974 * dissected enough of it to throw an exception.
4979 if (dcerpc_pdus == 0) {
4980 gboolean try_desegment = FALSE;
4981 if (dcerpc_cn_desegment && pinfo->can_desegment &&
4982 !tvb_bytes_exist(tvb, offset, sizeof(e_dce_cn_common_hdr_t))) {
4983 /* look for a previous occurence of the DCE-RPC protocol */
4984 wmem_list_frame_t *cur;
4985 cur = wmem_list_frame_prev(wmem_list_tail(pinfo->layers));
4986 while (cur != NULL) {
4987 if (proto_dcerpc == (gint)GPOINTER_TO_UINT(wmem_list_frame_data(cur))) {
4988 try_desegment = TRUE;
4991 cur = wmem_list_frame_prev(cur);
4995 if (try_desegment) {
4996 /* It didn't look like DCE-RPC but we already had one DCE-RPC
4997 * layer in this packet and what we have is short. Assume that
4998 * it was just too short to tell and ask the TCP layer for more
5000 pinfo->desegment_offset = offset;
5001 pinfo->desegment_len = (guint32)(sizeof(e_dce_cn_common_hdr_t) - tvb_length_remaining(tvb, offset));
5003 /* Really not DCE-RPC */
5009 * Well, we've seen at least one DCERPC PDU.
5013 /* if we had more than one Req/Resp in this PDU change the protocol column */
5014 /* this will formerly contain the last interface name, which may not be the same for all Req/Resp */
5015 if (dcerpc_pdus >= 2)
5016 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "%u*DCERPC", dcerpc_pdus);
5020 * Desegmentation required - bail now, but give the user a hint that desegmentation might be done later.
5022 proto_tree_add_uint_format(tree, hf_dcerpc_cn_deseg_req, tvb, offset,
5024 tvb_reported_length_remaining(tvb, offset),
5025 "[DCE RPC: %u byte%s left, desegmentation might follow]",
5026 tvb_reported_length_remaining(tvb, offset),
5027 plurality(tvb_reported_length_remaining(tvb, offset), "", "s"));
5032 * Step to the next PDU.
5040 dissect_dcerpc_cn_bs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5042 pinfo->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
5043 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
5047 dissect_dcerpc_cn_smbpipe(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5049 pinfo->dcetransporttype = DCE_CN_TRANSPORT_SMBPIPE;
5050 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
5054 dissect_dcerpc_cn_smb2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5056 pinfo->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
5057 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
5063 dissect_dcerpc_dg_auth(tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
5064 e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
5066 proto_item *ti = NULL;
5067 proto_tree *auth_tree = NULL;
5068 guint8 protection_level;
5071 * Initially set "*auth_level_p" to -1 to indicate that we haven't
5072 * yet seen any authentication level information.
5074 if (auth_level_p != NULL)
5078 * The authentication information is at the *end* of the PDU; in
5079 * request and response PDUs, the request and response stub data
5082 * If the full packet is here, and there's data past the end of the
5083 * packet body, then dissect the auth info.
5085 offset += hdr->frag_len;
5086 if (tvb_length_remaining(tvb, offset) > 0) {
5087 switch (hdr->auth_proto) {
5089 case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
5090 ti = proto_tree_add_text(dcerpc_tree, tvb, offset, -1, "Kerberos authentication verifier");
5091 auth_tree = proto_item_add_subtree(ti, ett_dcerpc_krb5_auth_verf);
5092 protection_level = tvb_get_guint8(tvb, offset);
5093 if (auth_level_p != NULL)
5094 *auth_level_p = protection_level;
5095 proto_tree_add_uint(auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
5097 proto_tree_add_item(auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, ENC_BIG_ENDIAN);
5099 if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
5100 offset += 6; /* 6 bytes of padding */
5102 offset += 2; /* 2 bytes of padding */
5103 proto_tree_add_item(auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, ENC_NA);
5108 proto_tree_add_text(dcerpc_tree, tvb, offset, -1, "Authentication verifier");
5115 dissect_dcerpc_dg_cancel_ack(tvbuff_t *tvb, int offset, packet_info *pinfo,
5116 proto_tree *dcerpc_tree,
5117 e_dce_dg_common_hdr_t *hdr)
5121 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5122 hdr->drep, hf_dcerpc_dg_cancel_vers,
5128 /* The only version we know about */
5129 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5130 hdr->drep, hf_dcerpc_dg_cancel_id,
5132 /*offset = */dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
5133 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
5140 dissect_dcerpc_dg_cancel(tvbuff_t *tvb, int offset, packet_info *pinfo,
5141 proto_tree *dcerpc_tree,
5142 e_dce_dg_common_hdr_t *hdr)
5146 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5147 hdr->drep, hf_dcerpc_dg_cancel_vers,
5153 /* The only version we know about */
5154 /*offset = */dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5155 hdr->drep, hf_dcerpc_dg_cancel_id,
5157 /* XXX - are NDR Booleans 32 bits? */
5159 /* XXX - the RPC reference in chapter: "the cancel PDU" doesn't mention
5160 the accepting_cancels field (it's only in the cancel_ack PDU)! */
5161 /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
5162 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
5169 dissect_dcerpc_dg_fack(tvbuff_t *tvb, int offset, packet_info *pinfo,
5170 proto_tree *dcerpc_tree,
5171 e_dce_dg_common_hdr_t *hdr)
5178 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
5179 hdr->drep, hf_dcerpc_dg_fack_vers,
5186 case 0: /* The only version documented in the DCE RPC 1.1 spec */
5187 case 1: /* This appears to be the same */
5188 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
5189 hdr->drep, hf_dcerpc_dg_fack_window_size,
5191 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5192 hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
5194 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5195 hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
5197 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
5198 hdr->drep, hf_dcerpc_dg_fack_serial_num,
5200 col_append_fstr(pinfo->cinfo, COL_INFO, " serial: %u",
5202 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
5203 hdr->drep, hf_dcerpc_dg_fack_selack_len,
5205 for (i = 0; i < selack_len; i++) {
5206 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5207 hdr->drep, hf_dcerpc_dg_fack_selack,
5216 dissect_dcerpc_dg_reject_fault(tvbuff_t *tvb, int offset, packet_info *pinfo,
5217 proto_tree *dcerpc_tree,
5218 e_dce_dg_common_hdr_t *hdr)
5222 /*offset = */dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5223 hdr->drep, hf_dcerpc_dg_status,
5226 col_append_fstr (pinfo->cinfo, COL_INFO,
5228 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
5232 dissect_dcerpc_dg_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
5233 proto_tree *dcerpc_tree, proto_tree *tree,
5234 e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
5236 int length, reported_length, stub_length;
5237 gboolean save_fragmented;
5238 fragment_head *fd_head;
5241 proto_item *parent_pi;
5243 col_append_fstr(pinfo->cinfo, COL_INFO, " opnum: %u len: %u",
5244 di->call_data->opnum, hdr->frag_len );
5246 length = tvb_length_remaining(tvb, offset);
5247 reported_length = tvb_reported_length_remaining(tvb, offset);
5248 stub_length = hdr->frag_len;
5249 if (length > stub_length)
5250 length = stub_length;
5251 if (reported_length > stub_length)
5252 reported_length = stub_length;
5254 save_fragmented = pinfo->fragmented;
5256 /* If we don't have reassembly enabled, or this packet contains
5257 the entire PDU, or if this is a short frame (or a frame
5258 not reassembled at a lower layer) that doesn't include all
5259 the data in the fragment, just call the handoff directly if
5260 this is the first fragment or the PDU isn't fragmented. */
5261 if ( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
5262 !tvb_bytes_exist(tvb, offset, stub_length) ) {
5263 if (hdr->frag_num == 0) {
5266 /* First fragment, possibly the only fragment */
5269 * XXX - authentication info?
5271 pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
5272 next_tvb = tvb_new_subset(tvb, offset, length,
5274 dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb,
5275 next_tvb, hdr->drep, di, NULL);
5277 /* PDU is fragmented and this isn't the first fragment */
5280 tvb_ensure_bytes_exist(tvb, offset, stub_length);
5281 proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
5282 "Fragment data (%d byte%s)",
5284 plurality(stub_length, "", "s"));
5289 /* Reassembly is enabled, the PDU is fragmented, and
5290 we have all the data in the fragment; the first two
5291 of those mean we should attempt reassembly, and the
5292 third means we can attempt reassembly. */
5295 tvb_ensure_bytes_exist(tvb, offset, stub_length);
5296 proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
5297 "Fragment data (%d byte%s)", stub_length,
5298 plurality(stub_length, "", "s"));
5302 fd_head = fragment_add_seq(&dcerpc_cl_reassembly_table,
5304 pinfo, hdr->seqnum, (void *)hdr,
5305 hdr->frag_num, stub_length,
5306 !(hdr->flags1 & PFCL1_LASTFRAG), 0);
5307 if (fd_head != NULL) {
5308 /* We completed reassembly... */
5309 if (pinfo->fd->num == fd_head->reassembled_in) {
5310 /* ...and this is the reassembled RPC PDU */
5311 next_tvb = tvb_new_chain(tvb, fd_head->tvb_data);
5312 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
5313 show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
5314 tree, pinfo, next_tvb, &pi);
5317 * XXX - authentication info?
5319 pinfo->fragmented = FALSE;
5320 dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb,
5321 next_tvb, hdr->drep, di, NULL);
5323 /* ...and this isn't the reassembled RPC PDU */
5324 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
5325 tvb, 0, 0, fd_head->reassembled_in);
5326 PROTO_ITEM_SET_GENERATED(pi);
5327 parent_pi = proto_tree_get_parent(dcerpc_tree);
5328 if (parent_pi != NULL) {
5329 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
5331 col_append_fstr(pinfo->cinfo, COL_INFO,
5332 " [DCE/RPC fragment, reas: #%u]", fd_head->reassembled_in);
5336 pinfo->fragmented = save_fragmented;
5340 dissect_dcerpc_dg_rqst(tvbuff_t *tvb, int offset, packet_info *pinfo,
5341 proto_tree *dcerpc_tree, proto_tree *tree,
5342 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
5345 dcerpc_call_value *value, v;
5346 dcerpc_matched_key matched_key, *new_matched_key;
5348 proto_item *parent_pi;
5351 if (!(pinfo->fd->flags.visited)) {
5352 dcerpc_call_value *call_value;
5353 dcerpc_dg_call_key *call_key;
5355 call_key = (dcerpc_dg_call_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_dg_call_key));
5356 call_key->conv = conv;
5357 call_key->seqnum = hdr->seqnum;
5358 call_key->act_id = hdr->act_id;
5360 call_value = (dcerpc_call_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_call_value));
5361 call_value->uuid = hdr->if_id;
5362 call_value->ver = hdr->if_ver;
5363 call_value->object_uuid = hdr->obj_id;
5364 call_value->opnum = hdr->opnum;
5365 call_value->req_frame = pinfo->fd->num;
5366 call_value->req_time = pinfo->fd->abs_ts;
5367 call_value->rep_frame = 0;
5368 call_value->max_ptr = 0;
5369 call_value->se_data = NULL;
5370 call_value->private_data = NULL;
5371 call_value->pol = NULL;
5372 /* NDR64 is not available on dg transports ?*/
5373 call_value->flags = 0;
5375 g_hash_table_insert(dcerpc_dg_calls, call_key, call_value);
5377 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof(dcerpc_matched_key));
5378 new_matched_key->frame = pinfo->fd->num;
5379 new_matched_key->call_id = hdr->seqnum;
5380 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
5383 matched_key.frame = pinfo->fd->num;
5384 matched_key.call_id = hdr->seqnum;
5385 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
5387 v.uuid = hdr->if_id;
5388 v.ver = hdr->if_ver;
5389 v.object_uuid = hdr->obj_id;
5390 v.opnum = hdr->opnum;
5391 v.req_frame = pinfo->fd->num;
5395 v.private_data = NULL;
5400 di->call_id = hdr->seqnum;
5402 di->ptype = PDU_REQ;
5403 di->call_data = value;
5405 if (value->rep_frame != 0) {
5406 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
5407 tvb, 0, 0, value->rep_frame);
5408 PROTO_ITEM_SET_GENERATED(pi);
5409 parent_pi = proto_tree_get_parent(dcerpc_tree);
5410 if (parent_pi != NULL) {
5411 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
5414 dissect_dcerpc_dg_stub(tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
5418 dissect_dcerpc_dg_resp(tvbuff_t *tvb, int offset, packet_info *pinfo,
5419 proto_tree *dcerpc_tree, proto_tree *tree,
5420 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
5423 dcerpc_call_value *value, v;
5424 dcerpc_matched_key matched_key, *new_matched_key;
5426 proto_item *parent_pi;
5429 if (!(pinfo->fd->flags.visited)) {
5430 dcerpc_call_value *call_value;
5431 dcerpc_dg_call_key call_key;
5433 call_key.conv = conv;
5434 call_key.seqnum = hdr->seqnum;
5435 call_key.act_id = hdr->act_id;
5437 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_dg_calls, &call_key))) {
5438 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
5439 new_matched_key->frame = pinfo->fd->num;
5440 new_matched_key->call_id = hdr->seqnum;
5441 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
5442 if (call_value->rep_frame == 0) {
5443 call_value->rep_frame = pinfo->fd->num;
5448 matched_key.frame = pinfo->fd->num;
5449 matched_key.call_id = hdr->seqnum;
5450 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
5452 v.uuid = hdr->if_id;
5453 v.ver = hdr->if_ver;
5454 v.object_uuid = hdr->obj_id;
5455 v.opnum = hdr->opnum;
5457 v.rep_frame = pinfo->fd->num;
5459 v.private_data = NULL;
5466 di->ptype = PDU_RESP;
5467 di->call_data = value;
5469 if (value->req_frame != 0) {
5471 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
5472 tvb, 0, 0, value->req_frame);
5473 PROTO_ITEM_SET_GENERATED(pi);
5474 parent_pi = proto_tree_get_parent(dcerpc_tree);
5475 if (parent_pi != NULL) {
5476 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
5478 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
5479 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
5480 PROTO_ITEM_SET_GENERATED(pi);
5482 proto_tree_add_expert(dcerpc_tree, pinfo, &ei_dcerpc_no_request_found, tvb, 0, 0);
5484 dissect_dcerpc_dg_stub(tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
5488 dissect_dcerpc_dg_ping_ack(tvbuff_t *tvb, int offset, packet_info *pinfo,
5489 proto_tree *dcerpc_tree,
5490 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
5492 proto_item *parent_pi;
5493 /* if (!(pinfo->fd->flags.visited)) {*/
5494 dcerpc_call_value *call_value;
5495 dcerpc_dg_call_key call_key;
5497 call_key.conv = conv;
5498 call_key.seqnum = hdr->seqnum;
5499 call_key.act_id = hdr->act_id;
5501 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_dg_calls, &call_key))) {
5505 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
5506 tvb, 0, 0, call_value->req_frame);
5507 PROTO_ITEM_SET_GENERATED(pi);
5508 parent_pi = proto_tree_get_parent(dcerpc_tree);
5509 if (parent_pi != NULL) {
5510 proto_item_append_text(parent_pi, ", [Req: #%u]", call_value->req_frame);
5513 col_append_fstr(pinfo->cinfo, COL_INFO, " [req: #%u]", call_value->req_frame);
5515 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &call_value->req_time);
5516 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
5517 PROTO_ITEM_SET_GENERATED(pi);
5523 * DCERPC dissector for connectionless calls
5526 dissect_dcerpc_dg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5528 proto_item *ti = NULL;
5529 proto_item *tf = NULL;
5530 proto_tree *dcerpc_tree = NULL;
5531 proto_tree *dg_flags1_tree = NULL;
5532 proto_tree *dg_flags2_tree = NULL;
5533 proto_tree *drep_tree = NULL;
5534 e_dce_dg_common_hdr_t hdr;
5536 conversation_t *conv;
5539 const char *uuid_name = NULL;
5542 * Check if this looks like a CL DCERPC call. All dg packets
5543 * have an 80 byte header on them. Which starts with
5544 * version (4), pkt_type.
5546 if (tvb_length(tvb) < sizeof (hdr)) {
5550 /* Version must be 4 */
5551 hdr.rpc_ver = tvb_get_guint8(tvb, offset++);
5552 if (hdr.rpc_ver != 4)
5555 /* Type must be <= 19 or it's not DCE/RPC */
5556 hdr.ptype = tvb_get_guint8(tvb, offset++);
5560 /* flags1 has bit 1 and 8 as reserved so if any of them are set, it is
5561 probably not a DCE/RPC packet
5563 hdr.flags1 = tvb_get_guint8(tvb, offset++);
5564 if (hdr.flags1&0x81)
5567 /* flags2 has all bits except bit 2 as reserved so if any of them are set
5568 it is probably not DCE/RPC.
5570 hdr.flags2 = tvb_get_guint8(tvb, offset++);
5571 if (hdr.flags2&0xfd)
5575 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCERPC");
5576 col_add_str(pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
5578 tvb_memcpy(tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
5579 offset += (int)sizeof (hdr.drep);
5580 hdr.serial_hi = tvb_get_guint8(tvb, offset++);
5581 dcerpc_tvb_get_uuid(tvb, offset, hdr.drep, &hdr.obj_id);
5583 dcerpc_tvb_get_uuid(tvb, offset, hdr.drep, &hdr.if_id);
5585 dcerpc_tvb_get_uuid(tvb, offset, hdr.drep, &hdr.act_id);
5587 hdr.server_boot = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
5589 hdr.if_ver = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
5591 hdr.seqnum = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
5593 hdr.opnum = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5595 hdr.ihint = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5597 hdr.ahint = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5599 hdr.frag_len = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5601 hdr.frag_num = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5603 hdr.auth_proto = tvb_get_guint8(tvb, offset++);
5604 hdr.serial_lo = tvb_get_guint8(tvb, offset++);
5607 ti = proto_tree_add_item(tree, proto_dcerpc, tvb, 0, -1, ENC_NA);
5609 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
5610 proto_item_append_text(ti, " %s, Seq: %u, Serial: %u, Frag: %u, FragLen: %u",
5611 val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"),
5612 hdr.seqnum, hdr.serial_hi*256+hdr.serial_lo,
5613 hdr.frag_num, hdr.frag_len);
5619 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
5623 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
5627 tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
5628 dg_flags1_tree = proto_item_add_subtree(tf, ett_dcerpc_dg_flags1);
5629 if (dg_flags1_tree) {
5630 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
5631 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
5632 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
5633 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
5634 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
5635 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
5636 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
5637 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
5639 proto_item_append_text(tf, " %s%s%s%s%s%s",
5640 (hdr.flags1 & PFCL1_BROADCAST) ? "\"Broadcast\" " : "",
5641 (hdr.flags1 & PFCL1_IDEMPOTENT) ? "\"Idempotent\" " : "",
5642 (hdr.flags1 & PFCL1_MAYBE) ? "\"Maybe\" " : "",
5643 (hdr.flags1 & PFCL1_NOFACK) ? "\"No Fack\" " : "",
5644 (hdr.flags1 & PFCL1_FRAG) ? "\"Fragment\" " : "",
5645 (hdr.flags1 & PFCL1_LASTFRAG) ? "\"Last Fragment\" " : "");
5652 tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
5653 dg_flags2_tree = proto_item_add_subtree(tf, ett_dcerpc_dg_flags2);
5654 if (dg_flags2_tree) {
5655 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
5656 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
5657 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
5658 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
5659 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
5660 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
5661 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
5662 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
5664 proto_item_append_text(tf, " %s",
5665 (hdr.flags2 & PFCL2_CANCEL_PENDING) ? "\"Cancel Pending\" " : "");
5672 tf = proto_tree_add_bytes(dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
5673 drep_tree = proto_item_add_subtree(tf, ett_dcerpc_drep);
5675 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
5676 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
5677 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
5678 proto_item_append_text(tf, " (Order: %s, Char: %s, Float: %s)",
5679 val_to_str_const(hdr.drep[0] >> 4, drep_byteorder_vals, "Unknown"),
5680 val_to_str_const(hdr.drep[0] & 0x0f, drep_character_vals, "Unknown"),
5681 val_to_str_const(hdr.drep[1], drep_fp_vals, "Unknown"));
5684 offset += (int)sizeof (hdr.drep);
5687 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
5691 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
5692 offset, 16, (e_guid_t *) &hdr.obj_id, "Object UUID: %s",
5693 guid_to_str((e_guid_t *) &hdr.obj_id));
5698 uuid_str = guid_to_str((e_guid_t*)&hdr.if_id);
5699 uuid_name = guids_get_uuid_name(&hdr.if_id);
5701 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
5702 offset, 16, (e_guid_t *) &hdr.if_id, "Interface: %s UUID: %s", uuid_name, uuid_str);
5704 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
5705 offset, 16, (e_guid_t *) &hdr.if_id, "Interface UUID: %s", uuid_str);
5711 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
5712 offset, 16, (e_guid_t *) &hdr.act_id, "Activity: %s",
5713 guid_to_str((e_guid_t *) &hdr.act_id));
5718 nstime_t server_boot;
5720 server_boot.secs = hdr.server_boot;
5721 server_boot.nsecs = 0;
5723 if (hdr.server_boot == 0)
5724 proto_tree_add_time_format_value(dcerpc_tree, hf_dcerpc_dg_server_boot,
5725 tvb, offset, 4, &server_boot,
5728 proto_tree_add_time(dcerpc_tree, hf_dcerpc_dg_server_boot,
5729 tvb, offset, 4, &server_boot);
5734 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
5738 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
5739 col_append_fstr(pinfo->cinfo, COL_INFO, ": seq: %u", hdr.seqnum);
5740 col_append_fstr(pinfo->cinfo, COL_DCE_CALL, "%u", hdr.seqnum);
5744 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
5748 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
5752 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
5756 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
5760 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
5761 if (hdr.flags1 & PFCL1_FRAG) {
5762 /* Fragmented - put the fragment number into the Info column */
5763 col_append_fstr(pinfo->cinfo, COL_INFO, " frag: %u",
5769 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
5773 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
5774 if (hdr.flags1 & PFCL1_FRAG) {
5775 /* Fragmented - put the serial number into the Info column */
5776 col_append_fstr(pinfo->cinfo, COL_INFO, " serial: %u",
5777 (hdr.serial_hi << 8) | hdr.serial_lo);
5783 * XXX - for Kerberos, we get a protection level; if it's
5784 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
5787 dissect_dcerpc_dg_auth(tvb, offset, dcerpc_tree, &hdr,
5792 * keeping track of the conversation shouldn't really be necessary
5793 * for connectionless packets, because everything we need to know
5794 * to dissect is in the header for each packet. Unfortunately,
5795 * Microsoft's implementation is buggy and often puts the
5796 * completely wrong if_id in the header. go figure. So, keep
5797 * track of the seqnum and use that if possible. Note: that's not
5798 * completely correct. It should really be done based on both the
5799 * activity_id and seqnum. I haven't seen anywhere that it would
5800 * make a difference, but for future reference...
5802 conv = find_or_create_conversation(pinfo);
5805 * Packet type specific stuff is next.
5808 switch (hdr.ptype) {
5810 case PDU_CANCEL_ACK:
5811 /* Body is optional */
5812 /* XXX - we assume "frag_len" is the length of the body */
5813 if (hdr.frag_len != 0)
5814 dissect_dcerpc_dg_cancel_ack(tvb, offset, pinfo, dcerpc_tree, &hdr);
5819 * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
5820 * but in at least one capture none of the Cl_cancel PDUs had a
5823 /* XXX - we assume "frag_len" is the length of the body */
5824 if (hdr.frag_len != 0)
5825 dissect_dcerpc_dg_cancel(tvb, offset, pinfo, dcerpc_tree, &hdr);
5829 /* Body is optional; if present, it's the same as PDU_FACK */
5830 /* XXX - we assume "frag_len" is the length of the body */
5831 if (hdr.frag_len != 0)
5832 dissect_dcerpc_dg_fack(tvb, offset, pinfo, dcerpc_tree, &hdr);
5836 /* Body is optional */
5837 /* XXX - we assume "frag_len" is the length of the body */
5838 if (hdr.frag_len != 0)
5839 dissect_dcerpc_dg_fack(tvb, offset, pinfo, dcerpc_tree, &hdr);
5844 dissect_dcerpc_dg_reject_fault(tvb, offset, pinfo, dcerpc_tree, &hdr);
5848 dissect_dcerpc_dg_rqst(tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
5852 dissect_dcerpc_dg_resp(tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
5855 /* these requests have no body */
5858 dissect_dcerpc_dg_ping_ack(tvb, offset, pinfo, dcerpc_tree, &hdr, conv);
5869 dcerpc_init_protocol(void)
5871 /* structures and data for BIND */
5873 g_hash_table_destroy(dcerpc_binds);
5874 dcerpc_binds = NULL;
5876 if (!dcerpc_binds) {
5877 dcerpc_binds = g_hash_table_new(dcerpc_bind_hash, dcerpc_bind_equal);
5880 /* structures and data for CALL */
5881 if (dcerpc_cn_calls) {
5882 g_hash_table_destroy(dcerpc_cn_calls);
5884 dcerpc_cn_calls = g_hash_table_new(dcerpc_cn_call_hash, dcerpc_cn_call_equal);
5885 if (dcerpc_dg_calls) {
5886 g_hash_table_destroy(dcerpc_dg_calls);
5888 dcerpc_dg_calls = g_hash_table_new(dcerpc_dg_call_hash, dcerpc_dg_call_equal);
5890 /* structure and data for MATCHED */
5891 if (dcerpc_matched) {
5892 g_hash_table_destroy(dcerpc_matched);
5894 dcerpc_matched = g_hash_table_new(dcerpc_matched_hash, dcerpc_matched_equal);
5896 decode_dcerpc_inject_bindings();
5900 proto_register_dcerpc(void)
5902 static hf_register_info hf[] = {
5903 { &hf_dcerpc_request_in,
5904 { "Request in frame", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE,
5905 NULL, 0, "This packet is a response to the packet with this number", HFILL }},
5906 { &hf_dcerpc_response_in,
5907 { "Response in frame", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
5908 NULL, 0, "This packet will be responded in the packet with this number", HFILL }},
5909 { &hf_dcerpc_referent_id,
5910 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
5911 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
5913 { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5914 { &hf_dcerpc_ver_minor,
5915 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5916 { &hf_dcerpc_packet_type,
5917 { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS(pckt_vals), 0x0, NULL, HFILL }},
5918 { &hf_dcerpc_cn_flags,
5919 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5920 { &hf_dcerpc_cn_flags_first_frag,
5921 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_FIRST_FRAG, NULL, HFILL }},
5922 { &hf_dcerpc_cn_flags_last_frag,
5923 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_LAST_FRAG, NULL, HFILL }},
5924 { &hf_dcerpc_cn_flags_cancel_pending,
5925 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_PENDING_CANCEL, NULL, HFILL }},
5926 { &hf_dcerpc_cn_flags_reserved,
5927 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_RESERVED_1, NULL, HFILL }},
5928 { &hf_dcerpc_cn_flags_mpx,
5929 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_CONC_MPX, NULL, HFILL }},
5930 { &hf_dcerpc_cn_flags_dne,
5931 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_DID_NOT_EXECUTE, NULL, HFILL }},
5932 { &hf_dcerpc_cn_flags_maybe,
5933 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_MAYBE, NULL, HFILL }},
5934 { &hf_dcerpc_cn_flags_object,
5935 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_OBJECT_UUID, NULL, HFILL }},
5937 { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5938 { &hf_dcerpc_drep_byteorder,
5939 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS(drep_byteorder_vals), 0x0, NULL, HFILL }},
5940 { &hf_dcerpc_drep_character,
5941 { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS(drep_character_vals), 0x0, NULL, HFILL }},
5942 { &hf_dcerpc_drep_fp,
5943 { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS(drep_fp_vals), 0x0, NULL, HFILL }},
5944 { &hf_dcerpc_cn_frag_len,
5945 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5946 { &hf_dcerpc_cn_auth_len,
5947 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5948 { &hf_dcerpc_cn_call_id,
5949 { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5950 { &hf_dcerpc_cn_max_xmit,
5951 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5952 { &hf_dcerpc_cn_max_recv,
5953 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5954 { &hf_dcerpc_cn_assoc_group,
5955 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5956 { &hf_dcerpc_cn_num_ctx_items,
5957 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5958 { &hf_dcerpc_cn_ctx_item,
5959 { "Ctx Item", "dcerpc.cn_ctx_item", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5960 { &hf_dcerpc_cn_ctx_id,
5961 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5962 { &hf_dcerpc_cn_num_trans_items,
5963 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5964 { &hf_dcerpc_cn_bind_abstract_syntax,
5965 { "Abstract Syntax", "dcerpc.cn_bind_abstract_syntax", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5966 { &hf_dcerpc_cn_bind_if_id,
5967 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5968 { &hf_dcerpc_cn_bind_if_ver,
5969 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5970 { &hf_dcerpc_cn_bind_if_ver_minor,
5971 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5972 { &hf_dcerpc_cn_bind_trans_syntax,
5973 { "Transfer Syntax", "dcerpc.cn_bind_trans", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5974 { &hf_dcerpc_cn_bind_trans_id,
5975 { "ID", "dcerpc.cn_bind_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5976 { &hf_dcerpc_cn_bind_trans_ver,
5977 { "ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5978 { &hf_dcerpc_cn_bind_trans_btfn_01, /* [MS-RPCE] 2.2.2.14 */
5979 { "Security Context Multiplexing Supported", "dcerpc.cn_bind_trans_btfn.01", FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x01, NULL, HFILL }},
5980 { &hf_dcerpc_cn_bind_trans_btfn_02,
5981 { "Keep Connection On Orphan Supported", "dcerpc.cn_bind_trans_btfn.02", FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x02, NULL, HFILL }},
5982 { &hf_dcerpc_cn_alloc_hint,
5983 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5984 { &hf_dcerpc_cn_sec_addr_len,
5985 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5986 { &hf_dcerpc_cn_sec_addr,
5987 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5988 { &hf_dcerpc_cn_num_results,
5989 { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5990 { &hf_dcerpc_cn_ack_result,
5991 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, NULL, HFILL }},
5992 { &hf_dcerpc_cn_ack_reason,
5993 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, NULL, HFILL }},
5994 { &hf_dcerpc_cn_ack_trans_id,
5995 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5996 { &hf_dcerpc_cn_ack_trans_ver,
5997 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5998 { &hf_dcerpc_cn_ack_btfn,
5999 { "Bind Time Feature Negotiation Bitmask", "dcerpc.cn_ack_btfn", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6000 { &hf_dcerpc_cn_reject_reason,
6001 { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, NULL, HFILL }},
6002 { &hf_dcerpc_cn_num_protocols,
6003 { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6004 { &hf_dcerpc_cn_protocol_ver_major,
6005 { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6006 { &hf_dcerpc_cn_protocol_ver_minor,
6007 { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6008 { &hf_dcerpc_cn_cancel_count,
6009 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6010 { &hf_dcerpc_cn_status,
6011 { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, NULL, HFILL }},
6012 { &hf_dcerpc_cn_deseg_req,
6013 { "Desegmentation Required", "dcerpc.cn_deseg_req", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6014 { &hf_dcerpc_auth_type,
6015 { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS(authn_protocol_vals), 0x0, NULL, HFILL }},
6016 { &hf_dcerpc_auth_level,
6017 { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, NULL, HFILL }},
6018 { &hf_dcerpc_auth_pad_len,
6019 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6020 { &hf_dcerpc_auth_rsrvd,
6021 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6022 { &hf_dcerpc_auth_ctx_id,
6023 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6024 { &hf_dcerpc_dg_flags1,
6025 { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6026 { &hf_dcerpc_dg_flags1_rsrvd_01,
6027 { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_RESERVED_01, NULL, HFILL }},
6028 { &hf_dcerpc_dg_flags1_last_frag,
6029 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_LASTFRAG, NULL, HFILL }},
6030 { &hf_dcerpc_dg_flags1_frag,
6031 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_FRAG, NULL, HFILL }},
6032 { &hf_dcerpc_dg_flags1_nofack,
6033 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_NOFACK, NULL, HFILL }},
6034 { &hf_dcerpc_dg_flags1_maybe,
6035 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_MAYBE, NULL, HFILL }},
6036 { &hf_dcerpc_dg_flags1_idempotent,
6037 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_IDEMPOTENT, NULL, HFILL }},
6038 { &hf_dcerpc_dg_flags1_broadcast,
6039 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_BROADCAST, NULL, HFILL }},
6040 { &hf_dcerpc_dg_flags1_rsrvd_80,
6041 { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_RESERVED_80, NULL, HFILL }},
6042 { &hf_dcerpc_dg_flags2,
6043 { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6044 { &hf_dcerpc_dg_flags2_rsrvd_01,
6045 { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_01, NULL, HFILL }},
6046 { &hf_dcerpc_dg_flags2_cancel_pending,
6047 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_CANCEL_PENDING, NULL, HFILL }},
6048 { &hf_dcerpc_dg_flags2_rsrvd_04,
6049 { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_04, NULL, HFILL }},
6050 { &hf_dcerpc_dg_flags2_rsrvd_08,
6051 { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_08, NULL, HFILL }},
6052 { &hf_dcerpc_dg_flags2_rsrvd_10,
6053 { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_10, NULL, HFILL }},
6054 { &hf_dcerpc_dg_flags2_rsrvd_20,
6055 { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_20, NULL, HFILL }},
6056 { &hf_dcerpc_dg_flags2_rsrvd_40,
6057 { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_40, NULL, HFILL }},
6058 { &hf_dcerpc_dg_flags2_rsrvd_80,
6059 { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_80, NULL, HFILL }},
6060 { &hf_dcerpc_dg_serial_lo,
6061 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6062 { &hf_dcerpc_dg_serial_hi,
6063 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6064 { &hf_dcerpc_dg_ahint,
6065 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6066 { &hf_dcerpc_dg_ihint,
6067 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6068 { &hf_dcerpc_dg_frag_len,
6069 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6070 { &hf_dcerpc_dg_frag_num,
6071 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6072 { &hf_dcerpc_dg_auth_proto,
6073 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS(authn_protocol_vals), 0x0, NULL, HFILL }},
6074 { &hf_dcerpc_dg_seqnum,
6075 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6076 { &hf_dcerpc_dg_server_boot,
6077 { "Server boot time", "dcerpc.dg_server_boot", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0, NULL, HFILL }},
6078 { &hf_dcerpc_dg_if_ver,
6079 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6080 { &hf_dcerpc_krb5_av_prot_level,
6081 { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, NULL, HFILL }},
6082 { &hf_dcerpc_krb5_av_key_vers_num,
6083 { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6084 { &hf_dcerpc_krb5_av_key_auth_verifier,
6085 { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6086 { &hf_dcerpc_obj_id,
6087 { "Object", "dcerpc.obj_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6088 { &hf_dcerpc_dg_if_id,
6089 { "Interface", "dcerpc.dg_if_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6090 { &hf_dcerpc_dg_act_id,
6091 { "Activity", "dcerpc.dg_act_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6093 { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6095 { &hf_dcerpc_dg_cancel_vers,
6096 { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6098 { &hf_dcerpc_dg_cancel_id,
6099 { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6101 { &hf_dcerpc_dg_server_accepting_cancels,
6102 { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6104 { &hf_dcerpc_dg_fack_vers,
6105 { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6107 { &hf_dcerpc_dg_fack_window_size,
6108 { "Window Size", "dcerpc.fack_window_size", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6110 { &hf_dcerpc_dg_fack_max_tsdu,
6111 { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6113 { &hf_dcerpc_dg_fack_max_frag_size,
6114 { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6116 { &hf_dcerpc_dg_fack_serial_num,
6117 { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6119 { &hf_dcerpc_dg_fack_selack_len,
6120 { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6122 { &hf_dcerpc_dg_fack_selack,
6123 { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6125 { &hf_dcerpc_dg_status,
6126 { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, NULL, HFILL }},
6128 { &hf_dcerpc_array_max_count,
6129 { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
6131 { &hf_dcerpc_array_offset,
6132 { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
6134 { &hf_dcerpc_array_actual_count,
6135 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
6137 { &hf_dcerpc_array_buffer,
6138 { "Buffer", "dcerpc.array.buffer", FT_BYTES, BASE_NONE, NULL, 0x0, "Buffer: Buffer containing elements of the array", HFILL }},
6141 { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6143 { &hf_dcerpc_fragments,
6144 { "Reassembled DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
6145 NULL, 0x0, "DCE/RPC Fragments", HFILL }},
6147 { &hf_dcerpc_fragment,
6148 { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM, BASE_NONE,
6149 NULL, 0x0, NULL, HFILL }},
6151 { &hf_dcerpc_fragment_overlap,
6152 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE,
6153 NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
6155 { &hf_dcerpc_fragment_overlap_conflict,
6156 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE,
6157 NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
6159 { &hf_dcerpc_fragment_multiple_tails,
6160 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE,
6161 NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
6163 { &hf_dcerpc_fragment_too_long_fragment,
6164 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE,
6165 NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
6167 { &hf_dcerpc_fragment_error,
6168 { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE,
6169 NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
6171 { &hf_dcerpc_fragment_count,
6172 { "Fragment count", "dcerpc.fragment.count", FT_UINT32, BASE_DEC,
6173 NULL, 0x0, NULL, HFILL }},
6176 { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE,
6177 NULL, 0, "Time between Request and Response for DCE-RPC calls", HFILL }},
6179 { &hf_dcerpc_reassembled_in,
6180 { "Reassembled PDU in frame", "dcerpc.reassembled_in", FT_FRAMENUM, BASE_NONE,
6181 NULL, 0x0, "The DCE/RPC PDU is completely reassembled in the packet with this number", HFILL }},
6183 { &hf_dcerpc_reassembled_length,
6184 { "Reassembled DCE/RPC length", "dcerpc.reassembled.length", FT_UINT32, BASE_DEC,
6185 NULL, 0x0, "The total length of the reassembled payload", HFILL }},
6187 { &hf_dcerpc_unknown_if_id,
6188 { "Unknown DCERPC interface id", "dcerpc.unknown_if_id", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6190 { &hf_dcerpc_cn_rts_flags,
6191 { "RTS Flags", "dcerpc.cn_rts_flags", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6192 { &hf_dcerpc_cn_rts_flags_none,
6193 {"None", "dcerpc.cn_rts_flags.none", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_NONE, NULL, HFILL }},
6194 { &hf_dcerpc_cn_rts_flags_ping,
6195 { "Ping", "dcerpc.cn_rts.flags.ping", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_PING, NULL, HFILL }},
6196 { &hf_dcerpc_cn_rts_flags_other_cmd,
6197 { "Other Cmd", "dcerpc.cn_rts_flags.other_cmd", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_OTHER_CMD, NULL, HFILL }},
6198 { &hf_dcerpc_cn_rts_flags_recycle_channel,
6199 { "Recycle Channel", "dcerpc.cn_rts_flags.recycle_channel", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_RECYCLE_CHANNEL, NULL, HFILL }},
6200 { &hf_dcerpc_cn_rts_flags_in_channel,
6201 { "In Channel", "dcerpc.cn_rts_flags.in_channel", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_IN_CHANNEL, NULL, HFILL }},
6202 { &hf_dcerpc_cn_rts_flags_out_channel,
6203 { "Out Channel", "dcerpc.cn_rts_flags.out_channel", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_OUT_CHANNEL, NULL, HFILL }},
6204 { &hf_dcerpc_cn_rts_flags_eof,
6205 { "EOF", "dcerpc.cn_rts_flags.eof", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_EOF, NULL, HFILL }},
6206 { &hf_dcerpc_cn_rts_commands_nb,
6207 { "RTS Number of Commands", "dcerpc.cn_rts_commands_nb", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6208 { &hf_dcerpc_cn_rts_command,
6209 { "RTS Command", "dcerpc.cn_rts_command", FT_UINT32, BASE_HEX, VALS(rts_command_vals), 0x0, NULL, HFILL }},
6210 { &hf_dcerpc_cn_rts_command_receivewindowsize,
6211 {"Receive Window Size", "dcerpc.cn_rts_command.receivewindowsize", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6212 { &hf_dcerpc_cn_rts_command_fack_bytesreceived,
6213 {"Bytes Received", "dcerpc.cn_rts_command.fack.bytesreceived", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6214 { &hf_dcerpc_cn_rts_command_fack_availablewindow,
6215 {"Available Window", "dcerpc.cn_rts_command.fack.availablewindow", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6216 { &hf_dcerpc_cn_rts_command_fack_channelcookie,
6217 {"Channel Cookie", "dcerpc.cn_rts_command.fack.channelcookie", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6218 { &hf_dcerpc_cn_rts_command_connectiontimeout,
6219 {"Connection Timeout", "dcerpc.cn_rts_command.connectiontimeout", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6220 { &hf_dcerpc_cn_rts_command_cookie,
6221 {"Cookie", "dcerpc.cn_rts_command.cookie", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6222 { &hf_dcerpc_cn_rts_command_channellifetime,
6223 {"Channel Lifetime", "dcerpc.cn_rts_command.channellifetime", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6224 { &hf_dcerpc_cn_rts_command_clientkeepalive,
6225 {"Client Keepalive", "dcerpc.cn_rts_command.clientkeepalive", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6226 { &hf_dcerpc_cn_rts_command_version,
6227 {"Version", "dcerpc.cn_rts_command.version", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6228 { &hf_dcerpc_cn_rts_command_conformancecount,
6229 {"Conformance Count", "dcerpc.cn_rts_command.padding.conformancecount", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6230 { &hf_dcerpc_cn_rts_command_padding,
6231 { "Padding", "dcerpc.cn_rts_command.padding.padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
6232 { &hf_dcerpc_cn_rts_command_addrtype,
6233 { "Address Type", "dcerpc.cn_rts_command.addrtype", FT_UINT32, BASE_DEC, VALS(rts_addresstype_vals), 0x0, NULL, HFILL }},
6234 { &hf_dcerpc_cn_rts_command_associationgroupid,
6235 {"Association Group ID", "dcerpc.cn_rts_command.associationgroupid", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6236 { &hf_dcerpc_cn_rts_command_forwarddestination,
6237 {"Forward Destination", "dcerpc.cn_rts_command.forwarddestination", FT_UINT32, BASE_DEC, VALS(rts_forward_destination_vals), 0x0, NULL, HFILL }},
6238 { &hf_dcerpc_cn_rts_command_pingtrafficsentnotify,
6239 {"Ping Traffic Sent Notify", "dcerpc.cn_rts_command.pingtrafficsentnotify", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6241 static gint *ett[] = {
6243 &ett_dcerpc_cn_flags,
6245 &ett_dcerpc_cn_iface,
6246 &ett_dcerpc_cn_trans_syntax,
6247 &ett_dcerpc_cn_trans_btfn,
6248 &ett_dcerpc_cn_rts_flags,
6249 &ett_dcerpc_cn_rts_command,
6250 &ett_dcerpc_cn_rts_pdu,
6252 &ett_dcerpc_dg_flags1,
6253 &ett_dcerpc_dg_flags2,
6254 &ett_dcerpc_pointer_data,
6256 &ett_dcerpc_fragments,
6257 &ett_dcerpc_fragment,
6258 &ett_dcerpc_krb5_auth_verf,
6261 static ei_register_info ei[] = {
6262 { &ei_dcerpc_fragment, { "dcerpc.fragment", PI_REASSEMBLE, PI_CHAT, "%s fragment", EXPFILL }},
6263 { &ei_dcerpc_fragment_reassembled, { "dcerpc.fragment_reassembled", PI_REASSEMBLE, PI_CHAT, "%s fragment, reassembled", EXPFILL }},
6264 { &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 }},
6265 { &ei_dcerpc_no_request_found, { "dcerpc.no_request_found", PI_SEQUENCE, PI_NOTE, "No request to this DCE/RPC call found", EXPFILL }},
6266 { &ei_dcerpc_cn_status, { "dcerpc.cn_status.expert", PI_RESPONSE_CODE, PI_NOTE, "Fault: %s", EXPFILL }},
6267 { &ei_dcerpc_fragment_multiple, { "dcerpc.fragment_multiple", PI_SEQUENCE, PI_CHAT, "Multiple DCE/RPC fragments/PDU's in one packet", EXPFILL }},
6268 { &ei_dcerpc_context_change, { "dcerpc.context_change", PI_SEQUENCE, PI_CHAT, "Context change: %s", EXPFILL }},
6269 { &ei_dcerpc_bind_not_acknowledged, { "dcerpc.bind_not_acknowledged", PI_SEQUENCE, PI_WARN, "Bind not acknowledged", EXPFILL }},
6272 /* Decode As handling */
6273 static build_valid_func dcerpc_da_build_value[1] = {dcerpc_value};
6274 static decode_as_value_t dcerpc_da_values = {dcerpc_prompt, 1, dcerpc_da_build_value};
6275 static decode_as_t dcerpc_da = {"dcerpc", "DCE-RPC",
6276 /* XXX - DCE/RPC doesn't have a true (sub)dissector table, so
6277 provide a "fake" one to fit the Decode As algorithm */
6279 1, 0, &dcerpc_da_values, NULL, NULL,
6280 dcerpc_populate_list, decode_dcerpc_binding_reset, dcerpc_decode_as_change, dcerpc_decode_as_free};
6282 module_t *dcerpc_module;
6283 expert_module_t* expert_dcerpc;
6285 proto_dcerpc = proto_register_protocol("Distributed Computing Environment / Remote Procedure Call (DCE/RPC)", "DCERPC", "dcerpc");
6286 proto_register_field_array(proto_dcerpc, hf, array_length(hf));
6287 proto_register_subtree_array(ett, array_length(ett));
6288 expert_dcerpc = expert_register_protocol(proto_dcerpc);
6289 expert_register_field_array(expert_dcerpc, ei, array_length(ei));
6291 register_init_routine(dcerpc_init_protocol);
6292 dcerpc_module = prefs_register_protocol(proto_dcerpc, NULL);
6293 prefs_register_bool_preference(dcerpc_module,
6295 "Reassemble DCE/RPC messages spanning multiple TCP segments",
6296 "Whether the DCE/RPC dissector should reassemble messages"
6297 " spanning multiple TCP segments."
6298 " To use this option, you must also enable"
6299 " \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
6300 &dcerpc_cn_desegment);
6301 prefs_register_bool_preference(dcerpc_module,
6302 "reassemble_dcerpc",
6303 "Reassemble DCE/RPC fragments",
6304 "Whether the DCE/RPC dissector should reassemble fragmented DCE/RPC PDUs",
6305 &dcerpc_reassemble);
6306 register_init_routine(dcerpc_reassemble_init);
6307 dcerpc_uuids = g_hash_table_new(dcerpc_uuid_hash, dcerpc_uuid_equal);
6308 dcerpc_tap = register_tap("dcerpc");
6310 register_decode_as(&dcerpc_da);
6314 proto_reg_handoff_dcerpc(void)
6316 heur_dissector_add("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
6317 heur_dissector_add("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
6318 heur_dissector_add("udp", dissect_dcerpc_dg, proto_dcerpc);
6319 heur_dissector_add("smb_transact", dissect_dcerpc_cn_smbpipe, proto_dcerpc);
6320 heur_dissector_add("smb2_heur_subdissectors", dissect_dcerpc_cn_smb2, proto_dcerpc);
6321 heur_dissector_add("http", dissect_dcerpc_cn_bs, proto_dcerpc);
6322 dcerpc_smb_init(proto_dcerpc);
6324 guids_add_uuid(&uuid_data_repr_proto, "32bit NDR");
6325 guids_add_uuid(&uuid_ndr64, "64bit NDR");
6326 guids_add_uuid(&uuid_bind_time_feature_nego_00, "bind time feature negotiation");
6327 guids_add_uuid(&uuid_bind_time_feature_nego_01, "bind time feature negotiation");
6328 guids_add_uuid(&uuid_bind_time_feature_nego_02, "bind time feature negotiation");
6329 guids_add_uuid(&uuid_bind_time_feature_nego_03, "bind time feature negotiation");
6330 guids_add_uuid(&uuid_asyncemsmdb, "async MAPI");
6334 * Editor modelines - http://www.wireshark.org/tools/modelines.html
6339 * indent-tabs-mode: nil
6342 * vi: set shiftwidth=4 tabstop=8 expandtab:
6343 * :indentSize=4:tabSize=8:noTabs=true: