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/dissectors/packet-dcerpc.h>
50 #include <epan/dissectors/packet-dcerpc-nt.h>
52 static int dcerpc_tap
= -1;
54 /* 32bit Network Data Representation, see DCE/RPC Appendix I */
55 static e_uuid_t uuid_data_repr_proto
= { 0x8a885d04, 0x1ceb, 0x11c9,
56 { 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60 } };
58 /* 64bit Network Data Representation, introduced in Windows Server 2008 */
59 static e_uuid_t uuid_ndr64
= { 0x71710533, 0xbeba, 0x4937,
60 { 0x83, 0x19, 0xb5, 0xdb, 0xef, 0x9c, 0xcc, 0x36 } };
62 /* Bind Time Feature Negotiation, see [MS-RPCE] 3.3.1.5.3 */
63 static e_uuid_t uuid_bind_time_feature_nego_00
= { 0x6cb71c2c, 0x9812, 0x4540, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
64 static e_uuid_t uuid_bind_time_feature_nego_01
= { 0x6cb71c2c, 0x9812, 0x4540, { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
65 static e_uuid_t uuid_bind_time_feature_nego_02
= { 0x6cb71c2c, 0x9812, 0x4540, { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
66 static e_uuid_t uuid_bind_time_feature_nego_03
= { 0x6cb71c2c, 0x9812, 0x4540, { 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
68 /* see [MS-OXRPC] Appendix A: Full IDL, http://msdn.microsoft.com/en-us/library/ee217991%28v=exchg.80%29.aspx */
69 static e_uuid_t uuid_asyncemsmdb
= { 0x5261574a, 0x4572, 0x206e,
70 { 0xb2, 0x68, 0x6b, 0x19, 0x92, 0x13, 0xb4, 0xe4 } };
72 static const value_string pckt_vals
[] = {
73 { PDU_REQ
, "Request"},
75 { PDU_RESP
, "Response"},
76 { PDU_FAULT
, "Fault"},
77 { PDU_WORKING
, "Working"},
78 { PDU_NOCALL
, "Nocall"},
79 { PDU_REJECT
, "Reject"},
81 { PDU_CL_CANCEL
, "Cl_cancel"},
83 { PDU_CANCEL_ACK
, "Cancel_ack"},
85 { PDU_BIND_ACK
, "Bind_ack"},
86 { PDU_BIND_NAK
, "Bind_nak"},
87 { PDU_ALTER
, "Alter_context"},
88 { PDU_ALTER_ACK
, "Alter_context_resp"},
89 { PDU_AUTH3
, "AUTH3"},
90 { PDU_SHUTDOWN
, "Shutdown"},
91 { PDU_CO_CANCEL
, "Co_cancel"},
92 { PDU_ORPHANED
, "Orphaned"},
93 { PDU_RTS
, "RPC-over-HTTP RTS"},
97 static const value_string drep_byteorder_vals
[] = {
99 { 1, "Little-endian" },
103 static const value_string drep_character_vals
[] = {
109 #define DCE_RPC_DREP_FP_IEEE 0
110 #define DCE_RPC_DREP_FP_VAX 1
111 #define DCE_RPC_DREP_FP_CRAY 2
112 #define DCE_RPC_DREP_FP_IBM 3
114 static const value_string drep_fp_vals
[] = {
115 { DCE_RPC_DREP_FP_IEEE
, "IEEE" },
116 { DCE_RPC_DREP_FP_VAX
, "VAX" },
117 { DCE_RPC_DREP_FP_CRAY
, "Cray" },
118 { DCE_RPC_DREP_FP_IBM
, "IBM" },
123 * Authentication services.
125 static const value_string authn_protocol_vals
[] = {
126 { DCE_C_RPC_AUTHN_PROTOCOL_NONE
, "None" },
127 { DCE_C_RPC_AUTHN_PROTOCOL_KRB5
, "Kerberos 5" },
128 { DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO
, "SPNEGO" },
129 { DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP
, "NTLMSSP" },
130 { DCE_C_RPC_AUTHN_PROTOCOL_GSS_SCHANNEL
, "SCHANNEL SSP" },
131 { DCE_C_RPC_AUTHN_PROTOCOL_GSS_KERBEROS
, "Kerberos SSP" },
132 { DCE_C_RPC_AUTHN_PROTOCOL_DPA
,
133 "Distributed Password Authentication SSP"},
134 { DCE_C_RPC_AUTHN_PROTOCOL_MSN
, "MSN SSP"},
135 { DCE_C_RPC_AUTHN_PROTOCOL_DIGEST
, "Digest SSP"},
136 { DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN
, "NETLOGON Secure Channel" },
137 { DCE_C_RPC_AUTHN_PROTOCOL_MQ
, "MSMQ SSP"},
144 static const value_string authn_level_vals
[] = {
145 { DCE_C_AUTHN_LEVEL_NONE
, "None" },
146 { DCE_C_AUTHN_LEVEL_CONNECT
, "Connect" },
147 { DCE_C_AUTHN_LEVEL_CALL
, "Call" },
148 { DCE_C_AUTHN_LEVEL_PKT
, "Packet" },
149 { DCE_C_AUTHN_LEVEL_PKT_INTEGRITY
, "Packet integrity" },
150 { DCE_C_AUTHN_LEVEL_PKT_PRIVACY
, "Packet privacy" },
155 * Flag bits in first flag field in connectionless PDU header.
157 #define PFCL1_RESERVED_01 0x01 /* Reserved for use by implementations */
158 #define PFCL1_LASTFRAG 0x02 /* If set, the PDU is the last
159 * fragment of a multi-PDU
161 #define PFCL1_FRAG 0x04 /* If set, the PDU is a fragment of
162 a multi-PDU transmission */
163 #define PFCL1_NOFACK 0x08 /* If set, the receiver is not
164 * requested to send a `fack' PDU
165 * for the fragment */
166 #define PFCL1_MAYBE 0x10 /* If set, the PDU is for a `maybe'
168 #define PFCL1_IDEMPOTENT 0x20 /* If set, the PDU is for an idempotent
170 #define PFCL1_BROADCAST 0x40 /* If set, the PDU is for a broadcast
172 #define PFCL1_RESERVED_80 0x80 /* Reserved for use by implementations */
175 * Flag bits in second flag field in connectionless PDU header.
177 #define PFCL2_RESERVED_01 0x01 /* Reserved for use by implementations */
178 #define PFCL2_CANCEL_PENDING 0x02 /* Cancel pending at the call end */
179 #define PFCL2_RESERVED_04 0x04 /* Reserved for future use */
180 #define PFCL2_RESERVED_08 0x08 /* Reserved for future use */
181 #define PFCL2_RESERVED_10 0x10 /* Reserved for future use */
182 #define PFCL2_RESERVED_20 0x20 /* Reserved for future use */
183 #define PFCL2_RESERVED_40 0x40 /* Reserved for future use */
184 #define PFCL2_RESERVED_80 0x80 /* Reserved for future use */
187 * Flag bits in connection-oriented PDU header.
189 #define PFC_FIRST_FRAG 0x01 /* First fragment */
190 #define PFC_LAST_FRAG 0x02 /* Last fragment */
191 #define PFC_PENDING_CANCEL 0x04 /* Cancel was pending at sender */
192 #define PFC_RESERVED_1 0x08
193 #define PFC_CONC_MPX 0x10 /* supports concurrent multiplexing
194 * of a single connection. */
195 #define PFC_DID_NOT_EXECUTE 0x20 /* only meaningful on `fault' packet;
196 * if true, guaranteed call did not
198 #define PFC_MAYBE 0x40 /* `maybe' call semantics requested */
199 #define PFC_OBJECT_UUID 0x80 /* if true, a non-nil object UUID
200 * was specified in the handle, and
201 * is present in the optional object
202 * field. If false, the object field
206 * Tests whether a connection-oriented PDU is fragmented; returns TRUE if
207 * it's not fragmented (i.e., this is both the first *and* last fragment),
208 * and FALSE otherwise.
210 #define PFC_NOT_FRAGMENTED(hdr) \
211 ((hdr->flags&(PFC_FIRST_FRAG|PFC_LAST_FRAG)) == (PFC_FIRST_FRAG|PFC_LAST_FRAG))
214 * Presentation context negotiation result.
216 static const value_string p_cont_result_vals
[] = {
218 { 1, "User rejection" },
219 { 2, "Provider rejection" },
220 { 3, "Negotiate ACK" }, /* [MS-RPCE] 2.2.2.4 */
225 * Presentation context negotiation rejection reasons.
227 static const value_string p_provider_reason_vals
[] = {
228 { 0, "Reason not specified" },
229 { 1, "Abstract syntax not supported" },
230 { 2, "Proposed transfer syntaxes not supported" },
231 { 3, "Local limit exceeded" },
238 #define REASON_NOT_SPECIFIED 0
239 #define TEMPORARY_CONGESTION 1
240 #define LOCAL_LIMIT_EXCEEDED 2
241 #define CALLED_PADDR_UNKNOWN 3 /* not used */
242 #define PROTOCOL_VERSION_NOT_SUPPORTED 4
243 #define DEFAULT_CONTEXT_NOT_SUPPORTED 5 /* not used */
244 #define USER_DATA_NOT_READABLE 6 /* not used */
245 #define NO_PSAP_AVAILABLE 7 /* not used */
246 #define AUTH_TYPE_NOT_RECOGNIZED 8 /* [MS-RPCE] 2.2.2.5 */
247 #define INVALID_CHECKSUM 9 /* [MS-RPCE] 2.2.2.5 */
249 static const value_string reject_reason_vals
[] = {
250 { REASON_NOT_SPECIFIED
, "Reason not specified" },
251 { TEMPORARY_CONGESTION
, "Temporary congestion" },
252 { LOCAL_LIMIT_EXCEEDED
, "Local limit exceeded" },
253 { CALLED_PADDR_UNKNOWN
, "Called paddr unknown" },
254 { PROTOCOL_VERSION_NOT_SUPPORTED
, "Protocol version not supported" },
255 { DEFAULT_CONTEXT_NOT_SUPPORTED
, "Default context not supported" },
256 { USER_DATA_NOT_READABLE
, "User data not readable" },
257 { NO_PSAP_AVAILABLE
, "No PSAP available" },
258 { AUTH_TYPE_NOT_RECOGNIZED
, "Authentication type not recognized" },
259 { INVALID_CHECKSUM
, "Invalid checksum" },
264 * Reject status codes.
266 static const value_string reject_status_vals
[] = {
267 { 0, "Stub-defined exception" },
268 { 0x00000001, "nca_s_fault_other" },
269 { 0x00000005, "nca_s_fault_access_denied" },
270 { 0x000006f7, "nca_s_fault_ndr" },
271 { 0x000006d8, "nca_s_fault_cant_perform" },
272 { 0x1c000001, "nca_s_fault_int_div_by_zero" },
273 { 0x1c000002, "nca_s_fault_addr_error" },
274 { 0x1c000003, "nca_s_fault_fp_div_zero" },
275 { 0x1c000004, "nca_s_fault_fp_underflow" },
276 { 0x1c000005, "nca_s_fault_fp_overflow" },
277 { 0x1c000006, "nca_s_fault_invalid_tag" },
278 { 0x1c000007, "nca_s_fault_invalid_bound" },
279 { 0x1c000008, "nca_rpc_version_mismatch" },
280 { 0x1c000009, "nca_unspec_reject" },
281 { 0x1c00000a, "nca_s_bad_actid" },
282 { 0x1c00000b, "nca_who_are_you_failed" },
283 { 0x1c00000c, "nca_manager_not_entered" },
284 { 0x1c00000d, "nca_s_fault_cancel" },
285 { 0x1c00000e, "nca_s_fault_ill_inst" },
286 { 0x1c00000f, "nca_s_fault_fp_error" },
287 { 0x1c000010, "nca_s_fault_int_overflow" },
288 { 0x1c000014, "nca_s_fault_pipe_empty" },
289 { 0x1c000015, "nca_s_fault_pipe_closed" },
290 { 0x1c000016, "nca_s_fault_pipe_order" },
291 { 0x1c000017, "nca_s_fault_pipe_discipline" },
292 { 0x1c000018, "nca_s_fault_pipe_comm_error" },
293 { 0x1c000019, "nca_s_fault_pipe_memory" },
294 { 0x1c00001a, "nca_s_fault_context_mismatch" },
295 { 0x1c00001b, "nca_s_fault_remote_no_memory" },
296 { 0x1c00001c, "nca_invalid_pres_context_id" },
297 { 0x1c00001d, "nca_unsupported_authn_level" },
298 { 0x1c00001f, "nca_invalid_checksum" },
299 { 0x1c000020, "nca_invalid_crc" },
300 { 0x1c000021, "ncs_s_fault_user_defined" },
301 { 0x1c000022, "nca_s_fault_tx_open_failed" },
302 { 0x1c000023, "nca_s_fault_codeset_conv_error" },
303 { 0x1c000024, "nca_s_fault_object_not_found" },
304 { 0x1c000025, "nca_s_fault_no_client_stub" },
305 { 0x1c010002, "nca_op_rng_error" },
306 { 0x1c010003, "nca_unk_if"},
307 { 0x1c010006, "nca_wrong_boot_time" },
308 { 0x1c010009, "nca_s_you_crashed" },
309 { 0x1c01000b, "nca_proto_error" },
310 { 0x1c010013, "nca_out_args_too_big" },
311 { 0x1c010014, "nca_server_too_busy" },
312 { 0x1c010017, "nca_unsupported_type" },
313 /* MS Windows specific values
314 * see: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/system_error_codes__1700-3999_.asp
315 * and: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/seccrypto/security/common_hresult_values.asp
316 * and: http://www.megos.ch/support/doserrors.txt
318 * XXX - we might need a way to dynamically add entries here, as higher layer protocols use these values too,
319 * at least MS protocols (like DCOM) do it that way ... */
320 { 0x80004001, "E_NOTIMPL" },
321 { 0x80004003, "E_POINTER" },
322 { 0x80004004, "E_ABORT" },
323 { 0x8000FFFF, "E_UNEXPECTED" },
324 { 0x80010105, "RPC_E_SERVERFAULT" },
325 { 0x80010108, "RPC_E_DISCONNECTED" },
326 { 0x80010113, "RPC_E_INVALID_IPID" },
327 { 0x8001011F, "RPC_E_TIMEOUT" },
328 { 0x80020003, "DISP_E_MEMBERNOTFOUND" },
329 { 0x80020006, "DISP_E_UNKNOWNNAME" },
330 { 0x8002000E, "DISP_E_BADPARAMCOUNT" },
331 { 0x8004CB00, "CBA_E_MALFORMED" },
332 { 0x8004CB01, "CBA_E_UNKNOWNOBJECT" },
333 { 0x8004CB05, "CBA_E_INVALIDID" },
334 { 0x8004CB09, "CBA_E_INVALIDCOOKIE" },
335 { 0x8004CB0B, "CBA_E_QOSTYPEUNSUPPORTED" },
336 { 0x8004CB0C, "CBA_E_QOSVALUEUNSUPPORTED" },
337 { 0x8004CB0F, "CBA_E_NOTAPPLICABLE" },
338 { 0x8004CB12, "CBA_E_LIMITVIOLATION" },
339 { 0x8004CB13, "CBA_E_QOSTYPENOTAPPLICABLE" },
340 { 0x8004CB18, "CBA_E_OUTOFPARTNERACCOS" },
341 { 0x8004CB1C, "CBA_E_FLAGUNSUPPORTED" },
342 { 0x8004CB23, "CBA_E_FRAMECOUNTUNSUPPORTED" },
343 { 0x8004CB25, "CBA_E_MODECHANGE" },
344 { 0x8007000E, "E_OUTOFMEMORY" },
345 { 0x80070057, "E_INVALIDARG" },
346 { 0x800706d1, "RPC_S_PROCNUM_OUT_OF_RANGE" },
347 { 0x80070776, "OR_INVALID_OXID" },
355 #define RTS_FLAG_NONE 0x0000
356 #define RTS_FLAG_PING 0x0001
357 #define RTS_FLAG_OTHER_CMD 0x0002
358 #define RTS_FLAG_RECYCLE_CHANNEL 0x0004
359 #define RTS_FLAG_IN_CHANNEL 0x0008
360 #define RTS_FLAG_OUT_CHANNEL 0x0010
361 #define RTS_FLAG_EOF 0x0020
362 #define RTS_FLAG_ECHO 0x0040
368 #define RTS_CMD_RECEIVEWINDOWSIZE 0x0
369 #define RTS_CMD_FLOWCONTROLACK 0x1
370 #define RTS_CMD_CONNECTIONTIMEOUT 0x2
371 #define RTS_CMD_COOKIE 0x3
372 #define RTS_CMD_CHANNELLIFETIME 0x4
373 #define RTS_CMD_CLIENTKEEPALIVE 0x5
374 #define RTS_CMD_VERSION 0x6
375 #define RTS_CMD_EMPTY 0x7
376 #define RTS_CMD_PADDING 0x8
377 #define RTS_CMD_NEGATIVEANCE 0x9
378 #define RTS_CMD_ANCE 0xA
379 #define RTS_CMD_CLIENTADDRESS 0xB
380 #define RTS_CMD_ASSOCIATIONGROUPID 0xC
381 #define RTS_CMD_DESTINATION 0xD
382 #define RTS_CMD_PINGTRAFFICSENTNOTIFY 0xE
384 static const value_string rts_command_vals
[] = {
385 { RTS_CMD_RECEIVEWINDOWSIZE
, "ReceiveWindowSize" },
386 { RTS_CMD_FLOWCONTROLACK
, "FlowControlAck" },
387 { RTS_CMD_CONNECTIONTIMEOUT
, "ConnectionTimeOut" },
388 { RTS_CMD_COOKIE
, "Cookie" },
389 { RTS_CMD_CHANNELLIFETIME
, "ChannelLifetime" },
390 { RTS_CMD_CLIENTKEEPALIVE
, "ClientKeepalive" },
391 { RTS_CMD_VERSION
, "Version" },
392 { RTS_CMD_EMPTY
, "Empty" },
393 { RTS_CMD_PADDING
, "Padding" },
394 { RTS_CMD_NEGATIVEANCE
, "NegativeANCE" },
395 { RTS_CMD_ANCE
, "ANCE" },
396 { RTS_CMD_CLIENTADDRESS
, "ClientAddress" },
397 { RTS_CMD_ASSOCIATIONGROUPID
, "AssociationGroupId" },
398 { RTS_CMD_DESTINATION
, "Destination" },
399 { RTS_CMD_PINGTRAFFICSENTNOTIFY
, "PingTrafficSentNotify" },
404 * RTS client address type
409 static const value_string rts_addresstype_vals
[] = {
410 { RTS_IPV4
, "IPV4" },
411 { RTS_IPV6
, "IPV6" },
416 * RTS Forward destination
419 static const value_string rts_forward_destination_vals
[] = {
421 { 0x1, "FDInProxy" },
423 { 0x3, "FDOutProxy" },
427 /* we need to keep track of what transport were used, ie what handle we came
428 * in through so we know what kind of pinfo->dce_smb_fid was passed to us.
430 /* Value of -1 is reserved for "not DCE packet" in packet_info.dcetransporttype. */
431 #define DCE_TRANSPORT_UNKNOWN 0
432 #define DCE_CN_TRANSPORT_SMBPIPE 1
435 static int proto_dcerpc
= -1;
438 static int hf_dcerpc_request_in
= -1;
439 static int hf_dcerpc_time
= -1;
440 static int hf_dcerpc_response_in
= -1;
441 static int hf_dcerpc_ver
= -1;
442 static int hf_dcerpc_ver_minor
= -1;
443 static int hf_dcerpc_packet_type
= -1;
444 static int hf_dcerpc_cn_flags
= -1;
445 static int hf_dcerpc_cn_flags_first_frag
= -1;
446 static int hf_dcerpc_cn_flags_last_frag
= -1;
447 static int hf_dcerpc_cn_flags_cancel_pending
= -1;
448 static int hf_dcerpc_cn_flags_reserved
= -1;
449 static int hf_dcerpc_cn_flags_mpx
= -1;
450 static int hf_dcerpc_cn_flags_dne
= -1;
451 static int hf_dcerpc_cn_flags_maybe
= -1;
452 static int hf_dcerpc_cn_flags_object
= -1;
453 static int hf_dcerpc_drep
= -1;
454 int hf_dcerpc_drep_byteorder
= -1;
455 static int hf_dcerpc_drep_character
= -1;
456 static int hf_dcerpc_drep_fp
= -1;
457 static int hf_dcerpc_cn_frag_len
= -1;
458 static int hf_dcerpc_cn_auth_len
= -1;
459 static int hf_dcerpc_cn_call_id
= -1;
460 static int hf_dcerpc_cn_max_xmit
= -1;
461 static int hf_dcerpc_cn_max_recv
= -1;
462 static int hf_dcerpc_cn_assoc_group
= -1;
463 static int hf_dcerpc_cn_num_ctx_items
= -1;
464 static int hf_dcerpc_cn_ctx_item
= -1;
465 static int hf_dcerpc_cn_ctx_id
= -1;
466 static int hf_dcerpc_cn_num_trans_items
= -1;
467 static int hf_dcerpc_cn_bind_abstract_syntax
= -1;
468 static int hf_dcerpc_cn_bind_if_id
= -1;
469 static int hf_dcerpc_cn_bind_if_ver
= -1;
470 static int hf_dcerpc_cn_bind_if_ver_minor
= -1;
471 static int hf_dcerpc_cn_bind_trans_syntax
= -1;
472 static int hf_dcerpc_cn_bind_trans_id
= -1;
473 static int hf_dcerpc_cn_bind_trans_ver
= -1;
474 static int hf_dcerpc_cn_bind_trans_btfn_01
= -1;
475 static int hf_dcerpc_cn_bind_trans_btfn_02
= -1;
476 static int hf_dcerpc_cn_alloc_hint
= -1;
477 static int hf_dcerpc_cn_sec_addr_len
= -1;
478 static int hf_dcerpc_cn_sec_addr
= -1;
479 static int hf_dcerpc_cn_num_results
= -1;
480 static int hf_dcerpc_cn_ack_result
= -1;
481 static int hf_dcerpc_cn_ack_reason
= -1;
482 static int hf_dcerpc_cn_ack_trans_id
= -1;
483 static int hf_dcerpc_cn_ack_trans_ver
= -1;
484 static int hf_dcerpc_cn_ack_btfn
= -1;
485 static int hf_dcerpc_cn_reject_reason
= -1;
486 static int hf_dcerpc_cn_num_protocols
= -1;
487 static int hf_dcerpc_cn_protocol_ver_major
= -1;
488 static int hf_dcerpc_cn_protocol_ver_minor
= -1;
489 static int hf_dcerpc_cn_cancel_count
= -1;
490 static int hf_dcerpc_cn_status
= -1;
491 static int hf_dcerpc_cn_deseg_req
= -1;
492 static int hf_dcerpc_cn_rts_flags
= -1;
493 static int hf_dcerpc_cn_rts_flags_none
= -1;
494 static int hf_dcerpc_cn_rts_flags_ping
= -1;
495 static int hf_dcerpc_cn_rts_flags_other_cmd
= -1;
496 static int hf_dcerpc_cn_rts_flags_recycle_channel
= -1;
497 static int hf_dcerpc_cn_rts_flags_in_channel
= -1;
498 static int hf_dcerpc_cn_rts_flags_out_channel
= -1;
499 static int hf_dcerpc_cn_rts_flags_eof
= -1;
500 static int hf_dcerpc_cn_rts_commands_nb
= -1;
501 static int hf_dcerpc_cn_rts_command
= -1;
502 static int hf_dcerpc_cn_rts_command_receivewindowsize
= -1;
503 static int hf_dcerpc_cn_rts_command_fack_bytesreceived
= -1;
504 static int hf_dcerpc_cn_rts_command_fack_availablewindow
= -1;
505 static int hf_dcerpc_cn_rts_command_fack_channelcookie
= -1;
506 static int hf_dcerpc_cn_rts_command_connectiontimeout
= -1;
507 static int hf_dcerpc_cn_rts_command_cookie
= -1;
508 static int hf_dcerpc_cn_rts_command_channellifetime
= -1;
509 static int hf_dcerpc_cn_rts_command_clientkeepalive
= -1;
510 static int hf_dcerpc_cn_rts_command_version
= -1;
511 static int hf_dcerpc_cn_rts_command_conformancecount
= -1;
512 static int hf_dcerpc_cn_rts_command_padding
= -1;
513 static int hf_dcerpc_cn_rts_command_addrtype
= -1;
514 static int hf_dcerpc_cn_rts_command_associationgroupid
= -1;
515 static int hf_dcerpc_cn_rts_command_forwarddestination
= -1;
516 static int hf_dcerpc_cn_rts_command_pingtrafficsentnotify
= -1;
517 static int hf_dcerpc_auth_type
= -1;
518 static int hf_dcerpc_auth_level
= -1;
519 static int hf_dcerpc_auth_pad_len
= -1;
520 static int hf_dcerpc_auth_rsrvd
= -1;
521 static int hf_dcerpc_auth_ctx_id
= -1;
522 static int hf_dcerpc_dg_flags1
= -1;
523 static int hf_dcerpc_dg_flags1_rsrvd_01
= -1;
524 static int hf_dcerpc_dg_flags1_last_frag
= -1;
525 static int hf_dcerpc_dg_flags1_frag
= -1;
526 static int hf_dcerpc_dg_flags1_nofack
= -1;
527 static int hf_dcerpc_dg_flags1_maybe
= -1;
528 static int hf_dcerpc_dg_flags1_idempotent
= -1;
529 static int hf_dcerpc_dg_flags1_broadcast
= -1;
530 static int hf_dcerpc_dg_flags1_rsrvd_80
= -1;
531 static int hf_dcerpc_dg_flags2
= -1;
532 static int hf_dcerpc_dg_flags2_rsrvd_01
= -1;
533 static int hf_dcerpc_dg_flags2_cancel_pending
= -1;
534 static int hf_dcerpc_dg_flags2_rsrvd_04
= -1;
535 static int hf_dcerpc_dg_flags2_rsrvd_08
= -1;
536 static int hf_dcerpc_dg_flags2_rsrvd_10
= -1;
537 static int hf_dcerpc_dg_flags2_rsrvd_20
= -1;
538 static int hf_dcerpc_dg_flags2_rsrvd_40
= -1;
539 static int hf_dcerpc_dg_flags2_rsrvd_80
= -1;
540 static int hf_dcerpc_dg_serial_hi
= -1;
541 static int hf_dcerpc_obj_id
= -1;
542 static int hf_dcerpc_dg_if_id
= -1;
543 static int hf_dcerpc_dg_act_id
= -1;
544 static int hf_dcerpc_dg_serial_lo
= -1;
545 static int hf_dcerpc_dg_ahint
= -1;
546 static int hf_dcerpc_dg_ihint
= -1;
547 static int hf_dcerpc_dg_frag_len
= -1;
548 static int hf_dcerpc_dg_frag_num
= -1;
549 static int hf_dcerpc_dg_auth_proto
= -1;
550 static int hf_dcerpc_opnum
= -1;
551 static int hf_dcerpc_dg_seqnum
= -1;
552 static int hf_dcerpc_dg_server_boot
= -1;
553 static int hf_dcerpc_dg_if_ver
= -1;
554 static int hf_dcerpc_krb5_av_prot_level
= -1;
555 static int hf_dcerpc_krb5_av_key_vers_num
= -1;
556 static int hf_dcerpc_krb5_av_key_auth_verifier
= -1;
557 static int hf_dcerpc_dg_cancel_vers
= -1;
558 static int hf_dcerpc_dg_cancel_id
= -1;
559 static int hf_dcerpc_dg_server_accepting_cancels
= -1;
560 static int hf_dcerpc_dg_fack_vers
= -1;
561 static int hf_dcerpc_dg_fack_window_size
= -1;
562 static int hf_dcerpc_dg_fack_max_tsdu
= -1;
563 static int hf_dcerpc_dg_fack_max_frag_size
= -1;
564 static int hf_dcerpc_dg_fack_serial_num
= -1;
565 static int hf_dcerpc_dg_fack_selack_len
= -1;
566 static int hf_dcerpc_dg_fack_selack
= -1;
567 static int hf_dcerpc_dg_status
= -1;
568 static int hf_dcerpc_array_max_count
= -1;
569 static int hf_dcerpc_array_offset
= -1;
570 static int hf_dcerpc_array_actual_count
= -1;
571 static int hf_dcerpc_array_buffer
= -1;
572 static int hf_dcerpc_op
= -1;
573 static int hf_dcerpc_referent_id
= -1;
574 static int hf_dcerpc_fragments
= -1;
575 static int hf_dcerpc_fragment
= -1;
576 static int hf_dcerpc_fragment_overlap
= -1;
577 static int hf_dcerpc_fragment_overlap_conflict
= -1;
578 static int hf_dcerpc_fragment_multiple_tails
= -1;
579 static int hf_dcerpc_fragment_too_long_fragment
= -1;
580 static int hf_dcerpc_fragment_error
= -1;
581 static int hf_dcerpc_fragment_count
= -1;
582 static int hf_dcerpc_reassembled_in
= -1;
583 static int hf_dcerpc_reassembled_length
= -1;
584 static int hf_dcerpc_unknown_if_id
= -1;
586 static gint ett_dcerpc
= -1;
587 static gint ett_dcerpc_cn_flags
= -1;
588 static gint ett_dcerpc_cn_ctx
= -1;
589 static gint ett_dcerpc_cn_iface
= -1;
590 static gint ett_dcerpc_cn_trans_syntax
= -1;
591 static gint ett_dcerpc_cn_trans_btfn
= -1;
592 static gint ett_dcerpc_cn_rts_flags
= -1;
593 static gint ett_dcerpc_cn_rts_command
= -1;
594 static gint ett_dcerpc_cn_rts_pdu
= -1;
595 static gint ett_dcerpc_drep
= -1;
596 static gint ett_dcerpc_dg_flags1
= -1;
597 static gint ett_dcerpc_dg_flags2
= -1;
598 static gint ett_dcerpc_pointer_data
= -1;
599 static gint ett_dcerpc_string
= -1;
600 static gint ett_dcerpc_fragments
= -1;
601 static gint ett_dcerpc_fragment
= -1;
602 static gint ett_dcerpc_krb5_auth_verf
= -1;
604 static expert_field ei_dcerpc_fragment_multiple
= EI_INIT
;
605 static expert_field ei_dcerpc_cn_status
= EI_INIT
;
606 static expert_field ei_dcerpc_fragment_reassembled
= EI_INIT
;
607 static expert_field ei_dcerpc_fragment
= EI_INIT
;
608 static expert_field ei_dcerpc_no_request_found
= EI_INIT
;
609 static expert_field ei_dcerpc_context_change
= EI_INIT
;
610 static expert_field ei_dcerpc_cn_ctx_id_no_bind
= EI_INIT
;
611 static expert_field ei_dcerpc_bind_not_acknowledged
= EI_INIT
;
613 static const fragment_items dcerpc_frag_items
= {
614 &ett_dcerpc_fragments
,
615 &ett_dcerpc_fragment
,
617 &hf_dcerpc_fragments
,
619 &hf_dcerpc_fragment_overlap
,
620 &hf_dcerpc_fragment_overlap_conflict
,
621 &hf_dcerpc_fragment_multiple_tails
,
622 &hf_dcerpc_fragment_too_long_fragment
,
623 &hf_dcerpc_fragment_error
,
624 &hf_dcerpc_fragment_count
,
626 &hf_dcerpc_reassembled_length
,
627 /* Reassembled data field */
632 /* list of hooks to be called when init_protocols is done */
633 GHookList dcerpc_hooks_init_protos
;
638 static dcerpc_info di
[20];
639 static int di_counter
= 0;
642 if (di_counter
>= 20) {
646 memset(&di
[di_counter
], 0, sizeof(dcerpc_info
));
648 return &di
[di_counter
];
651 /* try to desegment big DCE/RPC packets over TCP? */
652 static gboolean dcerpc_cn_desegment
= TRUE
;
654 /* reassemble DCE/RPC fragments */
655 /* reassembly of cl dcerpc fragments will not work for the case where ONE frame
656 might contain multiple dcerpc fragments for different PDUs.
657 this case would be so unusual/weird so if you got captures like that:
660 reassembly of co dcerpc fragments will not work for the case where TCP/SMB frames
661 are coming in out of sequence, but that will hurt in a lot of other places as well.
663 static gboolean dcerpc_reassemble
= TRUE
;
664 static reassembly_table dcerpc_co_reassembly_table
;
665 static reassembly_table dcerpc_cl_reassembly_table
;
667 typedef struct _dcerpc_fragment_key
{
672 } dcerpc_fragment_key
;
675 dcerpc_fragment_hash(gconstpointer k
)
677 const dcerpc_fragment_key
* key
= (const dcerpc_fragment_key
*) k
;
683 hash_val
+= key
->act_id
.Data1
;
684 hash_val
+= key
->act_id
.Data2
<< 16;
685 hash_val
+= key
->act_id
.Data3
;
691 dcerpc_fragment_equal(gconstpointer k1
, gconstpointer k2
)
693 const dcerpc_fragment_key
* key1
= (const dcerpc_fragment_key
*) k1
;
694 const dcerpc_fragment_key
* key2
= (const dcerpc_fragment_key
*) k2
;
696 /*key.id is the first item to compare since item is most
697 likely to differ between sessions, thus shortcircuiting
698 the comparison of addresses.
700 return (((key1
->id
== key2
->id
)
701 && (ADDRESSES_EQUAL(&key1
->src
, &key2
->src
))
702 && (ADDRESSES_EQUAL(&key1
->dst
, &key2
->dst
))
703 && (memcmp (&key1
->act_id
, &key2
->act_id
, sizeof (e_uuid_t
)) == 0))
707 /* allocate a persistent dcerpc fragment key to insert in the hash */
709 dcerpc_fragment_temporary_key(const packet_info
*pinfo
, const guint32 id
,
712 dcerpc_fragment_key
*key
= g_slice_new(dcerpc_fragment_key
);
713 e_dce_dg_common_hdr_t
*hdr
= (e_dce_dg_common_hdr_t
*)data
;
715 key
->src
= pinfo
->src
;
716 key
->dst
= pinfo
->dst
;
718 key
->act_id
= hdr
->act_id
;
723 /* allocate a persistent dcerpc fragment key to insert in the hash */
725 dcerpc_fragment_persistent_key(const packet_info
*pinfo
, const guint32 id
,
728 dcerpc_fragment_key
*key
= g_slice_new(dcerpc_fragment_key
);
729 e_dce_dg_common_hdr_t
*hdr
= (e_dce_dg_common_hdr_t
*)data
;
731 COPY_ADDRESS(&key
->src
, &pinfo
->src
);
732 COPY_ADDRESS(&key
->dst
, &pinfo
->dst
);
734 key
->act_id
= hdr
->act_id
;
740 dcerpc_fragment_free_temporary_key(gpointer ptr
)
742 dcerpc_fragment_key
*key
= (dcerpc_fragment_key
*)ptr
;
745 g_slice_free(dcerpc_fragment_key
, key
);
749 dcerpc_fragment_free_persistent_key(gpointer ptr
)
751 dcerpc_fragment_key
*key
= (dcerpc_fragment_key
*)ptr
;
755 * Free up the copies of the addresses from the old key.
757 g_free((gpointer
)key
->src
.data
);
758 g_free((gpointer
)key
->dst
.data
);
760 g_slice_free(dcerpc_fragment_key
, key
);
764 static const reassembly_table_functions dcerpc_cl_reassembly_table_functions
= {
765 dcerpc_fragment_hash
,
766 dcerpc_fragment_equal
,
767 dcerpc_fragment_temporary_key
,
768 dcerpc_fragment_persistent_key
,
769 dcerpc_fragment_free_temporary_key
,
770 dcerpc_fragment_free_persistent_key
774 dcerpc_reassemble_init(void)
777 * XXX - addresses_ports_reassembly_table_functions?
778 * Or can a single connection-oriented DCE RPC session persist
779 * over multiple transport layer connections?
781 reassembly_table_init(&dcerpc_co_reassembly_table
,
782 &addresses_reassembly_table_functions
);
783 reassembly_table_init(&dcerpc_cl_reassembly_table
,
784 &dcerpc_cl_reassembly_table_functions
);
788 * Authentication subdissectors. Used to dissect authentication blobs in
789 * DCERPC binds, requests and responses.
792 typedef struct _dcerpc_auth_subdissector
{
795 dcerpc_auth_subdissector_fns auth_fns
;
796 } dcerpc_auth_subdissector
;
798 static GSList
*dcerpc_auth_subdissector_list
;
800 static dcerpc_auth_subdissector_fns
*get_auth_subdissector_fns(
801 guint8 auth_level
, guint8 auth_type
)
806 for (i
= 0; (data
= g_slist_nth_data(dcerpc_auth_subdissector_list
, i
)); i
++) {
807 dcerpc_auth_subdissector
*asd
= (dcerpc_auth_subdissector
*)data
;
809 if ((asd
->auth_level
== auth_level
) &&
810 (asd
->auth_type
== auth_type
))
811 return &asd
->auth_fns
;
817 void register_dcerpc_auth_subdissector(guint8 auth_level
, guint8 auth_type
,
818 dcerpc_auth_subdissector_fns
*fns
)
820 dcerpc_auth_subdissector
*d
;
822 if (get_auth_subdissector_fns(auth_level
, auth_type
))
825 d
= (dcerpc_auth_subdissector
*)g_malloc(sizeof(dcerpc_auth_subdissector
));
827 d
->auth_level
= auth_level
;
828 d
->auth_type
= auth_type
;
829 memcpy(&d
->auth_fns
, fns
, sizeof(dcerpc_auth_subdissector_fns
));
831 dcerpc_auth_subdissector_list
= g_slist_append(dcerpc_auth_subdissector_list
, d
);
834 /* Hand off verifier data to a registered dissector */
836 static void dissect_auth_verf(tvbuff_t
*auth_tvb
, packet_info
*pinfo
,
838 dcerpc_auth_subdissector_fns
*auth_fns
,
839 e_dce_cn_common_hdr_t
*hdr
,
840 dcerpc_auth_info
*auth_info
)
842 dcerpc_dissect_fnct_t
*volatile fn
= NULL
;
843 /* XXX - "stub" a fake DCERPC INFO STRUCTURE
844 If a dcerpc_info is really needed, update
845 the call stacks to include it
847 FAKE_DCERPC_INFO_STRUCTURE
849 switch (hdr
->ptype
) {
852 fn
= auth_fns
->bind_fn
;
856 fn
= auth_fns
->bind_ack_fn
;
859 fn
= auth_fns
->auth3_fn
;
862 fn
= auth_fns
->req_verf_fn
;
865 fn
= auth_fns
->resp_verf_fn
;
868 /* Don't know how to handle authentication data in this
872 g_warning("attempt to dissect %s pdu authentication data",
873 val_to_str(hdr
->ptype
, pckt_vals
, "Unknown (%u)"));
878 fn(auth_tvb
, 0, pinfo
, tree
, &di
, hdr
->drep
);
880 tvb_ensure_bytes_exist(auth_tvb
, 0, hdr
->auth_len
);
881 proto_tree_add_text(tree
, auth_tvb
, 0, hdr
->auth_len
,
883 val_to_str(auth_info
->auth_type
,
889 /* Hand off payload data to a registered dissector */
891 static tvbuff_t
*decode_encrypted_data(tvbuff_t
*data_tvb
,
894 dcerpc_auth_subdissector_fns
*auth_fns
,
896 dcerpc_auth_info
*auth_info
)
898 dcerpc_decode_data_fnct_t
*fn
;
901 fn
= auth_fns
->req_data_fn
;
903 fn
= auth_fns
->resp_data_fn
;
906 return fn(data_tvb
, auth_tvb
, 0, pinfo
, auth_info
);
915 /* the registered subdissectors */
916 GHashTable
*dcerpc_uuids
= NULL
;
919 dcerpc_uuid_equal(gconstpointer k1
, gconstpointer k2
)
921 const dcerpc_uuid_key
*key1
= (const dcerpc_uuid_key
*)k1
;
922 const dcerpc_uuid_key
*key2
= (const dcerpc_uuid_key
*)k2
;
923 return ((memcmp(&key1
->uuid
, &key2
->uuid
, sizeof (e_uuid_t
)) == 0)
924 && (key1
->ver
== key2
->ver
));
928 dcerpc_uuid_hash(gconstpointer k
)
930 const dcerpc_uuid_key
*key
= (const dcerpc_uuid_key
*)k
;
931 /* This isn't perfect, but the Data1 part of these is almost always
933 return key
->uuid
.Data1
;
937 dcerpc_init_uuid(int proto
, int ett
, e_uuid_t
*uuid
, guint16 ver
,
938 dcerpc_sub_dissector
*procs
, int opnum_hf
)
940 dcerpc_uuid_key
*key
= (dcerpc_uuid_key
*)g_malloc(sizeof (*key
));
941 dcerpc_uuid_value
*value
= (dcerpc_uuid_value
*)g_malloc(sizeof (*value
));
942 header_field_info
*hf_info
;
943 module_t
*samr_module
;
944 const char *filter_name
= proto_get_protocol_filter_name(proto
);
949 value
->proto
= find_protocol_by_id(proto
);
950 value
->proto_id
= proto
;
952 value
->name
= proto_get_protocol_short_name(value
->proto
);
953 value
->procs
= procs
;
954 value
->opnum_hf
= opnum_hf
;
956 g_hash_table_insert(dcerpc_uuids
, key
, value
);
958 hf_info
= proto_registrar_get_nth(opnum_hf
);
959 hf_info
->strings
= value_string_from_subdissectors(procs
);
961 /* add this GUID to the global name resolving */
962 guids_add_uuid(uuid
, proto_get_protocol_short_name(value
->proto
));
964 /* Register the samr.nt_password preference as obsolete */
965 /* This should be in packet-dcerpc-samr.c */
966 if (strcmp(filter_name
, "samr") == 0) {
967 samr_module
= prefs_register_protocol(proto
, NULL
);
968 prefs_register_obsolete_preference(samr_module
, "nt_password");
972 /* Function to find the name of a registered protocol
973 * or NULL if the protocol/version is not known to wireshark.
976 dcerpc_get_proto_name(e_uuid_t
*uuid
, guint16 ver
)
979 dcerpc_uuid_value
*sub_proto
;
983 if (!(sub_proto
= (dcerpc_uuid_value
*)g_hash_table_lookup(dcerpc_uuids
, &key
))) {
986 return sub_proto
->name
;
989 /* Function to find the opnum hf-field of a registered protocol
990 * or -1 if the protocol/version is not known to wireshark.
993 dcerpc_get_proto_hf_opnum(e_uuid_t
*uuid
, guint16 ver
)
996 dcerpc_uuid_value
*sub_proto
;
1000 if (!(sub_proto
= (dcerpc_uuid_value
*)g_hash_table_lookup(dcerpc_uuids
, &key
))) {
1003 return sub_proto
->opnum_hf
;
1006 /* Create a value_string consisting of DCERPC opnum and name from a
1007 subdissector array. */
1009 value_string
*value_string_from_subdissectors(dcerpc_sub_dissector
*sd
)
1011 value_string
*vs
= NULL
;
1016 for (i
= 0; sd
[i
].name
; i
++) {
1018 vs
[i
].value
= sd
[i
].num
;
1019 vs
[i
].strptr
= sd
[i
].name
;
1025 vs
= (value_string
*)wmem_alloc(wmem_epan_scope(), (num_sd
+ 1) * sizeof(value_string
));
1029 vs
[num_sd
].value
= 0;
1030 vs
[num_sd
].strptr
= NULL
;
1035 /* Function to find the subdissector table of a registered protocol
1036 * or NULL if the protocol/version is not known to wireshark.
1038 dcerpc_sub_dissector
*
1039 dcerpc_get_proto_sub_dissector(e_uuid_t
*uuid
, guint16 ver
)
1041 dcerpc_uuid_key key
;
1042 dcerpc_uuid_value
*sub_proto
;
1046 if (!(sub_proto
= (dcerpc_uuid_value
*)g_hash_table_lookup(dcerpc_uuids
, &key
))) {
1049 return sub_proto
->procs
;
1054 * To keep track of ctx_id mappings.
1056 * Every time we see a bind call we update this table.
1057 * Note that we always specify a SMB FID. For non-SMB transports this
1060 static GHashTable
*dcerpc_binds
= NULL
;
1062 typedef struct _dcerpc_bind_key
{
1063 conversation_t
*conv
;
1068 typedef struct _dcerpc_bind_value
{
1072 } dcerpc_bind_value
;
1075 dcerpc_bind_equal(gconstpointer k1
, gconstpointer k2
)
1077 const dcerpc_bind_key
*key1
= (const dcerpc_bind_key
*)k1
;
1078 const dcerpc_bind_key
*key2
= (const dcerpc_bind_key
*)k2
;
1079 return ((key1
->conv
== key2
->conv
)
1080 && (key1
->ctx_id
== key2
->ctx_id
)
1081 && (key1
->smb_fid
== key2
->smb_fid
));
1085 dcerpc_bind_hash(gconstpointer k
)
1087 const dcerpc_bind_key
*key
= (const dcerpc_bind_key
*)k
;
1090 hash
= GPOINTER_TO_UINT(key
->conv
) + key
->ctx_id
+ key
->smb_fid
;
1096 * To keep track of callid mappings. Should really use some generic
1097 * conversation support instead.
1099 static GHashTable
*dcerpc_cn_calls
= NULL
;
1100 static GHashTable
*dcerpc_dg_calls
= NULL
;
1102 typedef struct _dcerpc_cn_call_key
{
1103 conversation_t
*conv
;
1106 } dcerpc_cn_call_key
;
1108 typedef struct _dcerpc_dg_call_key
{
1109 conversation_t
*conv
;
1112 } dcerpc_dg_call_key
;
1116 dcerpc_cn_call_equal(gconstpointer k1
, gconstpointer k2
)
1118 const dcerpc_cn_call_key
*key1
= (const dcerpc_cn_call_key
*)k1
;
1119 const dcerpc_cn_call_key
*key2
= (const dcerpc_cn_call_key
*)k2
;
1120 return ((key1
->conv
== key2
->conv
)
1121 && (key1
->call_id
== key2
->call_id
)
1122 && (key1
->smb_fid
== key2
->smb_fid
));
1126 dcerpc_dg_call_equal(gconstpointer k1
, gconstpointer k2
)
1128 const dcerpc_dg_call_key
*key1
= (const dcerpc_dg_call_key
*)k1
;
1129 const dcerpc_dg_call_key
*key2
= (const dcerpc_dg_call_key
*)k2
;
1130 return ((key1
->conv
== key2
->conv
)
1131 && (key1
->seqnum
== key2
->seqnum
)
1132 && ((memcmp(&key1
->act_id
, &key2
->act_id
, sizeof (e_uuid_t
)) == 0)));
1136 dcerpc_cn_call_hash(gconstpointer k
)
1138 const dcerpc_cn_call_key
*key
= (const dcerpc_cn_call_key
*)k
;
1139 return GPOINTER_TO_UINT(key
->conv
) + key
->call_id
+ key
->smb_fid
;
1143 dcerpc_dg_call_hash(gconstpointer k
)
1145 const dcerpc_dg_call_key
*key
= (const dcerpc_dg_call_key
*)k
;
1146 return (GPOINTER_TO_UINT(key
->conv
) + key
->seqnum
+ key
->act_id
.Data1
1147 + (key
->act_id
.Data2
<< 16) + key
->act_id
.Data3
1148 + (key
->act_id
.Data4
[0] << 24) + (key
->act_id
.Data4
[1] << 16)
1149 + (key
->act_id
.Data4
[2] << 8) + (key
->act_id
.Data4
[3] << 0)
1150 + (key
->act_id
.Data4
[4] << 24) + (key
->act_id
.Data4
[5] << 16)
1151 + (key
->act_id
.Data4
[6] << 8) + (key
->act_id
.Data4
[7] << 0));
1154 /* to keep track of matched calls/responses
1155 this one uses the same value struct as calls, but the key is the frame id
1156 and call id; there can be more than one call in a frame.
1158 XXX - why not just use the same keys as are used for calls?
1161 static GHashTable
*dcerpc_matched
= NULL
;
1163 typedef struct _dcerpc_matched_key
{
1166 } dcerpc_matched_key
;
1169 dcerpc_matched_equal(gconstpointer k1
, gconstpointer k2
)
1171 const dcerpc_matched_key
*key1
= (const dcerpc_matched_key
*)k1
;
1172 const dcerpc_matched_key
*key2
= (const dcerpc_matched_key
*)k2
;
1173 return ((key1
->frame
== key2
->frame
)
1174 && (key1
->call_id
== key2
->call_id
));
1178 dcerpc_matched_hash(gconstpointer k
)
1180 const dcerpc_matched_key
*key
= (const dcerpc_matched_key
*)k
;
1187 * Utility functions. Modeled after packet-rpc.c
1191 dissect_dcerpc_uint8(tvbuff_t
*tvb
, gint offset
, packet_info
*pinfo _U_
,
1192 proto_tree
*tree
, guint8
*drep
,
1193 int hfindex
, guint8
*pdata
)
1197 data
= tvb_get_guint8(tvb
, offset
);
1199 proto_tree_add_item(tree
, hfindex
, tvb
, offset
, 1, DREP_ENC_INTEGER(drep
));
1207 dissect_dcerpc_uint16(tvbuff_t
*tvb
, gint offset
, packet_info
*pinfo _U_
,
1208 proto_tree
*tree
, guint8
*drep
,
1209 int hfindex
, guint16
*pdata
)
1213 data
= ((drep
[0] & DREP_LITTLE_ENDIAN
)
1214 ? tvb_get_letohs(tvb
, offset
)
1215 : tvb_get_ntohs(tvb
, offset
));
1218 proto_tree_add_item(tree
, hfindex
, tvb
, offset
, 2, DREP_ENC_INTEGER(drep
));
1226 dissect_dcerpc_uint32(tvbuff_t
*tvb
, gint offset
, packet_info
*pinfo _U_
,
1227 proto_tree
*tree
, guint8
*drep
,
1228 int hfindex
, guint32
*pdata
)
1232 data
= ((drep
[0] & DREP_LITTLE_ENDIAN
)
1233 ? tvb_get_letohl(tvb
, offset
)
1234 : tvb_get_ntohl(tvb
, offset
));
1237 proto_tree_add_item(tree
, hfindex
, tvb
, offset
, 4, DREP_ENC_INTEGER(drep
));
1244 /* handles 32 bit unix time_t */
1246 dissect_dcerpc_time_t(tvbuff_t
*tvb
, gint offset
, packet_info
*pinfo _U_
,
1247 proto_tree
*tree
, guint8
*drep
,
1248 int hfindex
, guint32
*pdata
)
1253 data
= ((drep
[0] & DREP_LITTLE_ENDIAN
)
1254 ? tvb_get_letohl(tvb
, offset
)
1255 : tvb_get_ntohl(tvb
, offset
));
1260 if (data
== 0xffffffff) {
1261 /* special case, no time specified */
1262 proto_tree_add_time_format_value(tree
, hfindex
, tvb
, offset
, 4, &tv
, "No time specified");
1264 proto_tree_add_time(tree
, hfindex
, tvb
, offset
, 4, &tv
);
1274 dissect_dcerpc_uint64(tvbuff_t
*tvb
, gint offset
, packet_info
*pinfo _U_
,
1275 proto_tree
*tree
, guint8
*drep
,
1276 int hfindex
, guint64
*pdata
)
1280 data
= ((drep
[0] & DREP_LITTLE_ENDIAN
)
1281 ? tvb_get_letoh64(tvb
, offset
)
1282 : tvb_get_ntoh64(tvb
, offset
));
1285 header_field_info
*hfinfo
;
1287 /* This might be a field that is either 32bit, in NDR or
1288 64 bits in NDR64. So we must be careful and call the right
1291 hfinfo
= proto_registrar_get_nth(hfindex
);
1293 switch (hfinfo
->type
) {
1295 proto_tree_add_uint64(tree
, hfindex
, tvb
, offset
, 8, data
);
1298 proto_tree_add_int64(tree
, hfindex
, tvb
, offset
, 8, data
);
1301 DISSECTOR_ASSERT(data
<= G_MAXUINT32
);
1302 proto_tree_add_uint(tree
, hfindex
, tvb
, offset
, 8, (guint32
)data
);
1312 dissect_dcerpc_float(tvbuff_t
*tvb
, gint offset
, packet_info
*pinfo _U_
,
1313 proto_tree
*tree
, guint8
*drep
,
1314 int hfindex
, gfloat
*pdata
)
1320 case(DCE_RPC_DREP_FP_IEEE
):
1321 data
= ((drep
[0] & DREP_LITTLE_ENDIAN
)
1322 ? tvb_get_letohieee_float(tvb
, offset
)
1323 : tvb_get_ntohieee_float(tvb
, offset
));
1325 proto_tree_add_float(tree
, hfindex
, tvb
, offset
, 4, data
);
1328 case(DCE_RPC_DREP_FP_VAX
): /* (fall trough) */
1329 case(DCE_RPC_DREP_FP_CRAY
): /* (fall trough) */
1330 case(DCE_RPC_DREP_FP_IBM
): /* (fall trough) */
1332 /* ToBeDone: non IEEE floating formats */
1333 /* Set data to a negative infinity value */
1336 proto_tree_add_debug_text(tree
, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep
[1]);
1346 dissect_dcerpc_double(tvbuff_t
*tvb
, gint offset
, packet_info
*pinfo _U_
,
1347 proto_tree
*tree
, guint8
*drep
,
1348 int hfindex
, gdouble
*pdata
)
1354 case(DCE_RPC_DREP_FP_IEEE
):
1355 data
= ((drep
[0] & DREP_LITTLE_ENDIAN
)
1356 ? tvb_get_letohieee_double(tvb
, offset
)
1357 : tvb_get_ntohieee_double(tvb
, offset
));
1359 proto_tree_add_double(tree
, hfindex
, tvb
, offset
, 8, data
);
1362 case(DCE_RPC_DREP_FP_VAX
): /* (fall trough) */
1363 case(DCE_RPC_DREP_FP_CRAY
): /* (fall trough) */
1364 case(DCE_RPC_DREP_FP_IBM
): /* (fall trough) */
1366 /* ToBeDone: non IEEE double formats */
1367 /* Set data to a negative infinity value */
1368 data
= -G_MAXDOUBLE
;
1370 proto_tree_add_debug_text(tree
, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep
[1]);
1380 dissect_dcerpc_uuid_t(tvbuff_t
*tvb
, gint offset
, packet_info
*pinfo _U_
,
1381 proto_tree
*tree
, guint8
*drep
,
1382 int hfindex
, e_uuid_t
*pdata
)
1387 if (drep
[0] & DREP_LITTLE_ENDIAN
) {
1388 tvb_get_letohguid(tvb
, offset
, (e_guid_t
*) &uuid
);
1390 tvb_get_ntohguid(tvb
, offset
, (e_guid_t
*) &uuid
);
1393 proto_tree_add_guid(tree
, hfindex
, tvb
, offset
, 16, (e_guid_t
*) &uuid
);
1403 * a couple simpler things
1406 dcerpc_tvb_get_ntohs(tvbuff_t
*tvb
, gint offset
, guint8
*drep
)
1408 if (drep
[0] & DREP_LITTLE_ENDIAN
) {
1409 return tvb_get_letohs(tvb
, offset
);
1411 return tvb_get_ntohs(tvb
, offset
);
1416 dcerpc_tvb_get_ntohl(tvbuff_t
*tvb
, gint offset
, guint8
*drep
)
1418 if (drep
[0] & DREP_LITTLE_ENDIAN
) {
1419 return tvb_get_letohl(tvb
, offset
);
1421 return tvb_get_ntohl(tvb
, offset
);
1426 dcerpc_tvb_get_uuid(tvbuff_t
*tvb
, gint offset
, guint8
*drep
, e_uuid_t
*uuid
)
1428 if (drep
[0] & DREP_LITTLE_ENDIAN
) {
1429 tvb_get_letohguid(tvb
, offset
, (e_guid_t
*) uuid
);
1431 tvb_get_ntohguid(tvb
, offset
, (e_guid_t
*) uuid
);
1437 /* function to dissect a unidimensional conformant array */
1439 dissect_ndr_ucarray(tvbuff_t
*tvb
, gint offset
, packet_info
*pinfo
,
1440 proto_tree
*tree
, dcerpc_info
*di
, guint8
*drep
,
1441 dcerpc_dissect_fnct_t
*fnct
)
1445 int conformance_size
= 4;
1447 if (di
->call_data
->flags
& DCERPC_IS_NDR64
) {
1448 conformance_size
= 8;
1451 if (di
->conformant_run
) {
1454 /* conformant run, just dissect the max_count header */
1455 old_offset
= offset
;
1456 di
->conformant_run
= 0;
1457 offset
= dissect_ndr_uint3264(tvb
, offset
, pinfo
, tree
, di
, drep
,
1458 hf_dcerpc_array_max_count
, &val
);
1459 di
->array_max_count
= (gint32
)val
;
1460 di
->array_max_count_offset
= offset
-conformance_size
;
1461 di
->conformant_run
= 1;
1462 di
->conformant_eaten
= offset
-old_offset
;
1464 /* we don't remember where in the bytestream this field was */
1465 proto_tree_add_uint(tree
, hf_dcerpc_array_max_count
, tvb
, di
->array_max_count_offset
, conformance_size
, di
->array_max_count
);
1467 /* real run, dissect the elements */
1468 for(i
=0; i
<di
->array_max_count
; i
++) {
1469 offset
= (*fnct
)(tvb
, offset
, pinfo
, tree
, di
, drep
);
1476 /* function to dissect a unidimensional conformant and varying array
1477 * depending on the dissection function passed as a parameter,
1478 * content of the array will be dissected as a block or byte by byte
1481 dissect_ndr_ucvarray_core(tvbuff_t
*tvb
, gint offset
, packet_info
*pinfo
,
1482 proto_tree
*tree
, dcerpc_info
*di
, guint8
*drep
,
1483 dcerpc_dissect_fnct_t
*fnct_bytes
,
1484 dcerpc_dissect_fnct_blk_t
*fnct_block
)
1488 int conformance_size
= 4;
1490 if (di
->call_data
->flags
& DCERPC_IS_NDR64
) {
1491 conformance_size
= 8;
1494 if (di
->conformant_run
) {
1497 /* conformant run, just dissect the max_count header */
1498 old_offset
= offset
;
1499 di
->conformant_run
= 0;
1500 offset
= dissect_ndr_uint3264(tvb
, offset
, pinfo
, tree
, di
, drep
,
1501 hf_dcerpc_array_max_count
, &val
);
1502 DISSECTOR_ASSERT(val
<= G_MAXUINT32
);
1503 di
->array_max_count
= (guint32
)val
;
1504 di
->array_max_count_offset
= offset
-conformance_size
;
1505 offset
= dissect_ndr_uint3264(tvb
, offset
, pinfo
, tree
, di
, drep
,
1506 hf_dcerpc_array_offset
, &val
);
1507 DISSECTOR_ASSERT(val
<= G_MAXUINT32
);
1508 di
->array_offset
= (guint32
)val
;
1509 di
->array_offset_offset
= offset
-conformance_size
;
1510 offset
= dissect_ndr_uint3264(tvb
, offset
, pinfo
, tree
, di
, drep
,
1511 hf_dcerpc_array_actual_count
, &val
);
1512 DISSECTOR_ASSERT(val
<= G_MAXUINT32
);
1513 di
->array_actual_count
= (guint32
)val
;
1514 di
->array_actual_count_offset
= offset
-conformance_size
;
1515 di
->conformant_run
= 1;
1516 di
->conformant_eaten
= offset
-old_offset
;
1518 /* we don't remember where in the bytestream these fields were */
1519 proto_tree_add_uint(tree
, hf_dcerpc_array_max_count
, tvb
, di
->array_max_count_offset
, conformance_size
, di
->array_max_count
);
1520 proto_tree_add_uint(tree
, hf_dcerpc_array_offset
, tvb
, di
->array_offset_offset
, conformance_size
, di
->array_offset
);
1521 proto_tree_add_uint(tree
, hf_dcerpc_array_actual_count
, tvb
, di
->array_actual_count_offset
, conformance_size
, di
->array_actual_count
);
1523 /* real run, dissect the elements */
1525 offset
= (*fnct_block
)(tvb
, offset
, di
->array_actual_count
, pinfo
, tree
, drep
);
1527 for(i
=0 ;i
<di
->array_actual_count
; i
++) {
1528 old_offset
= offset
;
1529 offset
= (*fnct_bytes
)(tvb
, offset
, pinfo
, tree
, di
, drep
);
1530 if (offset
<= old_offset
)
1531 THROW(ReportedBoundsError
);
1540 dissect_ndr_ucvarray_block(tvbuff_t
*tvb
, gint offset
, packet_info
*pinfo
,
1541 proto_tree
*tree
, dcerpc_info
*di
, guint8
*drep
,
1542 dcerpc_dissect_fnct_blk_t
*fnct
)
1544 return dissect_ndr_ucvarray_core(tvb
, offset
, pinfo
, tree
, di
, drep
, NULL
, fnct
);
1548 dissect_ndr_ucvarray(tvbuff_t
*tvb
, gint offset
, packet_info
*pinfo
,
1549 proto_tree
*tree
, dcerpc_info
*di
, guint8
*drep
,
1550 dcerpc_dissect_fnct_t
*fnct
)
1552 return dissect_ndr_ucvarray_core(tvb
, offset
, pinfo
, tree
, di
, drep
, fnct
, NULL
);
1554 /* function to dissect a unidimensional varying array */
1556 dissect_ndr_uvarray(tvbuff_t
*tvb
, gint offset
, packet_info
*pinfo
,
1557 proto_tree
*tree
, dcerpc_info
*di
, guint8
*drep
,
1558 dcerpc_dissect_fnct_t
*fnct
)
1562 int conformance_size
= 4;
1564 if (di
->call_data
->flags
& DCERPC_IS_NDR64
) {
1565 conformance_size
= 8;
1568 if (di
->conformant_run
) {
1571 /* conformant run, just dissect the max_count header */
1572 old_offset
= offset
;
1573 di
->conformant_run
= 0;
1574 offset
= dissect_ndr_uint3264(tvb
, offset
, pinfo
, tree
, di
, drep
,
1575 hf_dcerpc_array_offset
, &val
);
1576 DISSECTOR_ASSERT(val
<= G_MAXUINT32
);
1577 di
->array_offset
= (guint32
)val
;
1578 di
->array_offset_offset
= offset
-conformance_size
;
1579 offset
= dissect_ndr_uint3264(tvb
, offset
, pinfo
, tree
, di
, drep
,
1580 hf_dcerpc_array_actual_count
, &val
);
1581 DISSECTOR_ASSERT(val
<= G_MAXUINT32
);
1582 di
->array_actual_count
= (guint32
)val
;
1583 di
->array_actual_count_offset
= offset
-conformance_size
;
1584 di
->conformant_run
= 1;
1585 di
->conformant_eaten
= offset
-old_offset
;
1587 /* we don't remember where in the bytestream these fields were */
1588 proto_tree_add_uint(tree
, hf_dcerpc_array_offset
, tvb
, di
->array_offset_offset
, conformance_size
, di
->array_offset
);
1589 proto_tree_add_uint(tree
, hf_dcerpc_array_actual_count
, tvb
, di
->array_actual_count_offset
, conformance_size
, di
->array_actual_count
);
1591 /* real run, dissect the elements */
1592 for(i
=0; i
<di
->array_actual_count
; i
++) {
1593 offset
= (*fnct
)(tvb
, offset
, pinfo
, tree
, di
, drep
);
1600 /* Dissect an string of bytes. This corresponds to
1601 IDL of the form '[string] byte *foo'.
1603 It can also be used for a conformant varying array of bytes if
1604 the contents of the array should be shown as a big blob, rather
1605 than showing each byte as an individual element.
1607 XXX - which of those is really the IDL type for, for example,
1608 the encrypted data in some MAPI packets? (Microsoft hasn't
1611 XXX - does this need to do all the conformant array stuff that
1612 "dissect_ndr_ucvarray()" does? These are presumably for strings
1613 that are conformant and varying - they're stored like conformant
1614 varying arrays of bytes. */
1616 dissect_ndr_byte_array(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
1617 proto_tree
*tree
, dcerpc_info
*di
, guint8
*drep
)
1621 if (di
->conformant_run
) {
1622 /* just a run to handle conformant arrays, no scalars to dissect */
1626 /* NDR array header */
1628 offset
= dissect_ndr_uint3264(tvb
, offset
, pinfo
, tree
, di
, drep
,
1629 hf_dcerpc_array_max_count
, NULL
);
1631 offset
= dissect_ndr_uint3264(tvb
, offset
, pinfo
, tree
, di
, drep
,
1632 hf_dcerpc_array_offset
, NULL
);
1634 offset
= dissect_ndr_uint3264(tvb
, offset
, pinfo
, tree
, di
, drep
,
1635 hf_dcerpc_array_actual_count
, &len
);
1637 DISSECTOR_ASSERT(len
<= G_MAXUINT32
);
1639 tvb_ensure_bytes_exist(tvb
, offset
, (guint32
)len
);
1640 proto_tree_add_item(tree
, hf_dcerpc_array_buffer
,
1641 tvb
, offset
, (guint32
)len
, ENC_NA
);
1644 offset
+= (guint32
)len
;
1649 /* For dissecting arrays that are to be interpreted as strings. */
1651 /* Dissect an NDR conformant varying string of elements.
1652 The length of each element is given by the 'size_is' parameter;
1653 the elements are assumed to be characters or wide characters.
1655 XXX - does this need to do all the conformant array stuff that
1656 "dissect_ndr_ucvarray()" does? */
1658 dissect_ndr_cvstring(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
1659 proto_tree
*tree
, dcerpc_info
*di
, guint8
*drep
, int size_is
,
1660 int hfindex
, gboolean add_subtree
, char **data
)
1662 proto_item
*string_item
;
1663 proto_tree
*string_tree
;
1667 header_field_info
*hfinfo
;
1669 if (di
->conformant_run
) {
1670 /* just a run to handle conformant arrays, no scalars to dissect */
1675 string_item
= proto_tree_add_text(tree
, tvb
, offset
, -1, "%s",
1676 proto_registrar_get_name(hfindex
));
1677 string_tree
= proto_item_add_subtree(string_item
, ett_dcerpc_string
);
1683 /* NDR array header */
1685 offset
= dissect_ndr_uint3264(tvb
, offset
, pinfo
, string_tree
, di
, drep
,
1686 hf_dcerpc_array_max_count
, NULL
);
1688 offset
= dissect_ndr_uint3264(tvb
, offset
, pinfo
, string_tree
, di
, drep
,
1689 hf_dcerpc_array_offset
, NULL
);
1691 offset
= dissect_ndr_uint3264(tvb
, offset
, pinfo
, string_tree
, di
, drep
,
1692 hf_dcerpc_array_actual_count
, &len
);
1694 DISSECTOR_ASSERT(len
<= G_MAXUINT32
);
1695 buffer_len
= size_is
* (guint32
)len
;
1698 if (!di
->no_align
&& (offset
% size_is
))
1699 offset
+= size_is
- (offset
% size_is
);
1701 if (size_is
== sizeof(guint16
)) {
1702 /* XXX - use drep to determine the byte order? */
1703 /* XXX - once we have an ENC_ value for UTF-16, just use
1704 proto_tree_add_item() with the appropriate ENC_ value? */
1705 /* XXX - should this ever be used with something that's *not*
1707 s
= tvb_get_unicode_string(wmem_packet_scope(), tvb
, offset
, buffer_len
, ENC_LITTLE_ENDIAN
);
1708 if (tree
&& buffer_len
) {
1709 hfinfo
= proto_registrar_get_nth(hfindex
);
1710 tvb_ensure_bytes_exist(tvb
, offset
, buffer_len
);
1711 if (hfinfo
->type
== FT_STRING
) {
1712 proto_tree_add_string(string_tree
, hfindex
, tvb
, offset
,
1715 proto_tree_add_item(string_tree
, hfindex
, tvb
, offset
,
1716 buffer_len
, DREP_ENC_INTEGER(drep
));
1722 * "tvb_get_string()" throws an exception if the entire string
1723 * isn't in the tvbuff. If the length is bogus, this should
1724 * keep us from trying to allocate an immensely large buffer.
1725 * (It won't help if the length is *valid* but immensely large,
1726 * but that's another matter; in any case, that would happen only
1727 * if we had an immensely large tvbuff....)
1729 * XXX - if this is an octet string, does the byte order
1730 * matter? Will this ever be anything *other* than an
1731 * octet string? What if size_is is neither 1 nor 2?
1733 tvb_ensure_bytes_exist(tvb
, offset
, buffer_len
);
1734 s
= tvb_get_string(wmem_packet_scope(), tvb
, offset
, buffer_len
);
1735 if (tree
&& buffer_len
)
1736 proto_tree_add_item(string_tree
, hfindex
, tvb
, offset
,
1737 buffer_len
, DREP_ENC_INTEGER(drep
));
1740 if (string_item
!= NULL
)
1741 proto_item_append_text(string_item
, ": %s", s
);
1746 offset
+= buffer_len
;
1748 proto_item_set_end(string_item
, tvb
, offset
);
1754 dissect_ndr_cstring(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
1755 proto_tree
*tree
, dcerpc_info
*di
, guint8
*drep
, int size_is
,
1756 int hfindex
, gboolean add_subtree
, char **data
)
1758 return dissect_ndr_cvstring(tvb
, offset
, pinfo
, tree
, di
, drep
, size_is
, hfindex
, add_subtree
, data
);
1761 /* Dissect an conformant varying string of chars.
1762 This corresponds to IDL of the form '[string] char *foo'.
1764 XXX - at least according to the DCE RPC 1.1 spec, a string has
1765 a null terminator, which isn't necessary as a terminator for
1766 the transfer language (as there's a length), but is presumably
1767 there for the benefit of null-terminated-string languages
1768 such as C. Is this ever used for purely counted strings?
1769 (Not that it matters if it is.) */
1771 dissect_ndr_char_cvstring(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
1772 proto_tree
*tree
, dcerpc_info
*di
, guint8
*drep
)
1774 return dissect_ndr_cvstring(tvb
, offset
, pinfo
, tree
, di
, drep
,
1775 sizeof(guint8
), di
->hf_index
,
1779 /* Dissect a conformant varying string of wchars (wide characters).
1780 This corresponds to IDL of the form '[string] wchar *foo'
1782 XXX - at least according to the DCE RPC 1.1 spec, a string has
1783 a null terminator, which isn't necessary as a terminator for
1784 the transfer language (as there's a length), but is presumably
1785 there for the benefit of null-terminated-string languages
1786 such as C. Is this ever used for purely counted strings?
1787 (Not that it matters if it is.) */
1789 dissect_ndr_wchar_cvstring(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
1790 proto_tree
*tree
, dcerpc_info
*di
, guint8
*drep
)
1792 return dissect_ndr_cvstring(tvb
, offset
, pinfo
, tree
, di
, drep
,
1793 sizeof(guint16
), di
->hf_index
,
1797 /* This function is aimed for PIDL usage and dissects a UNIQUE pointer to
1801 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
)
1804 gint levels
= CB_STR_ITEM_LEVELS(param
);
1806 offset
= dissect_ndr_cvstring(tvb
, offset
, pinfo
, tree
, di
, drep
,
1810 if (!di
->conformant_run
) {
1811 /* Append string to COL_INFO */
1812 if (param
& PIDL_SET_COL_INFO
) {
1813 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", %s", s
);
1815 /* Save string to dcv->private_data */
1816 if ((param
& PIDL_STR_SAVE
)
1817 && (!pinfo
->fd
->flags
.visited
)) {
1818 dcerpc_call_value
*dcv
= (dcerpc_call_value
*)di
->call_data
;
1819 dcv
->private_data
= wmem_strdup(wmem_file_scope(), s
);
1821 /* Append string to upper-level proto_items */
1822 if ((levels
> 0) && tree
&& s
&& s
[0]) {
1823 proto_item_append_text(tree
, ": %s", s
);
1824 tree
= tree
->parent
;
1827 proto_item_append_text(tree
, ": %s", s
);
1828 tree
= tree
->parent
;
1830 while (levels
> 0) {
1831 proto_item_append_text(tree
, " %s", s
);
1832 tree
= tree
->parent
;
1843 /* Dissect an NDR varying string of elements.
1844 The length of each element is given by the 'size_is' parameter;
1845 the elements are assumed to be characters or wide characters.
1848 dissect_ndr_vstring(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
1849 proto_tree
*tree
, dcerpc_info
*di
, guint8
*drep
, int size_is
,
1850 int hfindex
, gboolean add_subtree
, char **data
)
1852 proto_item
*string_item
;
1853 proto_tree
*string_tree
;
1857 header_field_info
*hfinfo
;
1859 if (di
->conformant_run
) {
1860 /* just a run to handle conformant arrays, no scalars to dissect */
1865 string_item
= proto_tree_add_text(tree
, tvb
, offset
, -1, "%s",
1866 proto_registrar_get_name(hfindex
));
1867 string_tree
= proto_item_add_subtree(string_item
, ett_dcerpc_string
);
1873 /* NDR array header */
1874 offset
= dissect_ndr_uint3264(tvb
, offset
, pinfo
, string_tree
, di
, drep
,
1875 hf_dcerpc_array_offset
, NULL
);
1877 offset
= dissect_ndr_uint3264(tvb
, offset
, pinfo
, string_tree
, di
, drep
,
1878 hf_dcerpc_array_actual_count
, &len
);
1880 DISSECTOR_ASSERT(len
<= G_MAXUINT32
);
1881 buffer_len
= size_is
* (guint32
)len
;
1884 if (!di
->no_align
&& (offset
% size_is
))
1885 offset
+= size_is
- (offset
% size_is
);
1887 if (size_is
== sizeof(guint16
)) {
1888 /* XXX - use drep to determine the byte order? */
1889 /* XXX - once we have an ENC_ value for UTF-16, just use
1890 proto_tree_add_item() with the appropriate ENC_ value? */
1891 /* XXX - should this ever be used with something that's *not*
1893 s
= tvb_get_unicode_string(wmem_packet_scope(), tvb
, offset
, buffer_len
, ENC_LITTLE_ENDIAN
);
1894 if (tree
&& buffer_len
) {
1895 hfinfo
= proto_registrar_get_nth(hfindex
);
1896 tvb_ensure_bytes_exist(tvb
, offset
, buffer_len
);
1897 if (hfinfo
->type
== FT_STRING
) {
1898 proto_tree_add_string(string_tree
, hfindex
, tvb
, offset
,
1901 proto_tree_add_item(string_tree
, hfindex
, tvb
, offset
,
1902 buffer_len
, DREP_ENC_INTEGER(drep
));
1908 * "tvb_get_string()" throws an exception if the entire string
1909 * isn't in the tvbuff. If the length is bogus, this should
1910 * keep us from trying to allocate an immensely large buffer.
1911 * (It won't help if the length is *valid* but immensely large,
1912 * but that's another matter; in any case, that would happen only
1913 * if we had an immensely large tvbuff....)
1915 * XXX - if this is an octet string, does the byte order
1916 * matter? Will this ever be anything *other* than an
1917 * octet string? What if size_is is neither 1 nor 2?
1919 tvb_ensure_bytes_exist(tvb
, offset
, buffer_len
);
1920 s
= tvb_get_string(wmem_packet_scope(), tvb
, offset
, buffer_len
);
1921 if (tree
&& buffer_len
)
1922 proto_tree_add_item(string_tree
, hfindex
, tvb
, offset
,
1923 buffer_len
, DREP_ENC_INTEGER(drep
));
1926 if (string_item
!= NULL
)
1927 proto_item_append_text(string_item
, ": %s", s
);
1932 offset
+= buffer_len
;
1934 proto_item_set_end(string_item
, tvb
, offset
);
1939 /* Dissect an varying string of chars.
1940 This corresponds to IDL of the form '[string] char *foo'.
1942 XXX - at least according to the DCE RPC 1.1 spec, a string has
1943 a null terminator, which isn't necessary as a terminator for
1944 the transfer language (as there's a length), but is presumably
1945 there for the benefit of null-terminated-string languages
1946 such as C. Is this ever used for purely counted strings?
1947 (Not that it matters if it is.) */
1949 dissect_ndr_char_vstring(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
1950 proto_tree
*tree
, dcerpc_info
*di
, guint8
*drep
)
1952 return dissect_ndr_vstring(tvb
, offset
, pinfo
, tree
, di
, drep
,
1953 sizeof(guint8
), di
->hf_index
,
1957 /* Dissect a varying string of wchars (wide characters).
1958 This corresponds to IDL of the form '[string] wchar *foo'
1960 XXX - at least according to the DCE RPC 1.1 spec, a string has
1961 a null terminator, which isn't necessary as a terminator for
1962 the transfer language (as there's a length), but is presumably
1963 there for the benefit of null-terminated-string languages
1964 such as C. Is this ever used for purely counted strings?
1965 (Not that it matters if it is.) */
1967 dissect_ndr_wchar_vstring(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
1968 proto_tree
*tree
, dcerpc_info
*di
, guint8
*drep
)
1970 return dissect_ndr_vstring(tvb
, offset
, pinfo
, tree
, di
, drep
,
1971 sizeof(guint16
), di
->hf_index
,
1976 /* ndr pointer handling */
1977 /* list of pointers encountered so far */
1978 static GSList
*ndr_pointer_list
= NULL
;
1980 /* position where in the list to insert newly encountered pointers */
1981 static int ndr_pointer_list_pos
= 0;
1983 /* Boolean controlling whether pointers are top-level or embedded */
1984 static gboolean pointers_are_top_level
= TRUE
;
1986 /* as a kludge, we represent all embedded reference pointers as id == -1
1987 hoping that his will not collide with any non-ref pointers */
1988 typedef struct ndr_pointer_data
{
1990 proto_item
*item
; /* proto_item for pointer */
1991 proto_tree
*tree
; /* subtree of above item */
1992 dcerpc_dissect_fnct_t
*fnct
; /*if non-NULL, we have not called it yet*/
1994 dcerpc_callback_fnct_t
*callback
;
1995 void *callback_args
;
1996 } ndr_pointer_data_t
;
1999 init_ndr_pointer_list(dcerpc_info
*di
)
2001 di
->conformant_run
= 0;
2003 while (ndr_pointer_list
) {
2004 ndr_pointer_data_t
*npd
= (ndr_pointer_data_t
*)g_slist_nth_data(ndr_pointer_list
, 0);
2005 ndr_pointer_list
= g_slist_remove(ndr_pointer_list
, npd
);
2009 ndr_pointer_list
= NULL
;
2010 ndr_pointer_list_pos
= 0;
2011 pointers_are_top_level
= TRUE
;
2015 dissect_deferred_pointers(packet_info
*pinfo
, tvbuff_t
*tvb
, int offset
, dcerpc_info
*di
, guint8
*drep
)
2017 int found_new_pointer
;
2026 found_new_pointer
= 0;
2027 len
= g_slist_length(ndr_pointer_list
);
2028 for(i
=next_pointer
; i
<len
; i
++) {
2029 ndr_pointer_data_t
*tnpd
= (ndr_pointer_data_t
*)g_slist_nth_data(ndr_pointer_list
, i
);
2031 dcerpc_dissect_fnct_t
*fnct
;
2034 found_new_pointer
= 1;
2037 ndr_pointer_list_pos
= i
+1;
2038 di
->hf_index
= tnpd
->hf_index
;
2039 /* first a run to handle any conformant
2041 di
->conformant_run
= 1;
2042 di
->conformant_eaten
= 0;
2043 old_offset
= offset
;
2044 offset
= (*(fnct
))(tvb
, offset
, pinfo
, NULL
, di
, drep
);
2046 DISSECTOR_ASSERT((offset
-old_offset
) == di
->conformant_eaten
);
2047 /* This is to check for any bugs in the dissectors.
2049 * Basically, the NDR representation will store all
2050 * arrays in two blocks, one block with the dimension
2051 * description, like size, number of elements and such,
2052 * and another block that contains the actual data stored
2054 * If the array is embedded directly inside another,
2055 * encapsulating aggregate type, like a union or struct,
2056 * then these two blocks will be stored at different places
2057 * in the bytestream, with other data between the blocks.
2059 * For this reason, all pointers to types (both aggregate
2060 * and scalar, for simplicity no distinction is made)
2061 * will have its dissector called twice.
2062 * The dissector will first be called with conformant_run == 1
2063 * in which mode the dissector MUST NOT consume any data from
2064 * the tvbuff (i.e. may not dissect anything) except the
2065 * initial control block for arrays.
2066 * The second time the dissector is called, with
2067 * conformant_run == 0, all other data for the type will be
2070 * All dissect_ndr_<type> dissectors are already prepared
2071 * for this and knows when it should eat data from the tvb
2072 * and when not to, so implementors of dissectors will
2073 * normally not need to worry about this or even know about
2074 * it. However, if a dissector for an aggregate type calls
2075 * a subdissector from outside packet-dcerpc.c, such as
2076 * the dissector in packet-smb.c for NT Security Descriptors
2077 * as an example, then it is VERY important to encapsulate
2078 * this call to an external subdissector with the appropriate
2079 * test for conformant_run, i.e. it will need something like
2081 * dcerpc_info *di (received as function parameter)
2083 * if (di->conformant_run) {
2087 * to make sure it makes the right thing.
2088 * This assert will signal when someone has forgotten to
2089 * make the dissector aware of this requirement.
2092 /* now we dissect the actual pointer */
2093 di
->conformant_run
= 0;
2094 old_offset
= offset
;
2095 offset
= (*(fnct
))(tvb
, offset
, pinfo
, tnpd
->tree
, di
, drep
);
2097 tnpd
->callback(pinfo
, tnpd
->tree
, tnpd
->item
, di
, tvb
, old_offset
, offset
, tnpd
->callback_args
);
2098 proto_item_set_len(tnpd
->item
, offset
- old_offset
);
2102 } while (found_new_pointer
);
2109 add_pointer_to_list(packet_info
*pinfo
, proto_tree
*tree
, proto_item
*item
,
2110 dcerpc_info
*di
, dcerpc_dissect_fnct_t
*fnct
, guint32 id
, int hf_index
,
2111 dcerpc_callback_fnct_t
*callback
, void *callback_args
)
2113 ndr_pointer_data_t
*npd
;
2115 /* check if this pointer is valid */
2116 if (id
!= 0xffffffff) {
2117 dcerpc_call_value
*value
;
2119 value
= di
->call_data
;
2121 if (di
->ptype
== PDU_REQ
) {
2122 if (!(pinfo
->fd
->flags
.visited
)) {
2123 if (id
> value
->max_ptr
) {
2124 value
->max_ptr
= id
;
2128 /* if we haven't seen the request bail out since we cant
2129 know whether this is the first non-NULL instance
2131 if (value
->req_frame
== 0) {
2132 /* XXX THROW EXCEPTION */
2135 /* We saw this one in the request frame, nothing to
2137 if (id
<= value
->max_ptr
) {
2143 npd
= (ndr_pointer_data_t
*)g_malloc(sizeof(ndr_pointer_data_t
));
2148 npd
->hf_index
= hf_index
;
2149 npd
->callback
= callback
;
2150 npd
->callback_args
= callback_args
;
2151 ndr_pointer_list
= g_slist_insert(ndr_pointer_list
, npd
,
2152 ndr_pointer_list_pos
);
2153 ndr_pointer_list_pos
++;
2158 find_pointer_index(guint32 id
)
2160 ndr_pointer_data_t
*npd
;
2163 len
= g_slist_length(ndr_pointer_list
);
2164 for(i
=0; i
<len
; i
++) {
2165 npd
= (ndr_pointer_data_t
*)g_slist_nth_data(ndr_pointer_list
, i
);
2167 if (npd
->id
== id
) {
2176 /* This function dissects an NDR pointer and stores the callback for later
2177 * deferred dissection.
2179 * fnct is the callback function for when we have reached this object in
2182 * type is what type of pointer.
2184 * this is text is what text we should put in any created tree node.
2186 * hf_index is what hf value we want to pass to the callback function when
2187 * it is called, the callback can later pick this one up from di->hf_index.
2189 * callback is executed after the pointer has been dereferenced.
2191 * callback_args is passed as an argument to the callback function
2193 * See packet-dcerpc-samr.c for examples
2196 dissect_ndr_pointer_cb(tvbuff_t
*tvb
, gint offset
, packet_info
*pinfo
,
2197 proto_tree
*tree
, dcerpc_info
*di
, guint8
*drep
, dcerpc_dissect_fnct_t
*fnct
,
2198 int type
, const char *text
, int hf_index
,
2199 dcerpc_callback_fnct_t
*callback
, void *callback_args
)
2201 proto_tree
*tr
= NULL
;
2202 gint start_offset
= offset
;
2203 int pointer_size
= 4;
2205 if (di
->conformant_run
) {
2206 /* this call was only for dissecting the header for any
2207 embedded conformant array. we will not parse any
2208 pointers in this mode.
2212 if (di
->call_data
->flags
& DCERPC_IS_NDR64
) {
2217 /*TOP LEVEL REFERENCE POINTER*/
2218 if ( pointers_are_top_level
2219 && (type
== NDR_POINTER_REF
) ) {
2222 /* we must find out a nice way to do the length here */
2223 item
= proto_tree_add_text(tree
, tvb
, offset
, 0,
2225 tr
= proto_item_add_subtree(item
,ett_dcerpc_pointer_data
);
2227 add_pointer_to_list(pinfo
, tr
, item
, di
, fnct
, 0xffffffff,
2228 hf_index
, callback
, callback_args
);
2232 /*TOP LEVEL FULL POINTER*/
2233 if ( pointers_are_top_level
2234 && (type
== NDR_POINTER_PTR
) ) {
2239 /* get the referent id */
2240 offset
= dissect_ndr_uint3264(tvb
, offset
, pinfo
, NULL
, di
, drep
, -1, &id
);
2242 tvb_ensure_bytes_exist(tvb
, offset
-pointer_size
, pointer_size
);
2243 /* we got a NULL pointer */
2245 proto_tree_add_text(tree
, tvb
, offset
-pointer_size
,
2247 "(NULL pointer) %s",text
);
2251 /* see if we have seen this pointer before */
2252 DISSECTOR_ASSERT(id
<= G_MAXUINT32
);
2253 idx
= find_pointer_index((guint32
)id
);
2255 /* we have seen this pointer before */
2257 proto_tree_add_text(tree
, tvb
, offset
-pointer_size
,
2259 "(duplicate PTR) %s",text
);
2264 item
= proto_tree_add_text(tree
, tvb
, offset
-pointer_size
,
2267 tr
= proto_item_add_subtree(item
,ett_dcerpc_pointer_data
);
2268 proto_tree_add_uint(tr
, hf_dcerpc_referent_id
, tvb
,
2269 offset
-pointer_size
, pointer_size
, (guint32
)id
);
2270 add_pointer_to_list(pinfo
, tr
, item
, di
, fnct
, (guint32
)id
, hf_index
,
2271 callback
, callback_args
);
2274 /*TOP LEVEL UNIQUE POINTER*/
2275 if ( pointers_are_top_level
2276 && (type
== NDR_POINTER_UNIQUE
) ) {
2280 /* get the referent id */
2281 offset
= dissect_ndr_uint3264(tvb
, offset
, pinfo
, NULL
, di
, drep
, -1, &id
);
2283 tvb_ensure_bytes_exist(tvb
, offset
-pointer_size
, pointer_size
);
2284 /* we got a NULL pointer */
2286 proto_tree_add_text(tree
, tvb
, offset
-pointer_size
,
2288 "(NULL pointer) %s",text
);
2293 DISSECTOR_ASSERT(id
<= G_MAXUINT32
);
2294 item
= proto_tree_add_text(tree
, tvb
, offset
-pointer_size
,
2297 tr
= proto_item_add_subtree(item
,ett_dcerpc_pointer_data
);
2298 proto_tree_add_uint(tr
, hf_dcerpc_referent_id
, tvb
,
2299 offset
-pointer_size
, pointer_size
, (guint32
)id
);
2300 add_pointer_to_list(pinfo
, tr
, item
, di
, fnct
, 0xffffffff,
2301 hf_index
, callback
, callback_args
);
2305 /*EMBEDDED REFERENCE POINTER*/
2306 if ( (!pointers_are_top_level
)
2307 && (type
== NDR_POINTER_REF
) ) {
2311 /* get the referent id */
2312 offset
= dissect_ndr_uint3264(tvb
, offset
, pinfo
, NULL
, di
, drep
, -1, &id
);
2314 tvb_ensure_bytes_exist(tvb
, offset
-pointer_size
, pointer_size
);
2316 item
= proto_tree_add_text(tree
, tvb
, offset
-pointer_size
,
2319 tr
= proto_item_add_subtree(item
,ett_dcerpc_pointer_data
);
2320 DISSECTOR_ASSERT(id
<= G_MAXUINT32
);
2321 proto_tree_add_uint(tr
, hf_dcerpc_referent_id
, tvb
,
2322 offset
-pointer_size
, pointer_size
, (guint32
)id
);
2323 add_pointer_to_list(pinfo
, tr
, item
, di
, fnct
, 0xffffffff,
2324 hf_index
, callback
, callback_args
);
2328 /*EMBEDDED UNIQUE POINTER*/
2329 if ( (!pointers_are_top_level
)
2330 && (type
== NDR_POINTER_UNIQUE
) ) {
2334 /* get the referent id */
2335 offset
= dissect_ndr_uint3264(tvb
, offset
, pinfo
, NULL
, di
, drep
, -1, &id
);
2337 tvb_ensure_bytes_exist(tvb
, offset
-pointer_size
, pointer_size
);
2338 /* we got a NULL pointer */
2340 proto_tree_add_text(tree
, tvb
, offset
-pointer_size
,
2342 "(NULL pointer) %s", text
);
2347 item
= proto_tree_add_text(tree
, tvb
, offset
-pointer_size
,
2350 tr
= proto_item_add_subtree(item
,ett_dcerpc_pointer_data
);
2351 DISSECTOR_ASSERT(id
<= G_MAXUINT32
);
2352 proto_tree_add_uint(tr
, hf_dcerpc_referent_id
, tvb
,
2353 offset
-pointer_size
, pointer_size
, (guint32
)id
);
2354 add_pointer_to_list(pinfo
, tr
, item
, di
, fnct
, 0xffffffff,
2355 hf_index
, callback
, callback_args
);
2359 /*EMBEDDED FULL POINTER*/
2360 if ( (!pointers_are_top_level
)
2361 && (type
== NDR_POINTER_PTR
) ) {
2366 /* get the referent id */
2367 offset
= dissect_ndr_uint3264(tvb
, offset
, pinfo
, NULL
, di
, drep
, -1, &id
);
2369 tvb_ensure_bytes_exist(tvb
, offset
-pointer_size
, pointer_size
);
2370 /* we got a NULL pointer */
2372 proto_tree_add_text(tree
, tvb
, offset
-pointer_size
,
2374 "(NULL pointer) %s",text
);
2378 /* see if we have seen this pointer before */
2379 DISSECTOR_ASSERT(id
<= G_MAXUINT32
);
2380 idx
= find_pointer_index((guint32
)id
);
2382 /* we have seen this pointer before */
2384 proto_tree_add_text(tree
, tvb
, offset
-pointer_size
,
2386 "(duplicate PTR) %s",text
);
2391 item
= proto_tree_add_text(tree
, tvb
, offset
-pointer_size
,
2394 tr
= proto_item_add_subtree(item
,ett_dcerpc_pointer_data
);
2395 proto_tree_add_uint(tr
, hf_dcerpc_referent_id
, tvb
,
2396 offset
-pointer_size
, pointer_size
, (guint32
)id
);
2397 add_pointer_to_list(pinfo
, tr
, item
, di
, fnct
, (guint32
)id
, hf_index
,
2398 callback
, callback_args
);
2404 /* After each top level pointer we have dissected we have to
2405 dissect all deferrals before we move on to the next top level
2407 if (pointers_are_top_level
== TRUE
) {
2408 pointers_are_top_level
= FALSE
;
2409 offset
= dissect_deferred_pointers(pinfo
, tvb
, offset
, di
, drep
);
2410 pointers_are_top_level
= TRUE
;
2413 /* Set the length for the new subtree */
2415 proto_item_set_len(tr
, offset
-start_offset
);
2421 dissect_ndr_pointer(tvbuff_t
*tvb
, gint offset
, packet_info
*pinfo
,
2422 proto_tree
*tree
, dcerpc_info
*di
, guint8
*drep
, dcerpc_dissect_fnct_t
*fnct
,
2423 int type
, const char *text
, int hf_index
)
2425 return dissect_ndr_pointer_cb(
2426 tvb
, offset
, pinfo
, tree
, di
, drep
, fnct
, type
, text
, hf_index
,
2430 dissect_ndr_toplevel_pointer(tvbuff_t
*tvb
, gint offset
, packet_info
*pinfo
,
2431 proto_tree
*tree
, dcerpc_info
*di
, guint8
*drep
, dcerpc_dissect_fnct_t
*fnct
,
2432 int type
, const char *text
, int hf_index
)
2436 pointers_are_top_level
= TRUE
;
2437 ret
= dissect_ndr_pointer_cb(
2438 tvb
, offset
, pinfo
, tree
, di
, drep
, fnct
, type
, text
, hf_index
,
2443 dissect_ndr_embedded_pointer(tvbuff_t
*tvb
, gint offset
, packet_info
*pinfo
,
2444 proto_tree
*tree
, dcerpc_info
*di
, guint8
*drep
, dcerpc_dissect_fnct_t
*fnct
,
2445 int type
, const char *text
, int hf_index
)
2449 pointers_are_top_level
= FALSE
;
2450 ret
= dissect_ndr_pointer_cb(
2451 tvb
, offset
, pinfo
, tree
, di
, drep
, fnct
, type
, text
, hf_index
,
2457 show_stub_data(tvbuff_t
*tvb
, gint offset
, proto_tree
*dcerpc_tree
,
2458 dcerpc_auth_info
*auth_info
, gboolean is_encrypted
)
2460 int length
, plain_length
, auth_pad_len
;
2461 guint auth_pad_offset
;
2464 * We don't show stub data unless we have some in the tvbuff;
2465 * however, in the protocol tree, we show, as the number of
2466 * bytes, the reported number of bytes, not the number of bytes
2467 * that happen to be in the tvbuff.
2469 if (tvb_length_remaining(tvb
, offset
) > 0) {
2470 auth_pad_len
= auth_info
?auth_info
->auth_pad_len
:0;
2471 length
= tvb_reported_length_remaining(tvb
, offset
);
2473 /* if auth_pad_len is larger than length then we ignore auth_pad_len totally */
2474 plain_length
= length
- auth_pad_len
;
2475 if (plain_length
< 1) {
2476 plain_length
= length
;
2479 auth_pad_offset
= offset
+ plain_length
;
2481 if ((auth_info
!= NULL
) &&
2482 (auth_info
->auth_level
== DCE_C_AUTHN_LEVEL_PKT_PRIVACY
)) {
2484 tvb_ensure_bytes_exist(tvb
, offset
, length
);
2485 proto_tree_add_text(dcerpc_tree
, tvb
, offset
, length
,
2486 "Encrypted stub data (%d byte%s)",
2487 length
, plurality(length
, "", "s"));
2488 /* is the padding is still inside the encrypted blob, don't display it explicit */
2491 tvb_ensure_bytes_exist(tvb
, offset
, plain_length
);
2492 proto_tree_add_text(dcerpc_tree
, tvb
, offset
, plain_length
,
2493 "Decrypted stub data (%d byte%s)",
2494 plain_length
, plurality(plain_length
, "", "s"));
2497 tvb_ensure_bytes_exist(tvb
, offset
, plain_length
);
2498 proto_tree_add_text(dcerpc_tree
, tvb
, offset
, plain_length
,
2499 "Stub data (%d byte%s)", plain_length
,
2500 plurality(plain_length
, "", "s"));
2502 /* If there is auth padding at the end of the stub, display it */
2503 if (auth_pad_len
!= 0) {
2504 tvb_ensure_bytes_exist(tvb
, auth_pad_offset
, auth_pad_len
);
2505 proto_tree_add_text(dcerpc_tree
, tvb
, auth_pad_offset
,
2507 "Auth Padding (%u byte%s)",
2509 plurality(auth_pad_len
, "", "s"));
2515 dcerpc_try_handoff(packet_info
*pinfo
, proto_tree
*tree
,
2516 proto_tree
*dcerpc_tree
,
2517 tvbuff_t
*volatile tvb
, tvbuff_t
*decrypted_tvb
,
2518 guint8
*drep
, dcerpc_info
*info
,
2519 dcerpc_auth_info
*auth_info
)
2521 volatile gint offset
= 0;
2522 dcerpc_uuid_key key
;
2523 dcerpc_uuid_value
*sub_proto
;
2524 proto_tree
*volatile sub_tree
= NULL
;
2525 dcerpc_sub_dissector
*proc
;
2526 const gchar
*name
= NULL
;
2527 const char *volatile saved_proto
;
2528 guint length
= 0, reported_length
= 0;
2529 tvbuff_t
*volatile stub_tvb
;
2530 volatile guint auth_pad_len
;
2531 volatile int auth_pad_offset
;
2532 proto_item
*sub_item
= NULL
;
2533 proto_item
*pi
, *hidden_item
;
2535 dcerpc_dissect_fnct_t
*volatile sub_dissect
;
2537 key
.uuid
= info
->call_data
->uuid
;
2538 key
.ver
= info
->call_data
->ver
;
2540 if ((sub_proto
= (dcerpc_uuid_value
*)g_hash_table_lookup(dcerpc_uuids
, &key
)) == NULL
2541 || !proto_is_protocol_enabled(sub_proto
->proto
)) {
2543 * We don't have a dissector for this UUID, or the protocol
2544 * for that UUID is disabled.
2547 hidden_item
= proto_tree_add_boolean(dcerpc_tree
, hf_dcerpc_unknown_if_id
,
2548 tvb
, offset
, 0, TRUE
);
2549 PROTO_ITEM_SET_HIDDEN(hidden_item
);
2550 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " %s V%u",
2551 guids_resolve_uuid_to_str(&info
->call_data
->uuid
), info
->call_data
->ver
);
2553 if (decrypted_tvb
!= NULL
) {
2554 show_stub_data(decrypted_tvb
, 0, dcerpc_tree
, auth_info
,
2557 show_stub_data(tvb
, 0, dcerpc_tree
, auth_info
, TRUE
);
2561 for (proc
= sub_proto
->procs
; proc
->name
; proc
++) {
2562 if (proc
->num
== info
->call_data
->opnum
) {
2568 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, sub_proto
->name
);
2571 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "Unknown operation %u %s",
2572 info
->call_data
->opnum
,
2573 (info
->ptype
== PDU_REQ
) ? "request" : "response");
2575 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "%s %s",
2576 name
, (info
->ptype
== PDU_REQ
) ? "request" : "response");
2578 sub_dissect
= (info
->ptype
== PDU_REQ
) ?
2579 proc
->dissect_rqst
: proc
->dissect_resp
;
2582 sub_item
= proto_tree_add_item(tree
, sub_proto
->proto_id
,
2583 (decrypted_tvb
!= NULL
)?decrypted_tvb
:tvb
,
2587 sub_tree
= proto_item_add_subtree(sub_item
, sub_proto
->ett
);
2589 proto_item_append_text(sub_item
, ", unknown operation %u",
2590 info
->call_data
->opnum
);
2592 proto_item_append_text(sub_item
, ", %s", name
);
2596 * Put the operation number into the tree along with
2597 * the operation's name.
2599 if (sub_proto
->opnum_hf
!= -1)
2600 proto_tree_add_uint_format(sub_tree
, sub_proto
->opnum_hf
,
2601 tvb
, 0, 0, info
->call_data
->opnum
,
2602 "Operation: %s (%u)",
2603 name
? name
: "Unknown operation",
2604 info
->call_data
->opnum
);
2606 proto_tree_add_uint_format_value(sub_tree
, hf_dcerpc_op
, tvb
,
2607 0, 0, info
->call_data
->opnum
,
2609 name
? name
: "Unknown operation",
2610 info
->call_data
->opnum
);
2612 if ((info
->ptype
== PDU_REQ
) && (info
->call_data
->rep_frame
!= 0)) {
2613 pi
= proto_tree_add_uint(sub_tree
, hf_dcerpc_response_in
,
2614 tvb
, 0, 0, info
->call_data
->rep_frame
);
2615 PROTO_ITEM_SET_GENERATED(pi
);
2617 if ((info
->ptype
== PDU_RESP
) && (info
->call_data
->req_frame
!= 0)) {
2618 pi
= proto_tree_add_uint(sub_tree
, hf_dcerpc_request_in
,
2619 tvb
, 0, 0, info
->call_data
->req_frame
);
2620 PROTO_ITEM_SET_GENERATED(pi
);
2624 if (decrypted_tvb
!= NULL
) {
2625 /* Either there was no encryption or we successfully decrypted
2626 the encrypted payload. */
2628 /* We have a subdissector - call it. */
2629 saved_proto
= pinfo
->current_proto
;
2630 pinfo
->current_proto
= sub_proto
->name
;
2632 init_ndr_pointer_list(info
);
2634 length
= tvb_length(decrypted_tvb
);
2635 reported_length
= tvb_reported_length(decrypted_tvb
);
2638 * Remove the authentication padding from the stub data.
2640 if ((auth_info
!= NULL
) && (auth_info
->auth_pad_len
!= 0)) {
2641 if (reported_length
>= auth_info
->auth_pad_len
) {
2643 * OK, the padding length isn't so big that it
2644 * exceeds the stub length. Trim the reported
2645 * length of the tvbuff.
2647 reported_length
-= auth_info
->auth_pad_len
;
2650 * If that exceeds the actual amount of data in
2651 * the tvbuff (which means we have at least one
2652 * byte of authentication padding in the tvbuff),
2653 * trim the actual amount.
2655 if (length
> reported_length
)
2656 length
= reported_length
;
2658 stub_tvb
= tvb_new_subset(decrypted_tvb
, 0, length
, reported_length
);
2659 auth_pad_len
= auth_info
->auth_pad_len
;
2660 auth_pad_offset
= reported_length
;
2663 * The padding length exceeds the stub length.
2664 * Don't bother dissecting the stub, trim the padding
2665 * length to what's in the stub data, and show the
2666 * entire stub as authentication padding.
2669 auth_pad_len
= reported_length
;
2670 auth_pad_offset
= 0;
2675 * No authentication padding.
2677 stub_tvb
= decrypted_tvb
;
2679 auth_pad_offset
= 0;
2683 proto_item_set_len(sub_item
, length
);
2686 if (stub_tvb
!= NULL
) {
2688 * Catch all exceptions other than BoundsError, so that even
2689 * if the stub data is bad, we still show the authentication
2692 * If we get BoundsError, it means the frame was cut short
2693 * by a snapshot length, so there's nothing more to
2694 * dissect; just re-throw that exception.
2699 offset
= sub_dissect(stub_tvb
, 0, pinfo
, sub_tree
,
2702 /* If we have a subdissector and it didn't dissect all
2703 data in the tvb, make a note of it. */
2704 remaining
= tvb_reported_length_remaining(stub_tvb
, offset
);
2705 if (remaining
> 0) {
2706 proto_tree_add_text(sub_tree
, stub_tvb
, offset
,
2708 "[Long frame (%d byte%s)]",
2710 plurality(remaining
, "", "s"));
2711 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
2712 "[Long frame (%d byte%s)]",
2714 plurality(remaining
, "", "s"));
2717 } CATCH_NONFATAL_ERRORS
{
2719 * Somebody threw an exception that means that there
2720 * was a problem dissecting the payload; that means
2721 * that a dissector was found, so we don't need to
2722 * dissect the payload as data or update the protocol
2725 * Just show the exception and then drive on to show
2726 * the authentication padding.
2728 show_exception(stub_tvb
, pinfo
, tree
, EXCEPT_CODE
, GET_MESSAGE
);
2732 /* If there is auth padding at the end of the stub, display it */
2733 if (auth_pad_len
!= 0) {
2734 tvb_ensure_bytes_exist(tvb
, auth_pad_offset
, auth_pad_len
);
2735 proto_tree_add_text(sub_tree
, decrypted_tvb
, auth_pad_offset
,
2737 "Auth Padding (%u byte%s)",
2739 plurality(auth_pad_len
, "", "s"));
2742 pinfo
->current_proto
= saved_proto
;
2744 /* No subdissector - show it as stub data. */
2745 if (decrypted_tvb
) {
2746 show_stub_data(decrypted_tvb
, 0, sub_tree
, auth_info
, FALSE
);
2748 show_stub_data(tvb
, 0, sub_tree
, auth_info
, TRUE
);
2752 show_stub_data(tvb
, 0, sub_tree
, auth_info
, TRUE
);
2754 tap_queue_packet(dcerpc_tap
, pinfo
, info
);
2759 dissect_dcerpc_verifier(tvbuff_t
*tvb
, packet_info
*pinfo
,
2760 proto_tree
*dcerpc_tree
, e_dce_cn_common_hdr_t
*hdr
,
2761 dcerpc_auth_info
*auth_info
)
2765 auth_info
->auth_data
= NULL
;
2767 if (auth_info
->auth_size
!= 0) {
2768 dcerpc_auth_subdissector_fns
*auth_fns
;
2771 auth_offset
= hdr
->frag_len
- hdr
->auth_len
;
2773 auth_tvb
= tvb_new_subset(tvb
, auth_offset
, hdr
->auth_len
,
2776 auth_info
->auth_data
= auth_tvb
;
2778 if ((auth_fns
= get_auth_subdissector_fns(auth_info
->auth_level
,
2779 auth_info
->auth_type
))) {
2781 * Catch all bounds-error exceptions, so that even if the
2782 * verifier is bad or we don't have all of it, we still
2783 * show the stub data.
2786 dissect_auth_verf(auth_tvb
, pinfo
, dcerpc_tree
, auth_fns
,
2788 } CATCH_BOUNDS_ERRORS
{
2789 show_exception(auth_tvb
, pinfo
, dcerpc_tree
, EXCEPT_CODE
, GET_MESSAGE
);
2792 tvb_ensure_bytes_exist(tvb
, 0, hdr
->auth_len
);
2793 proto_tree_add_text(dcerpc_tree
, auth_tvb
, 0, hdr
->auth_len
,
2798 return hdr
->auth_len
;
2802 dissect_dcerpc_cn_auth(tvbuff_t
*tvb
, int stub_offset
, packet_info
*pinfo
,
2803 proto_tree
*dcerpc_tree
, e_dce_cn_common_hdr_t
*hdr
,
2804 gboolean are_credentials
, dcerpc_auth_info
*auth_info
)
2806 volatile int offset
;
2809 * Initially set auth_level and auth_type to zero to indicate that we
2810 * haven't yet seen any authentication level information.
2812 auth_info
->auth_level
= 0;
2813 auth_info
->auth_type
= 0;
2814 auth_info
->auth_size
= 0;
2815 auth_info
->auth_pad_len
= 0;
2818 * The authentication information is at the *end* of the PDU; in
2819 * request and response PDUs, the request and response stub data
2822 * Is there any authentication data (i.e., is the authentication length
2823 * non-zero), and is the authentication length valid (i.e., is it, plus
2824 * 8 bytes for the type/level/pad length/reserved/context id, less than
2825 * or equal to the fragment length minus the starting offset of the
2830 && ((hdr
->auth_len
+ 8) <= (hdr
->frag_len
- stub_offset
))) {
2833 * Yes, there is authentication data, and the length is valid.
2834 * Do we have all the bytes of stub data?
2835 * (If not, we'd throw an exception dissecting *that*, so don't
2836 * bother trying to dissect the authentication information and
2837 * throwing another exception there.)
2839 offset
= hdr
->frag_len
- (hdr
->auth_len
+ 8);
2840 if (offset
== 0 || tvb_offset_exists(tvb
, offset
- 1)) {
2842 * Either there's no stub data, or the last byte of the stub
2843 * data is present in the captured data, so we shouldn't
2844 * get a BoundsError dissecting the stub data.
2846 * Try dissecting the authentication data.
2847 * Catch all exceptions, so that even if the auth info is bad
2848 * or we don't have all of it, we still show the stuff we
2849 * dissect after this, such as stub data.
2852 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
2853 hf_dcerpc_auth_type
,
2854 &auth_info
->auth_type
);
2855 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
2856 hf_dcerpc_auth_level
,
2857 &auth_info
->auth_level
);
2859 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
2860 hf_dcerpc_auth_pad_len
,
2861 &auth_info
->auth_pad_len
);
2862 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
2863 hf_dcerpc_auth_rsrvd
, NULL
);
2864 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
2865 hf_dcerpc_auth_ctx_id
, NULL
);
2868 * Dissect the authentication data.
2870 if (are_credentials
) {
2872 dcerpc_auth_subdissector_fns
*auth_fns
;
2874 auth_tvb
= tvb_new_subset(tvb
, offset
,
2875 MIN(hdr
->auth_len
,tvb_length_remaining(tvb
, offset
)),
2878 if ((auth_fns
= get_auth_subdissector_fns(auth_info
->auth_level
,
2879 auth_info
->auth_type
)))
2880 dissect_auth_verf(auth_tvb
, pinfo
, dcerpc_tree
, auth_fns
,
2883 proto_tree_add_text(dcerpc_tree
, tvb
, offset
, hdr
->auth_len
,
2884 "Auth Credentials");
2887 /* Compute the size of the auth block. Note that this should not
2888 include auth padding, since when NTLMSSP encryption is used, the
2889 padding is actually inside the encrypted stub */
2890 auth_info
->auth_size
= hdr
->auth_len
+ 8;
2891 } CATCH_BOUNDS_ERRORS
{
2892 show_exception(tvb
, pinfo
, dcerpc_tree
, EXCEPT_CODE
, GET_MESSAGE
);
2899 /* We need to hash in the SMB fid number to generate a unique hash table
2900 * key as DCERPC over SMB allows several pipes over the same TCP/IP
2902 * We pass this function the transport type here to make sure we only look
2903 * at this function if it came across an SMB pipe.
2904 * Other transports might need to mix in their own extra multiplexing data
2905 * as well in the future.
2908 guint16
dcerpc_get_transport_salt(packet_info
*pinfo
)
2910 switch (pinfo
->dcetransporttype
) {
2911 case DCE_CN_TRANSPORT_SMBPIPE
:
2912 /* DCERPC over smb */
2913 return pinfo
->dcetransportsalt
;
2916 /* Some other transport... */
2921 * Connection oriented packet types
2925 dissect_dcerpc_cn_bind(tvbuff_t
*tvb
, gint offset
, packet_info
*pinfo
,
2926 proto_tree
*dcerpc_tree
, e_dce_cn_common_hdr_t
*hdr
)
2928 conversation_t
*conv
= find_or_create_conversation(pinfo
);
2929 guint8 num_ctx_items
= 0;
2932 guint8 num_trans_items
;
2937 guint16 if_ver
, if_ver_minor
;
2938 dcerpc_auth_info auth_info
;
2940 const char *uuid_name
= NULL
;
2941 proto_item
*iface_item
= NULL
;
2943 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
2944 hf_dcerpc_cn_max_xmit
, NULL
);
2946 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
2947 hf_dcerpc_cn_max_recv
, NULL
);
2949 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
2950 hf_dcerpc_cn_assoc_group
, NULL
);
2952 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
2953 hf_dcerpc_cn_num_ctx_items
, &num_ctx_items
);
2958 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", %u context items:", num_ctx_items
);
2960 for (i
= 0; i
< num_ctx_items
; i
++) {
2961 proto_item
*ctx_item
= NULL
;
2962 proto_tree
*ctx_tree
= NULL
, *iface_tree
= NULL
;
2963 gint ctx_offset
= offset
;
2965 dissect_dcerpc_uint16(tvb
, offset
, pinfo
, NULL
, hdr
->drep
,
2966 hf_dcerpc_cn_ctx_id
, &ctx_id
);
2968 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
2969 /* (if we have multiple contexts, this might cause "decode as"
2970 * to behave unpredictably) */
2971 pinfo
->dcectxid
= ctx_id
;
2974 ctx_item
= proto_tree_add_item(dcerpc_tree
, hf_dcerpc_cn_ctx_item
,
2977 ctx_tree
= proto_item_add_subtree(ctx_item
, ett_dcerpc_cn_ctx
);
2980 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, ctx_tree
, hdr
->drep
,
2981 hf_dcerpc_cn_ctx_id
, &ctx_id
);
2982 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, ctx_tree
, hdr
->drep
,
2983 hf_dcerpc_cn_num_trans_items
, &num_trans_items
);
2986 proto_item_append_text(ctx_item
, "[%u]: Context ID:%u", i
+1, ctx_id
);
2992 dcerpc_tvb_get_uuid(tvb
, offset
, hdr
->drep
, &if_id
);
2995 iface_item
= proto_tree_add_item(ctx_tree
, hf_dcerpc_cn_bind_abstract_syntax
, tvb
, offset
, 0, ENC_NA
);
2996 iface_tree
= proto_item_add_subtree(iface_item
, ett_dcerpc_cn_iface
);
2998 uuid_str
= guid_to_str((e_guid_t
*)&if_id
);
2999 uuid_name
= guids_get_uuid_name(&if_id
);
3001 proto_tree_add_guid_format(iface_tree
, hf_dcerpc_cn_bind_if_id
, tvb
,
3002 offset
, 16, (e_guid_t
*) &if_id
, "Interface: %s UUID: %s", uuid_name
, uuid_str
);
3003 proto_item_append_text(iface_item
, ": %s", uuid_name
);
3004 proto_item_append_text(ctx_item
, ", %s", uuid_name
);
3006 proto_tree_add_guid_format(iface_tree
, hf_dcerpc_cn_bind_if_id
, tvb
,
3007 offset
, 16, (e_guid_t
*) &if_id
, "Interface UUID: %s", uuid_str
);
3008 proto_item_append_text(iface_item
, ": %s", uuid_str
);
3009 proto_item_append_text(ctx_item
, ", %s", uuid_str
);
3014 if (hdr
->drep
[0] & DREP_LITTLE_ENDIAN
) {
3015 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, iface_tree
, hdr
->drep
,
3016 hf_dcerpc_cn_bind_if_ver
, &if_ver
);
3017 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, iface_tree
, hdr
->drep
,
3018 hf_dcerpc_cn_bind_if_ver_minor
, &if_ver_minor
);
3020 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, iface_tree
, hdr
->drep
,
3021 hf_dcerpc_cn_bind_if_ver_minor
, &if_ver_minor
);
3022 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, iface_tree
, hdr
->drep
,
3023 hf_dcerpc_cn_bind_if_ver
, &if_ver
);
3027 proto_item_append_text(iface_item
, " V%u.%u", if_ver
, if_ver_minor
);
3028 proto_item_set_len(iface_item
, 20);
3031 memset(&trans_id
, 0, sizeof(trans_id
));
3032 for (j
= 0; j
< num_trans_items
; j
++) {
3033 proto_tree
*trans_tree
= NULL
;
3034 proto_item
*trans_item
= NULL
;
3035 proto_item
*uuid_item
= NULL
;
3037 dcerpc_tvb_get_uuid(tvb
, offset
, hdr
->drep
, &trans_id
);
3040 trans_item
= proto_tree_add_item(ctx_tree
, hf_dcerpc_cn_bind_trans_syntax
, tvb
, offset
, 0, ENC_NA
);
3041 trans_tree
= proto_item_add_subtree(trans_item
, ett_dcerpc_cn_trans_syntax
);
3043 uuid_str
= guid_to_str((e_guid_t
*) &trans_id
);
3044 uuid_name
= guids_get_uuid_name(&trans_id
);
3047 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
);
3048 proto_item_append_text(trans_item
, "[%u]: %s", j
+1, uuid_name
);
3049 proto_item_append_text(ctx_item
, ", %s", uuid_name
);
3051 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
);
3052 proto_item_append_text(trans_item
, "[%u]: %s", j
+1, uuid_str
);
3053 proto_item_append_text(ctx_item
, ", %s", uuid_str
);
3056 /* check for [MS-RPCE] 3.3.1.5.3 Bind Time Feature Negotiation */
3057 if (trans_id
.Data1
== 0x6cb71c2c && trans_id
.Data2
== 0x9812 && trans_id
.Data3
== 0x4540) {
3058 proto_tree
*uuid_tree
= proto_item_add_subtree(uuid_item
, ett_dcerpc_cn_trans_btfn
);
3059 proto_tree_add_boolean(uuid_tree
, hf_dcerpc_cn_bind_trans_btfn_01
, tvb
, offset
+8, 1, trans_id
.Data4
[0]);
3060 proto_tree_add_boolean(uuid_tree
, hf_dcerpc_cn_bind_trans_btfn_02
, tvb
, offset
+8, 1, trans_id
.Data4
[0]);
3065 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, trans_tree
, hdr
->drep
,
3066 hf_dcerpc_cn_bind_trans_ver
, &trans_ver
);
3068 proto_item_set_len(trans_item
, 20);
3069 proto_item_append_text(trans_item
, " V%u", trans_ver
);
3073 /* if this is the first time we've seen this packet, we need to
3074 update the dcerpc_binds table so that any later calls can
3075 match to the interface.
3076 XXX We assume that BINDs will NEVER be fragmented.
3078 if (!(pinfo
->fd
->flags
.visited
)) {
3079 dcerpc_bind_key
*key
;
3080 dcerpc_bind_value
*value
;
3082 key
= (dcerpc_bind_key
*)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_key
));
3084 key
->ctx_id
= ctx_id
;
3085 key
->smb_fid
= dcerpc_get_transport_salt(pinfo
);
3087 value
= (dcerpc_bind_value
*)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_value
));
3088 value
->uuid
= if_id
;
3089 value
->ver
= if_ver
;
3090 value
->transport
= trans_id
;
3092 /* add this entry to the bind table */
3093 g_hash_table_insert(dcerpc_binds
, key
, value
);
3097 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ",");
3098 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " %s V%u.%u (%s)",
3099 guids_resolve_uuid_to_str(&if_id
), if_ver
, if_ver_minor
,
3100 guids_resolve_uuid_to_str(&trans_id
));
3103 proto_item_set_len(ctx_item
, offset
- ctx_offset
);
3108 * XXX - we should save the authentication type *if* we have
3109 * an authentication header, and associate it with an authentication
3110 * context, so subsequent PDUs can use that context.
3112 dissect_dcerpc_cn_auth(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
, TRUE
, &auth_info
);
3116 dissect_dcerpc_cn_bind_ack(tvbuff_t
*tvb
, gint offset
, packet_info
*pinfo
,
3117 proto_tree
*dcerpc_tree
, e_dce_cn_common_hdr_t
*hdr
)
3119 guint16 max_xmit
, max_recv
;
3120 guint16 sec_addr_len
;
3127 dcerpc_auth_info auth_info
;
3128 const char *uuid_name
= NULL
;
3129 const char *result_str
= NULL
;
3131 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
3132 hf_dcerpc_cn_max_xmit
, &max_xmit
);
3134 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
3135 hf_dcerpc_cn_max_recv
, &max_recv
);
3137 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
3138 hf_dcerpc_cn_assoc_group
, NULL
);
3140 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
3141 hf_dcerpc_cn_sec_addr_len
, &sec_addr_len
);
3142 if (sec_addr_len
!= 0) {
3143 tvb_ensure_bytes_exist(tvb
, offset
, sec_addr_len
);
3144 proto_tree_add_item(dcerpc_tree
, hf_dcerpc_cn_sec_addr
, tvb
, offset
,
3145 sec_addr_len
, ENC_ASCII
|ENC_NA
);
3146 offset
+= sec_addr_len
;
3150 offset
+= 4 - offset
% 4;
3153 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
3154 hf_dcerpc_cn_num_results
, &num_results
);
3159 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", max_xmit: %u max_recv: %u, %u results:",
3160 max_xmit
, max_recv
, num_results
);
3162 for (i
= 0; i
< num_results
; i
++) {
3163 proto_tree
*ctx_tree
= NULL
;
3164 proto_item
*ctx_item
= NULL
;
3167 ctx_item
= proto_tree_add_text(dcerpc_tree
, tvb
, offset
, 24, "Ctx Item[%u]:", i
+1);
3168 ctx_tree
= proto_item_add_subtree(ctx_item
, ett_dcerpc_cn_ctx
);
3171 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, ctx_tree
,
3172 hdr
->drep
, hf_dcerpc_cn_ack_result
,
3175 /* [MS-RPCE] 3.3.1.5.3 check if this Ctx Item is the response to a Bind Time Feature Negotiation request */
3177 const int old_offset
= offset
;
3178 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, ctx_tree
, hdr
->drep
, hf_dcerpc_cn_ack_btfn
, &reason
);
3179 proto_tree_add_boolean(ctx_tree
, hf_dcerpc_cn_bind_trans_btfn_01
, tvb
, old_offset
, 1, reason
);
3180 proto_tree_add_boolean(ctx_tree
, hf_dcerpc_cn_bind_trans_btfn_02
, tvb
, old_offset
, 1, reason
);
3181 } else if (result
!= 0) {
3182 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, ctx_tree
,
3183 hdr
->drep
, hf_dcerpc_cn_ack_reason
,
3187 * The reason for rejection isn't meaningful, and often isn't
3188 * set, when the syntax was accepted.
3193 result_str
= val_to_str(result
, p_cont_result_vals
, "Unknown result (%u)");
3196 dcerpc_tvb_get_uuid(tvb
, offset
, hdr
->drep
, &trans_id
);
3197 uuid_name
= guids_get_uuid_name(&trans_id
);
3199 uuid_name
= guid_to_str((e_guid_t
*) &trans_id
);
3201 proto_tree_add_guid_format(ctx_tree
, hf_dcerpc_cn_ack_trans_id
, tvb
,
3202 offset
, 16, (e_guid_t
*) &trans_id
, "Transfer Syntax: %s",
3204 proto_item_append_text(ctx_item
, " %s, %s", result_str
, uuid_name
);
3208 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, ctx_tree
, hdr
->drep
,
3209 hf_dcerpc_cn_ack_trans_ver
, &trans_ver
);
3212 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ",");
3213 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " %s", result_str
);
3217 * XXX - do we need to do anything with the authentication level
3218 * we get back from this?
3220 dissect_dcerpc_cn_auth(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
, TRUE
, &auth_info
);
3224 dissect_dcerpc_cn_bind_nak(tvbuff_t
*tvb
, gint offset
, packet_info
*pinfo
,
3225 proto_tree
*dcerpc_tree
, e_dce_cn_common_hdr_t
*hdr
)
3228 guint8 num_protocols
;
3231 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
,
3232 hdr
->drep
, hf_dcerpc_cn_reject_reason
,
3235 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " reason: %s",
3236 val_to_str(reason
, reject_reason_vals
, "Unknown (%u)"));
3238 if (reason
== PROTOCOL_VERSION_NOT_SUPPORTED
) {
3239 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
3240 hf_dcerpc_cn_num_protocols
,
3243 for (i
= 0; i
< num_protocols
; i
++) {
3244 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, dcerpc_tree
,
3245 hdr
->drep
, hf_dcerpc_cn_protocol_ver_major
,
3247 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, dcerpc_tree
,
3248 hdr
->drep
, hf_dcerpc_cn_protocol_ver_minor
,
3254 /* Return a string describing a DCE/RPC fragment as first, middle, or end
3257 #define PFC_FRAG_MASK 0x03
3260 fragment_type(guint8 flags
)
3262 static const char* t
[4] = {
3268 return t
[flags
& PFC_FRAG_MASK
];
3271 /* Dissect stub data (payload) of a DCERPC packet. */
3274 dissect_dcerpc_cn_stub(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
3275 proto_tree
*dcerpc_tree
, proto_tree
*tree
,
3276 e_dce_cn_common_hdr_t
*hdr
, dcerpc_info
*di
,
3277 dcerpc_auth_info
*auth_info
, guint32 alloc_hint _U_
,
3280 gint length
, reported_length
;
3281 gboolean save_fragmented
;
3282 fragment_head
*fd_head
= NULL
;
3284 tvbuff_t
*auth_tvb
, *payload_tvb
, *decrypted_tvb
;
3286 proto_item
*parent_pi
;
3287 proto_item
*dcerpc_tree_item
;
3289 save_fragmented
= pinfo
->fragmented
;
3291 length
= tvb_length_remaining(tvb
, offset
);
3292 reported_length
= tvb_reported_length_remaining(tvb
, offset
);
3293 if (reported_length
< 0 ||
3294 (guint32
)reported_length
< auth_info
->auth_size
) {
3295 /* We don't even have enough bytes for the authentication
3299 reported_length
-= auth_info
->auth_size
;
3300 if (length
> reported_length
)
3301 length
= reported_length
;
3302 payload_tvb
= tvb_new_subset(tvb
, offset
, length
, reported_length
);
3305 /*don't bother if we don't have the entire tvb */
3306 /*XXX we should really make sure we calculate auth_info->auth_data
3307 and use that one instead of this auth_tvb hack
3309 if (tvb_length(tvb
) == tvb_reported_length(tvb
)) {
3310 if (tvb_length_remaining(tvb
, offset
+length
) > 8) {
3311 auth_tvb
= tvb_new_subset_remaining(tvb
, offset
+length
+8);
3315 /* Decrypt the PDU if it is encrypted */
3317 if (auth_info
->auth_type
&&
3318 (auth_info
->auth_level
== DCE_C_AUTHN_LEVEL_PKT_PRIVACY
)) {
3320 * We know the authentication type, and the authentication
3321 * level is "Packet privacy", meaning the payload is
3322 * encrypted; attempt to decrypt it.
3324 dcerpc_auth_subdissector_fns
*auth_fns
;
3326 /* Start out assuming we won't succeed in decrypting. */
3327 decrypted_tvb
= NULL
;
3328 /* Schannel needs information into the footer (verifier) in order to setup decryption keys
3329 * so we call it in order to have a chance to decipher the data
3331 if (DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN
== auth_info
->auth_type
) {
3332 dissect_dcerpc_cn_auth(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
, TRUE
, auth_info
);
3335 if ((auth_fns
= get_auth_subdissector_fns(
3336 auth_info
->auth_level
, auth_info
->auth_type
))) {
3339 result
= decode_encrypted_data(
3340 payload_tvb
, auth_tvb
, pinfo
, auth_fns
,
3341 hdr
->ptype
== PDU_REQ
, auth_info
);
3345 proto_tree_add_text(
3346 dcerpc_tree
, payload_tvb
, 0, -1,
3347 "Encrypted stub data (%d byte%s)",
3348 tvb_reported_length(payload_tvb
),
3350 plurality(tvb_length(payload_tvb
), "", "s"));
3352 add_new_data_source(
3353 pinfo
, result
, "Decrypted stub data");
3356 decrypted_tvb
= result
;
3360 decrypted_tvb
= payload_tvb
;
3362 /* if this packet is not fragmented, just dissect it and exit */
3363 if (PFC_NOT_FRAGMENTED(hdr
)) {
3364 pinfo
->fragmented
= FALSE
;
3367 pinfo
, tree
, dcerpc_tree
, payload_tvb
, decrypted_tvb
,
3368 hdr
->drep
, di
, auth_info
);
3370 pinfo
->fragmented
= save_fragmented
;
3374 /* The packet is fragmented. */
3375 pinfo
->fragmented
= TRUE
;
3377 /* debug output of essential fragment data. */
3378 /* leave it here for future debugging sessions */
3379 /*printf("DCE num:%u offset:%u frag_len:%u tvb_len:%u\n",
3380 pinfo->fd->num, offset, hdr->frag_len, tvb_length(decrypted_tvb));*/
3382 /* if we are not doing reassembly and this is the first fragment
3383 then just dissect it and exit
3384 XXX - if we're not doing reassembly, can we decrypt an
3387 if ( (!dcerpc_reassemble
) && (hdr
->flags
& PFC_FIRST_FRAG
) ) {
3390 pinfo
, tree
, dcerpc_tree
, payload_tvb
, decrypted_tvb
,
3391 hdr
->drep
, di
, auth_info
);
3393 expert_add_info_format(pinfo
, NULL
, &ei_dcerpc_fragment
, "%s fragment", fragment_type(hdr
->flags
));
3395 pinfo
->fragmented
= save_fragmented
;
3399 /* if we have already seen this packet, see if it was reassembled
3400 and if so dissect the full pdu.
3403 if (pinfo
->fd
->flags
.visited
) {
3404 fd_head
= fragment_get_reassembled(&dcerpc_co_reassembly_table
, frame
);
3408 /* if we are not doing reassembly and it was neither a complete PDU
3409 nor the first fragment then there is nothing more we can do
3410 so we just have to exit
3412 if ( !dcerpc_reassemble
|| (tvb_length(tvb
) != tvb_reported_length(tvb
)) )
3415 /* if we didn't get 'frame' we don't know where the PDU started and thus
3416 it is pointless to continue
3421 /* from now on we must attempt to reassemble the PDU
3424 /* if we get here we know it is the first time we see the packet
3425 and we also know it is only a fragment and not a full PDU,
3426 thus we must reassemble it.
3429 /* Do we have any non-encrypted data to reassemble? */
3430 if (decrypted_tvb
== NULL
) {
3431 /* No. We can't even try to reassemble. */
3435 /* defragmentation is a bit tricky, as there's no offset of the fragment
3436 * in the protocol data.
3438 * just use fragment_add_seq_next() and hope that TCP/SMB segments coming
3439 * in with the correct sequence.
3441 fd_head
= fragment_add_seq_next(&dcerpc_co_reassembly_table
,
3442 decrypted_tvb
, 0, pinfo
, frame
, NULL
,
3443 tvb_length(decrypted_tvb
),
3444 hdr
->flags
&PFC_LAST_FRAG
? FALSE
: TRUE
/* more_frags */);
3448 /* if reassembly is complete and this is the last fragment
3449 * (multiple fragments in one PDU are possible!)
3450 * dissect the full PDU
3452 if (fd_head
&& (fd_head
->flags
& FD_DEFRAGMENTED
) ) {
3454 if ((pinfo
->fd
->num
== fd_head
->reassembled_in
) && (hdr
->flags
& PFC_LAST_FRAG
) ) {
3456 proto_item
*frag_tree_item
;
3458 next_tvb
= tvb_new_chain((decrypted_tvb
)?decrypted_tvb
:payload_tvb
,
3461 add_new_data_source(pinfo
, next_tvb
, "Reassembled DCE/RPC");
3462 show_fragment_tree(fd_head
, &dcerpc_frag_items
,
3463 tree
, pinfo
, next_tvb
, &frag_tree_item
);
3464 /* the toplevel fragment subtree is now behind all desegmented data,
3465 * move it right behind the DCE/RPC tree */
3466 dcerpc_tree_item
= proto_tree_get_parent(dcerpc_tree
);
3467 if (frag_tree_item
&& dcerpc_tree_item
) {
3468 proto_tree_move_item(tree
, dcerpc_tree_item
, frag_tree_item
);
3471 pinfo
->fragmented
= FALSE
;
3473 expert_add_info_format(pinfo
, frag_tree_item
, &ei_dcerpc_fragment_reassembled
, "%s fragment, reassembled", fragment_type(hdr
->flags
));
3475 dcerpc_try_handoff(pinfo
, tree
, dcerpc_tree
, next_tvb
,
3476 next_tvb
, hdr
->drep
, di
, auth_info
);
3479 if (decrypted_tvb
) {
3480 pi
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_reassembled_in
,
3481 decrypted_tvb
, 0, 0, fd_head
->reassembled_in
);
3483 pi
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_reassembled_in
,
3484 payload_tvb
, 0, 0, fd_head
->reassembled_in
);
3486 PROTO_ITEM_SET_GENERATED(pi
);
3487 parent_pi
= proto_tree_get_parent(dcerpc_tree
);
3488 if (parent_pi
!= NULL
) {
3489 proto_item_append_text(parent_pi
, ", [Reas: #%u]", fd_head
->reassembled_in
);
3491 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
3492 " [DCE/RPC %s fragment, reas: #%u]", fragment_type(hdr
->flags
), fd_head
->reassembled_in
);
3493 expert_add_info_format(pinfo
, NULL
, &ei_dcerpc_fragment_reassembled
, "%s fragment, reassembled in #%u", fragment_type(hdr
->flags
), fd_head
->reassembled_in
);
3496 /* Reassembly not complete - some fragments
3497 are missing. Just show the stub data. */
3498 expert_add_info_format(pinfo
, NULL
, &ei_dcerpc_fragment
, "%s fragment", fragment_type(hdr
->flags
));
3500 if (decrypted_tvb
) {
3501 show_stub_data(decrypted_tvb
, 0, tree
, auth_info
, FALSE
);
3503 show_stub_data(payload_tvb
, 0, tree
, auth_info
, TRUE
);
3507 pinfo
->fragmented
= save_fragmented
;
3511 * Registers a conversation/UUID binding association, so that
3512 * we can invoke the proper sub-dissector for a given DCERPC
3515 * @param binding all values needed to create and bind a new conversation
3517 * @return Pointer to newly-added UUID/conversation binding.
3519 struct _dcerpc_bind_value
*
3520 dcerpc_add_conv_to_bind_table(decode_dcerpc_bind_values_t
*binding
)
3522 dcerpc_bind_value
*bind_value
;
3523 dcerpc_bind_key
*key
;
3524 conversation_t
*conv
;
3526 conv
= find_conversation(
3536 conv
= conversation_new(
3546 bind_value
= (dcerpc_bind_value
*)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_value
));
3547 bind_value
->uuid
= binding
->uuid
;
3548 bind_value
->ver
= binding
->ver
;
3549 /* For now, assume all DCE/RPC we pick from "decode as" is using
3550 standard ndr and not ndr64.
3551 We should make this selectable from the dialog in the future
3553 bind_value
->transport
= uuid_data_repr_proto
;
3555 key
= (dcerpc_bind_key
*)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_key
));
3557 key
->ctx_id
= binding
->ctx_id
;
3558 key
->smb_fid
= binding
->smb_fid
;
3560 /* add this entry to the bind table */
3561 g_hash_table_insert(dcerpc_binds
, key
, bind_value
);
3568 dissect_dcerpc_cn_rqst(tvbuff_t
*tvb
, gint offset
, packet_info
*pinfo
,
3569 proto_tree
*dcerpc_tree
, proto_tree
*tree
,
3570 e_dce_cn_common_hdr_t
*hdr
)
3572 conversation_t
*conv
;
3575 e_uuid_t obj_id
= DCERPC_UUID_NULL
;
3576 dcerpc_auth_info auth_info
;
3579 proto_item
*parent_pi
;
3581 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
3582 hf_dcerpc_cn_alloc_hint
, &alloc_hint
);
3584 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
3585 hf_dcerpc_cn_ctx_id
, &ctx_id
);
3586 parent_pi
= proto_tree_get_parent(dcerpc_tree
);
3587 if (parent_pi
!= NULL
) {
3588 proto_item_append_text(parent_pi
, ", Ctx: %u", ctx_id
);
3591 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
3592 hf_dcerpc_opnum
, &opnum
);
3594 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3595 pinfo
->dcectxid
= ctx_id
;
3597 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", opnum: %u, Ctx: %u",
3600 if (hdr
->flags
& PFC_OBJECT_UUID
) {
3601 dcerpc_tvb_get_uuid(tvb
, offset
, hdr
->drep
, &obj_id
);
3603 proto_tree_add_guid_format(dcerpc_tree
, hf_dcerpc_obj_id
, tvb
,
3604 offset
, 16, (e_guid_t
*) &obj_id
, "Object UUID: %s",
3605 guid_to_str((e_guid_t
*) &obj_id
));
3611 * XXX - what if this was set when the connection was set up,
3612 * and we just have a security context?
3614 dissect_dcerpc_cn_auth(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
, FALSE
, &auth_info
);
3616 conv
= find_conversation(pinfo
->fd
->num
, &pinfo
->src
, &pinfo
->dst
, pinfo
->ptype
,
3617 pinfo
->srcport
, pinfo
->destport
, 0);
3619 show_stub_data(tvb
, offset
, dcerpc_tree
, &auth_info
, TRUE
);
3621 dcerpc_matched_key matched_key
, *new_matched_key
;
3622 dcerpc_call_value
*value
;
3624 /* !!! we can NOT check flags.visited here since this will interact
3625 badly with when SMB handles (i.e. calls the subdissector)
3626 and desegmented pdu's .
3627 Instead we check if this pdu is already in the matched table or not
3629 matched_key
.frame
= pinfo
->fd
->num
;
3630 matched_key
.call_id
= hdr
->call_id
;
3631 value
= (dcerpc_call_value
*)g_hash_table_lookup(dcerpc_matched
, &matched_key
);
3633 dcerpc_bind_key bind_key
;
3634 dcerpc_bind_value
*bind_value
;
3636 bind_key
.conv
= conv
;
3637 bind_key
.ctx_id
= ctx_id
;
3638 bind_key
.smb_fid
= dcerpc_get_transport_salt(pinfo
);
3640 if ((bind_value
= (dcerpc_bind_value
*)g_hash_table_lookup(dcerpc_binds
, &bind_key
)) ) {
3641 if (!(hdr
->flags
&PFC_FIRST_FRAG
)) {
3642 dcerpc_cn_call_key call_key
;
3643 dcerpc_call_value
*call_value
;
3645 call_key
.conv
= conv
;
3646 call_key
.call_id
= hdr
->call_id
;
3647 call_key
.smb_fid
= dcerpc_get_transport_salt(pinfo
);
3648 if ((call_value
= (dcerpc_call_value
*)g_hash_table_lookup(dcerpc_cn_calls
, &call_key
))) {
3649 new_matched_key
= (dcerpc_matched_key
*)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key
));
3650 *new_matched_key
= matched_key
;
3651 g_hash_table_insert(dcerpc_matched
, new_matched_key
, call_value
);
3655 dcerpc_cn_call_key
*call_key
;
3656 dcerpc_call_value
*call_value
;
3658 /* We found the binding and it is the first fragment
3659 (or a complete PDU) of a dcerpc pdu so just add
3660 the call to both the call table and the
3663 call_key
= (dcerpc_cn_call_key
*)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_cn_call_key
));
3664 call_key
->conv
= conv
;
3665 call_key
->call_id
= hdr
->call_id
;
3666 call_key
->smb_fid
= dcerpc_get_transport_salt(pinfo
);
3668 /* if there is already a matching call in the table
3669 remove it so it is replaced with the new one */
3670 if (g_hash_table_lookup(dcerpc_cn_calls
, call_key
)) {
3671 g_hash_table_remove(dcerpc_cn_calls
, call_key
);
3674 call_value
= (dcerpc_call_value
*)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_call_value
));
3675 call_value
->uuid
= bind_value
->uuid
;
3676 call_value
->ver
= bind_value
->ver
;
3677 call_value
->object_uuid
= obj_id
;
3678 call_value
->opnum
= opnum
;
3679 call_value
->req_frame
= pinfo
->fd
->num
;
3680 call_value
->req_time
= pinfo
->fd
->abs_ts
;
3681 call_value
->rep_frame
= 0;
3682 call_value
->max_ptr
= 0;
3683 call_value
->se_data
= NULL
;
3684 call_value
->private_data
= NULL
;
3685 call_value
->pol
= NULL
;
3686 call_value
->flags
= 0;
3687 if (!memcmp(&bind_value
->transport
, &uuid_ndr64
, sizeof(uuid_ndr64
))) {
3688 call_value
->flags
|= DCERPC_IS_NDR64
;
3691 g_hash_table_insert(dcerpc_cn_calls
, call_key
, call_value
);
3693 new_matched_key
= (dcerpc_matched_key
*)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key
));
3694 *new_matched_key
= matched_key
;
3695 g_hash_table_insert(dcerpc_matched
, new_matched_key
, call_value
);
3705 /* handoff this call */
3707 di
->call_id
= hdr
->call_id
;
3708 di
->smb_fid
= dcerpc_get_transport_salt(pinfo
);
3709 di
->ptype
= PDU_REQ
;
3710 di
->call_data
= value
;
3713 if (value
->rep_frame
!= 0) {
3714 pi
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_response_in
,
3715 tvb
, 0, 0, value
->rep_frame
);
3716 PROTO_ITEM_SET_GENERATED(pi
);
3717 if (parent_pi
!= NULL
) {
3718 proto_item_append_text(parent_pi
, ", [Resp: #%u]", value
->rep_frame
);
3722 dissect_dcerpc_cn_stub(tvb
, offset
, pinfo
, dcerpc_tree
, tree
,
3723 hdr
, di
, &auth_info
, alloc_hint
,
3726 /* no bind information, simply show stub data */
3727 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
);
3728 show_stub_data(tvb
, offset
, dcerpc_tree
, &auth_info
, TRUE
);
3732 /* Dissect the verifier */
3733 dissect_dcerpc_verifier(tvb
, pinfo
, dcerpc_tree
, hdr
, &auth_info
);
3738 dissect_dcerpc_cn_resp(tvbuff_t
*tvb
, gint offset
, packet_info
*pinfo
,
3739 proto_tree
*dcerpc_tree
, proto_tree
*tree
,
3740 e_dce_cn_common_hdr_t
*hdr
)
3742 dcerpc_call_value
*value
= NULL
;
3743 conversation_t
*conv
;
3745 dcerpc_auth_info auth_info
;
3748 proto_item
*parent_pi
;
3749 e_uuid_t obj_id_null
= DCERPC_UUID_NULL
;
3751 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
3752 hf_dcerpc_cn_alloc_hint
, &alloc_hint
);
3754 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
3755 hf_dcerpc_cn_ctx_id
, &ctx_id
);
3756 parent_pi
= proto_tree_get_parent(dcerpc_tree
);
3757 if (parent_pi
!= NULL
) {
3758 proto_item_append_text(parent_pi
, ", Ctx: %u", ctx_id
);
3761 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3762 pinfo
->dcectxid
= ctx_id
;
3764 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", Ctx: %u", ctx_id
);
3766 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
3767 hf_dcerpc_cn_cancel_count
, NULL
);
3772 * XXX - what if this was set when the connection was set up,
3773 * and we just have a security context?
3775 dissect_dcerpc_cn_auth(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
, FALSE
, &auth_info
);
3777 conv
= find_conversation(pinfo
->fd
->num
, &pinfo
->src
, &pinfo
->dst
, pinfo
->ptype
,
3778 pinfo
->srcport
, pinfo
->destport
, 0);
3781 /* no point in creating one here, really */
3782 show_stub_data(tvb
, offset
, dcerpc_tree
, &auth_info
, TRUE
);
3784 dcerpc_matched_key matched_key
, *new_matched_key
;
3786 /* !!! we can NOT check flags.visited here since this will interact
3787 badly with when SMB handles (i.e. calls the subdissector)
3788 and desegmented pdu's .
3789 Instead we check if this pdu is already in the matched table or not
3791 matched_key
.frame
= pinfo
->fd
->num
;
3792 matched_key
.call_id
= hdr
->call_id
;
3793 value
= (dcerpc_call_value
*)g_hash_table_lookup(dcerpc_matched
, &matched_key
);
3795 dcerpc_cn_call_key call_key
;
3796 dcerpc_call_value
*call_value
;
3798 call_key
.conv
= conv
;
3799 call_key
.call_id
= hdr
->call_id
;
3800 call_key
.smb_fid
= dcerpc_get_transport_salt(pinfo
);
3802 if ((call_value
= (dcerpc_call_value
*)g_hash_table_lookup(dcerpc_cn_calls
, &call_key
))) {
3803 /* extra sanity check, only match them if the reply
3804 came after the request */
3805 if (call_value
->req_frame
<pinfo
->fd
->num
) {
3806 new_matched_key
= (dcerpc_matched_key
*)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key
));
3807 *new_matched_key
= matched_key
;
3808 g_hash_table_insert(dcerpc_matched
, new_matched_key
, call_value
);
3810 if (call_value
->rep_frame
== 0) {
3811 call_value
->rep_frame
= pinfo
->fd
->num
;
3821 /* handoff this call */
3823 di
->call_id
= hdr
->call_id
;
3824 di
->smb_fid
= dcerpc_get_transport_salt(pinfo
);
3825 di
->ptype
= PDU_RESP
;
3826 di
->call_data
= value
;
3828 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_opnum
, tvb
, 0, 0, value
->opnum
);
3830 /* (optional) "Object UUID" from request */
3831 if (dcerpc_tree
&& (memcmp(&value
->object_uuid
, &obj_id_null
, sizeof(obj_id_null
)) != 0)) {
3832 pi
= proto_tree_add_guid_format(dcerpc_tree
, hf_dcerpc_obj_id
, tvb
,
3833 offset
, 0, (e_guid_t
*) &value
->object_uuid
, "Object UUID: %s",
3834 guid_to_str((e_guid_t
*) &value
->object_uuid
));
3835 PROTO_ITEM_SET_GENERATED(pi
);
3839 if (value
->req_frame
!= 0) {
3841 pi
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_request_in
,
3842 tvb
, 0, 0, value
->req_frame
);
3843 PROTO_ITEM_SET_GENERATED(pi
);
3844 if (parent_pi
!= NULL
) {
3845 proto_item_append_text(parent_pi
, ", [Req: #%u]", value
->req_frame
);
3847 nstime_delta(&delta_ts
, &pinfo
->fd
->abs_ts
, &value
->req_time
);
3848 pi
= proto_tree_add_time(dcerpc_tree
, hf_dcerpc_time
, tvb
, offset
, 0, &delta_ts
);
3849 PROTO_ITEM_SET_GENERATED(pi
);
3851 proto_tree_add_expert(dcerpc_tree
, pinfo
, &ei_dcerpc_no_request_found
, tvb
, 0, 0);
3854 dissect_dcerpc_cn_stub(tvb
, offset
, pinfo
, dcerpc_tree
, tree
,
3855 hdr
, di
, &auth_info
, alloc_hint
,
3858 /* no bind information, simply show stub data */
3859 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
);
3860 show_stub_data(tvb
, offset
, dcerpc_tree
, &auth_info
, TRUE
);
3864 /* Dissect the verifier */
3865 dissect_dcerpc_verifier(tvb
, pinfo
, dcerpc_tree
, hdr
, &auth_info
);
3869 dissect_dcerpc_cn_fault(tvbuff_t
*tvb
, gint offset
, packet_info
*pinfo
,
3870 proto_tree
*dcerpc_tree
, e_dce_cn_common_hdr_t
*hdr
)
3872 dcerpc_call_value
*value
= NULL
;
3873 conversation_t
*conv
;
3877 dcerpc_auth_info auth_info
;
3878 proto_item
*pi
= NULL
;
3880 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
3881 hf_dcerpc_cn_alloc_hint
, &alloc_hint
);
3883 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
3884 hf_dcerpc_cn_ctx_id
, &ctx_id
);
3886 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
3887 hf_dcerpc_cn_cancel_count
, NULL
);
3892 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
3893 hf_dcerpc_cn_status
, &status
);
3895 status
= ((hdr
->drep
[0] & DREP_LITTLE_ENDIAN
)
3896 ? tvb_get_letohl(tvb
, offset
)
3897 : tvb_get_ntohl(tvb
, offset
));
3899 pi
= proto_tree_add_item(dcerpc_tree
, hf_dcerpc_cn_status
, tvb
, offset
, 4, DREP_ENC_INTEGER(hdr
->drep
));
3902 expert_add_info_format(pinfo
, pi
, &ei_dcerpc_cn_status
, "Fault: %s", val_to_str(status
, reject_status_vals
, "Unknown (0x%08x)"));
3904 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3905 pinfo
->dcectxid
= ctx_id
;
3907 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
3908 ", Ctx: %u, status: %s", ctx_id
,
3909 val_to_str(status
, reject_status_vals
,
3910 "Unknown (0x%08x)"));
3916 * XXX - what if this was set when the connection was set up,
3917 * and we just have a security context?
3919 dissect_dcerpc_cn_auth(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
, FALSE
, &auth_info
);
3921 conv
= find_conversation(pinfo
->fd
->num
, &pinfo
->src
, &pinfo
->dst
, pinfo
->ptype
,
3922 pinfo
->srcport
, pinfo
->destport
, 0);
3924 /* no point in creating one here, really */
3926 dcerpc_matched_key matched_key
, *new_matched_key
;
3928 /* !!! we can NOT check flags.visited here since this will interact
3929 badly with when SMB handles (i.e. calls the subdissector)
3930 and desegmented pdu's .
3931 Instead we check if this pdu is already in the matched table or not
3933 matched_key
.frame
= pinfo
->fd
->num
;
3934 matched_key
.call_id
= hdr
->call_id
;
3935 value
= (dcerpc_call_value
*)g_hash_table_lookup(dcerpc_matched
, &matched_key
);
3937 dcerpc_cn_call_key call_key
;
3938 dcerpc_call_value
*call_value
;
3940 call_key
.conv
= conv
;
3941 call_key
.call_id
= hdr
->call_id
;
3942 call_key
.smb_fid
= dcerpc_get_transport_salt(pinfo
);
3944 if ((call_value
= (dcerpc_call_value
*)g_hash_table_lookup(dcerpc_cn_calls
, &call_key
))) {
3945 new_matched_key
= (dcerpc_matched_key
*)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key
));
3946 *new_matched_key
= matched_key
;
3947 g_hash_table_insert(dcerpc_matched
, new_matched_key
, call_value
);
3950 if (call_value
->rep_frame
== 0) {
3951 call_value
->rep_frame
= pinfo
->fd
->num
;
3958 int length
, stub_length
;
3960 proto_item
*parent_pi
;
3963 /* handoff this call */
3965 di
->call_id
= hdr
->call_id
;
3966 di
->smb_fid
= dcerpc_get_transport_salt(pinfo
);
3967 di
->ptype
= PDU_FAULT
;
3968 di
->call_data
= value
;
3970 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_opnum
, tvb
, 0, 0, value
->opnum
);
3971 if (value
->req_frame
!= 0) {
3973 pi
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_request_in
,
3974 tvb
, 0, 0, value
->req_frame
);
3975 PROTO_ITEM_SET_GENERATED(pi
);
3976 parent_pi
= proto_tree_get_parent(dcerpc_tree
);
3977 if (parent_pi
!= NULL
) {
3978 proto_item_append_text(parent_pi
, ", [Req: #%u]", value
->req_frame
);
3980 nstime_delta(&delta_ts
, &pinfo
->fd
->abs_ts
, &value
->req_time
);
3981 pi
= proto_tree_add_time(dcerpc_tree
, hf_dcerpc_time
, tvb
, offset
, 0, &delta_ts
);
3982 PROTO_ITEM_SET_GENERATED(pi
);
3984 proto_tree_add_expert(dcerpc_tree
, pinfo
, &ei_dcerpc_no_request_found
, tvb
, 0, 0);
3987 length
= tvb_length_remaining(tvb
, offset
);
3988 /* as we now create a tvb in dissect_dcerpc_cn() containing only the
3989 * stub_data, the following calculation is no longer valid:
3990 * stub_length = hdr->frag_len - offset - auth_info.auth_size;
3991 * simply use the remaining length of the tvb instead.
3992 * XXX - or better use the reported_length?!?
3994 stub_length
= length
;
3995 if (length
> stub_length
)
3996 length
= stub_length
;
3998 /* If we don't have reassembly enabled, or this packet contains
3999 the entire PDU, or if we don't have all the data in this
4000 fragment, just call the handoff directly if this is the
4001 first fragment or the PDU isn't fragmented. */
4002 if ( (!dcerpc_reassemble
) || PFC_NOT_FRAGMENTED(hdr
) ||
4003 !tvb_bytes_exist(tvb
, offset
, stub_length
) ) {
4004 if (hdr
->flags
&PFC_FIRST_FRAG
) {
4005 /* First fragment, possibly the only fragment */
4007 * XXX - should there be a third routine for each
4008 * function in an RPC subdissector, to handle
4009 * fault responses? The DCE RPC 1.1 spec says
4010 * three's "stub data" here, which I infer means
4011 * that it's protocol-specific and call-specific.
4013 * It should probably get passed the status code
4014 * as well, as that might be protocol-specific.
4017 if (stub_length
> 0) {
4018 tvb_ensure_bytes_exist(tvb
, offset
, stub_length
);
4019 proto_tree_add_text(dcerpc_tree
, tvb
, offset
, stub_length
,
4020 "Fault stub data (%d byte%s)",
4022 plurality(stub_length
, "", "s"));
4026 /* PDU is fragmented and this isn't the first fragment */
4028 if (stub_length
> 0) {
4029 tvb_ensure_bytes_exist(tvb
, offset
, stub_length
);
4030 proto_tree_add_text(dcerpc_tree
, tvb
, offset
, stub_length
,
4031 "Fragment data (%d byte%s)",
4033 plurality(stub_length
, "", "s"));
4038 /* Reassembly is enabled, the PDU is fragmented, and
4039 we have all the data in the fragment; the first two
4040 of those mean we should attempt reassembly, and the
4041 third means we can attempt reassembly. */
4044 tvb_ensure_bytes_exist(tvb
, offset
, stub_length
);
4045 proto_tree_add_text(dcerpc_tree
, tvb
, offset
, stub_length
,
4046 "Fragment data (%d byte%s)",
4048 plurality(stub_length
, "", "s"));
4051 if (hdr
->flags
&PFC_FIRST_FRAG
) { /* FIRST fragment */
4052 if ( (!pinfo
->fd
->flags
.visited
) && value
->rep_frame
) {
4053 fragment_add_seq_next(&dcerpc_co_reassembly_table
,
4055 pinfo
, value
->rep_frame
, NULL
,
4059 } else if (hdr
->flags
&PFC_LAST_FRAG
) { /* LAST fragment */
4060 if ( value
->rep_frame
) {
4061 fragment_head
*fd_head
;
4063 fd_head
= fragment_add_seq_next(&dcerpc_co_reassembly_table
,
4065 pinfo
, value
->rep_frame
, NULL
,
4070 /* We completed reassembly */
4072 proto_item
*frag_tree_item
;
4074 next_tvb
= tvb_new_chain(tvb
, fd_head
->tvb_data
);
4075 add_new_data_source(pinfo
, next_tvb
, "Reassembled DCE/RPC");
4076 show_fragment_tree(fd_head
, &dcerpc_frag_items
,
4077 dcerpc_tree
, pinfo
, next_tvb
, &frag_tree_item
);
4080 * XXX - should there be a third routine for each
4081 * function in an RPC subdissector, to handle
4082 * fault responses? The DCE RPC 1.1 spec says
4083 * three's "stub data" here, which I infer means
4084 * that it's protocol-specific and call-specific.
4086 * It should probably get passed the status code
4087 * as well, as that might be protocol-specific.
4091 tvb_ensure_bytes_exist(tvb
, offset
, stub_length
);
4092 proto_tree_add_text(dcerpc_tree
, tvb
, offset
, stub_length
,
4093 "Fault stub data (%d byte%s)",
4095 plurality(stub_length
, "", "s"));
4100 } else { /* MIDDLE fragment(s) */
4101 if ( (!pinfo
->fd
->flags
.visited
) && value
->rep_frame
) {
4102 fragment_add_seq_next(&dcerpc_co_reassembly_table
,
4104 pinfo
, value
->rep_frame
, NULL
,
4115 dissect_dcerpc_cn_rts(tvbuff_t
*tvb
, gint offset
, packet_info
*pinfo
,
4116 proto_tree
*dcerpc_tree
, e_dce_cn_common_hdr_t
*hdr
)
4118 proto_item
*tf
= NULL
;
4119 proto_item
*parent_pi
= NULL
;
4120 proto_tree
*cn_rts_pdu_tree
= NULL
;
4122 guint16 commands_nb
= 0;
4125 const char *info_str
= NULL
;
4127 /* Dissect specific RTS header */
4128 rts_flags
= dcerpc_tvb_get_ntohs(tvb
, offset
, hdr
->drep
);
4130 proto_tree
*cn_rts_flags_tree
;
4132 tf
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_cn_rts_flags
, tvb
, offset
, 2, rts_flags
);
4133 cn_rts_flags_tree
= proto_item_add_subtree(tf
, ett_dcerpc_cn_rts_flags
);
4134 proto_tree_add_boolean(cn_rts_flags_tree
, hf_dcerpc_cn_rts_flags_none
, tvb
, offset
, 1, rts_flags
);
4135 proto_tree_add_boolean(cn_rts_flags_tree
, hf_dcerpc_cn_rts_flags_ping
, tvb
, offset
, 1, rts_flags
);
4136 proto_tree_add_boolean(cn_rts_flags_tree
, hf_dcerpc_cn_rts_flags_other_cmd
, tvb
, offset
, 1, rts_flags
);
4137 proto_tree_add_boolean(cn_rts_flags_tree
, hf_dcerpc_cn_rts_flags_recycle_channel
, tvb
, offset
, 1, rts_flags
);
4138 proto_tree_add_boolean(cn_rts_flags_tree
, hf_dcerpc_cn_rts_flags_in_channel
, tvb
, offset
, 1, rts_flags
);
4139 proto_tree_add_boolean(cn_rts_flags_tree
, hf_dcerpc_cn_rts_flags_out_channel
, tvb
, offset
, 1, rts_flags
);
4140 proto_tree_add_boolean(cn_rts_flags_tree
, hf_dcerpc_cn_rts_flags_eof
, tvb
, offset
, 1, rts_flags
);
4144 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
, hdr
->drep
,
4145 hf_dcerpc_cn_rts_commands_nb
, &commands_nb
);
4147 /* Create the RTS PDU tree - we do not yet know its name */
4148 tf
= proto_tree_add_text(dcerpc_tree
, tvb
, offset
, tvb_length_remaining(tvb
, offset
), "RTS PDU: %u commands", commands_nb
);
4149 cn_rts_pdu_tree
= proto_item_add_subtree(tf
, ett_dcerpc_cn_rts_pdu
);
4151 cmd
= (guint32
*)wmem_alloc(wmem_packet_scope(), sizeof (guint32
) * (commands_nb
+ 1));
4153 /* Dissect commands */
4154 for (i
= 0; i
< commands_nb
; ++i
) {
4155 proto_tree
*cn_rts_command_tree
= NULL
;
4156 const guint32 command
= dcerpc_tvb_get_ntohl(tvb
, offset
, hdr
->drep
);
4158 tf
= proto_tree_add_uint(cn_rts_pdu_tree
, hf_dcerpc_cn_rts_command
, tvb
, offset
, 4, command
);
4159 cn_rts_command_tree
= proto_item_add_subtree(tf
, ett_dcerpc_cn_rts_command
);
4162 case RTS_CMD_RECEIVEWINDOWSIZE
:
4163 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_receivewindowsize
, NULL
);
4165 case RTS_CMD_FLOWCONTROLACK
:
4166 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_fack_bytesreceived
, NULL
);
4167 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_fack_availablewindow
, NULL
);
4168 offset
= dissect_dcerpc_uuid_t(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_fack_channelcookie
, NULL
);
4170 case RTS_CMD_CONNECTIONTIMEOUT
:
4171 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_connectiontimeout
, NULL
);
4173 case RTS_CMD_COOKIE
:
4174 offset
= dissect_dcerpc_uuid_t(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_cookie
, NULL
);
4176 case RTS_CMD_CHANNELLIFETIME
:
4177 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_channellifetime
, NULL
);
4179 case RTS_CMD_CLIENTKEEPALIVE
:
4180 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_clientkeepalive
, NULL
);
4182 case RTS_CMD_VERSION
:
4183 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_version
, NULL
);
4187 case RTS_CMD_PADDING
: {
4189 const guint32 conformance_count
= dcerpc_tvb_get_ntohl(tvb
, offset
, hdr
->drep
);
4190 proto_tree_add_uint(cn_rts_command_tree
, hf_dcerpc_cn_rts_command_conformancecount
, tvb
, offset
, 4, conformance_count
);
4192 padding
= (guint8
*)tvb_memdup(NULL
, tvb
, offset
, conformance_count
);
4193 proto_tree_add_bytes(cn_rts_command_tree
, hf_dcerpc_cn_rts_command_padding
, tvb
, offset
, conformance_count
, padding
);
4194 offset
+= conformance_count
;
4196 case RTS_CMD_NEGATIVEANCE
:
4200 case RTS_CMD_CLIENTADDRESS
: {
4202 const guint32 addrtype
= dcerpc_tvb_get_ntohl(tvb
, offset
, hdr
->drep
);
4203 proto_tree_add_uint(cn_rts_command_tree
, hf_dcerpc_cn_rts_command_addrtype
, tvb
, offset
, 4, addrtype
);
4207 const guint32 addr4
= tvb_get_ipv4(tvb
, offset
);
4208 proto_tree_add_text(cn_rts_command_tree
, tvb
, offset
, 4, "%s", get_hostname(addr4
));
4212 struct e_in6_addr addr6
;
4213 tvb_get_ipv6(tvb
, offset
, &addr6
);
4214 proto_tree_add_text(cn_rts_command_tree
, tvb
, offset
, 16, "%s", get_hostname6(&addr6
));
4218 padding
= (guint8
*)tvb_memdup(NULL
, tvb
, offset
, 12);
4219 proto_tree_add_bytes(cn_rts_command_tree
, hf_dcerpc_cn_rts_command_padding
, tvb
, offset
, 12, padding
);
4222 case RTS_CMD_ASSOCIATIONGROUPID
:
4223 offset
= dissect_dcerpc_uuid_t(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_associationgroupid
, NULL
);
4225 case RTS_CMD_DESTINATION
:
4226 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_forwarddestination
, NULL
);
4228 case RTS_CMD_PINGTRAFFICSENTNOTIFY
:
4229 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, cn_rts_command_tree
, hdr
->drep
, hf_dcerpc_cn_rts_command_pingtrafficsentnotify
, NULL
);
4232 proto_tree_add_text(cn_rts_command_tree
, tvb
, offset
, 0, "unknown RTS command number");
4237 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "RPCH");
4239 /* Define which PDU Body we are dealing with */
4240 info_str
= "unknown RTS PDU";
4242 switch (rts_flags
) {
4244 switch (commands_nb
) {
4246 if (cmd
[0] == 0x2) {
4247 info_str
= "CONN/A3";
4248 } else if (cmd
[0] == 0x3) {
4249 info_str
= "IN_R1/A5,IN_R1/A6,IN_R2/A2,IN_R2/A5,OUT_R2/A4";
4250 } else if (cmd
[0] == 0x7) {
4251 info_str
= "IN_R1/B1";
4252 } else if (cmd
[0] == 0x0) {
4253 info_str
= "IN_R1/B2";
4254 } else if (cmd
[0] == 0xD) {
4255 info_str
= "IN_R2/A3,IN_R2/A4";
4256 } else if (cmd
[0] == 0xA) {
4257 info_str
= "OUT_R1/A9,OUT_R1/A10,OUT_R1/A11,OUT_R2/B1,OUT_R2/B2";
4261 if ((cmd
[0] == 0x0) && (cmd
[1] == 0x6)) {
4262 info_str
= "CONN/B3";
4263 } else if ((cmd
[0] == 0xD) && (cmd
[1] == 0xA)) {
4264 info_str
= "OUT_R2/A5,OUT_R2/A6";
4268 if ((cmd
[0] == 0x6) && (cmd
[1] == 0x0) && (cmd
[2] == 0x2)) {
4269 info_str
= "CONN/C1,CONN/C2";
4273 if ((cmd
[0] == 0x6) && (cmd
[1] == 0x3) && (cmd
[2] == 0x3) && (cmd
[3] == 0x0)) {
4274 info_str
= "CONN/A1";
4275 } else if ((cmd
[0] == 0xD) && (cmd
[1] == 0x6) && (cmd
[2] == 0x0) && (cmd
[3] == 0x2)) {
4276 info_str
= "IN_R1/A3,IN_R1/A4";
4280 if ((cmd
[0] == 0x6) && (cmd
[1] == 0x3) && (cmd
[2] == 0x3) && (cmd
[3] == 0x4) && (cmd
[4] == 0x5) && (cmd
[5] == 0xC)) {
4281 info_str
= "CONN/B1";
4289 switch (commands_nb
) {
4294 if ((cmd
[0] == 0x7) || (cmd
[0] == 0x8)) {
4295 info_str
= "OUT_R2/C1";
4302 case RTS_FLAG_OTHER_CMD
:
4303 switch (commands_nb
) {
4305 if (cmd
[0] == 0x5) {
4306 info_str
= "Keep-Alive";
4307 } else if (cmd
[0] == 0xE) {
4308 info_str
= "PingTrafficSentNotify";
4309 } else if (cmd
[0] == 0x1) {
4310 info_str
= "FlowControlAck";
4314 if ((cmd
[0] == 0xD) && (cmd
[1] == 0x1)) {
4315 info_str
= "FlowControlAckWithDestination";
4322 case RTS_FLAG_RECYCLE_CHANNEL
:
4323 switch (commands_nb
) {
4325 if (cmd
[0] == 0xD) {
4326 info_str
= "OUT_R1/A1,OUT_R1/A2,OUT_R2/A1,OUT_R2/A2";
4330 if ((cmd
[0] == 0x6) && (cmd
[1] == 0x3) && (cmd
[2] == 0x3) && (cmd
[3] == 0x3)) {
4331 info_str
= "IN_R1/A1,IN_R2/A1";
4335 if ((cmd
[0] == 0x6) && (cmd
[1] == 0x3) && (cmd
[2] == 0x3) && (cmd
[3] == 0x3) && (cmd
[4] == 0x0)) {
4336 info_str
= "OUT_R1/A3,OUT_R2/A3";
4343 case RTS_FLAG_IN_CHANNEL
|RTS_FLAG_RECYCLE_CHANNEL
:
4344 switch (commands_nb
) {
4346 if ((cmd
[0] == 0x6) && (cmd
[1] == 0x3) && (cmd
[2] == 0x3) && (cmd
[3] == 0x3) && (cmd
[4] == 0x0) && (cmd
[5] == 0x2)) {
4347 info_str
= "IN_R1/A2";
4353 case RTS_FLAG_IN_CHANNEL
:
4354 switch (commands_nb
) {
4356 if ((cmd
[0] == 0x6) && (cmd
[1] == 0x3) && (cmd
[2] == 0x3) && (cmd
[3] == 0x0) && (cmd
[4] == 0x2) && (cmd
[5] == 0xC) && (cmd
[6] == 0xB)) {
4357 info_str
= "CONN/B2";
4363 case RTS_FLAG_OUT_CHANNEL
|RTS_FLAG_RECYCLE_CHANNEL
:
4364 switch (commands_nb
) {
4366 if ((cmd
[0] == 0x6) && (cmd
[1] == 0x3) && (cmd
[2] == 0x3) && (cmd
[3] == 0x3) && (cmd
[4] == 0x4) && (cmd
[5] == 0) && (cmd
[6] == 0x2)) {
4367 info_str
= "OUT_R1/A4";
4374 case RTS_FLAG_OUT_CHANNEL
:
4375 switch (commands_nb
) {
4377 if ((cmd
[0] == 0xD) && (cmd
[1] == 0x3)) {
4378 info_str
= "OUT_R1/A7,OUT_R1/A8,OUT_R2/A8";
4382 if ((cmd
[0] == 0xD) && (cmd
[1] == 0x6) && (cmd
[2] == 0x2)) {
4383 info_str
= "OUT_R1/A5,OUT_R1/A6";
4384 } else if ((cmd
[0] == 0xD) && (cmd
[1] == 0x3) && (cmd
[2] == 0x6)) {
4385 info_str
= "OUT_R2/A7";
4389 if ((cmd
[0] == 0x6) && (cmd
[1] == 0x3) && (cmd
[2] == 0x3) && (cmd
[3] == 0x4) && (cmd
[4] == 0x0)) {
4390 info_str
= "CONN/A2";
4397 switch (commands_nb
) {
4399 if (cmd
[0] == 0xA) {
4400 info_str
= "OUT_R2/B3";
4408 switch (commands_nb
) {
4420 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "%s, ", info_str
);
4421 col_set_fence(pinfo
->cinfo
,COL_INFO
);
4423 parent_pi
= proto_tree_get_parent(dcerpc_tree
);
4424 if (parent_pi
!= NULL
) {
4425 proto_item_append_text(parent_pi
, ", %s", info_str
);
4430 * DCERPC dissector for connection oriented calls.
4431 * We use transport type to later multiplex between what kind of
4432 * pinfo->private_data structure to expect.
4435 dissect_dcerpc_cn(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
4436 proto_tree
*tree
, gboolean can_desegment
, int *pkt_len
)
4438 static const guint8 nulls
[4] = { 0 };
4442 proto_item
*ti
= NULL
;
4443 proto_item
*tf
= NULL
;
4444 proto_tree
*dcerpc_tree
= NULL
;
4445 proto_tree
*cn_flags_tree
= NULL
;
4446 proto_tree
*drep_tree
= NULL
;
4447 e_dce_cn_common_hdr_t hdr
;
4448 dcerpc_auth_info auth_info
;
4449 tvbuff_t
*fragment_tvb
;
4452 * when done over nbt, dcerpc requests are padded with 4 bytes of null
4453 * data for some reason.
4455 * XXX - if that's always the case, the right way to do this would
4456 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
4457 * the 4 bytes of null padding, and make that the dissector
4458 * used for "netbios".
4460 if (tvb_memeql(tvb
, offset
, nulls
, 4) == 0) {
4469 * Check if this looks like a C/O DCERPC call
4471 if (!tvb_bytes_exist(tvb
, offset
, sizeof (hdr
))) {
4472 return FALSE
; /* not enough information to check */
4474 start_offset
= offset
;
4475 hdr
.rpc_ver
= tvb_get_guint8(tvb
, offset
++);
4476 if (hdr
.rpc_ver
!= 5)
4478 hdr
.rpc_ver_minor
= tvb_get_guint8(tvb
, offset
++);
4479 if ((hdr
.rpc_ver_minor
!= 0) && (hdr
.rpc_ver_minor
!= 1))
4481 hdr
.ptype
= tvb_get_guint8(tvb
, offset
++);
4482 if (hdr
.ptype
> PDU_RTS
)
4485 hdr
.flags
= tvb_get_guint8(tvb
, offset
++);
4486 tvb_memcpy(tvb
, (guint8
*)hdr
.drep
, offset
, sizeof (hdr
.drep
));
4487 offset
+= (int)sizeof (hdr
.drep
);
4489 hdr
.frag_len
= dcerpc_tvb_get_ntohs(tvb
, offset
, hdr
.drep
);
4491 hdr
.auth_len
= dcerpc_tvb_get_ntohs(tvb
, offset
, hdr
.drep
);
4493 hdr
.call_id
= dcerpc_tvb_get_ntohl(tvb
, offset
, hdr
.drep
);
4496 if (pinfo
->dcectxid
== 0) {
4497 col_append_fstr(pinfo
->cinfo
, COL_DCE_CALL
, "%u", hdr
.call_id
);
4499 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
4500 * prepend a delimiter */
4501 col_append_fstr(pinfo
->cinfo
, COL_DCE_CALL
, "#%u", hdr
.call_id
);
4504 if (can_desegment
&& pinfo
->can_desegment
4505 && !tvb_bytes_exist(tvb
, start_offset
, hdr
.frag_len
)) {
4506 pinfo
->desegment_offset
= start_offset
;
4507 pinfo
->desegment_len
= hdr
.frag_len
- tvb_length_remaining(tvb
, start_offset
);
4508 *pkt_len
= 0; /* desegmentation required */
4512 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "DCERPC");
4514 if (pinfo
->dcectxid
!= 0) {
4515 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
4516 * append a delimiter and set a column fence */
4517 col_append_str(pinfo
->cinfo
, COL_INFO
, " # ");
4518 col_set_fence(pinfo
->cinfo
,COL_INFO
);
4520 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "%s: call_id: %u",
4521 pckt_vals
[hdr
.ptype
].strptr
, hdr
.call_id
);
4523 if (pinfo
->dcectxid
!= 0) {
4524 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU */
4525 expert_add_info(pinfo
, NULL
, &ei_dcerpc_fragment_multiple
);
4528 offset
= start_offset
;
4529 tvb_ensure_bytes_exist(tvb
, offset
, 16);
4531 ti
= proto_tree_add_item(tree
, proto_dcerpc
, tvb
, offset
, hdr
.frag_len
, ENC_NA
);
4532 dcerpc_tree
= proto_item_add_subtree(ti
, ett_dcerpc
);
4535 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_ver
, tvb
, offset
, 1, hdr
.rpc_ver
);
4538 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_ver_minor
, tvb
, offset
, 1, hdr
.rpc_ver_minor
);
4541 tf
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_packet_type
, tvb
, offset
, 1, hdr
.ptype
);
4544 #if 0 /* XXX - too much "output noise", removed for now */
4545 if (hdr
.ptype
== PDU_BIND
|| hdr
.ptype
== PDU_ALTER
||
4546 hdr
.ptype
== PDU_BIND_ACK
|| hdr
.ptype
== PDU_ALTER_ACK
)
4547 expert_add_info_format(pinfo
, tf
, &ei_dcerpc_context_change
, "Context change: %s", val_to_str(hdr
.ptype
, pckt_vals
, "(0x%x)"));
4549 if (hdr
.ptype
== PDU_BIND_NAK
)
4550 expert_add_info(pinfo
, tf
, &ei_dcerpc_bind_not_acknowledged
);
4553 proto_item_append_text(ti
, " %s, Fragment: %s",
4554 val_to_str(hdr
.ptype
, pckt_vals
, "Unknown (0x%02x)"),
4555 fragment_type(hdr
.flags
));
4557 tf
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_cn_flags
, tvb
, offset
, 1, hdr
.flags
);
4558 cn_flags_tree
= proto_item_add_subtree(tf
, ett_dcerpc_cn_flags
);
4560 proto_tree_add_boolean(cn_flags_tree
, hf_dcerpc_cn_flags_object
, tvb
, offset
, 1, hdr
.flags
);
4561 proto_tree_add_boolean(cn_flags_tree
, hf_dcerpc_cn_flags_maybe
, tvb
, offset
, 1, hdr
.flags
);
4562 proto_tree_add_boolean(cn_flags_tree
, hf_dcerpc_cn_flags_dne
, tvb
, offset
, 1, hdr
.flags
);
4563 proto_tree_add_boolean(cn_flags_tree
, hf_dcerpc_cn_flags_mpx
, tvb
, offset
, 1, hdr
.flags
);
4564 proto_tree_add_boolean(cn_flags_tree
, hf_dcerpc_cn_flags_reserved
, tvb
, offset
, 1, hdr
.flags
);
4565 proto_tree_add_boolean(cn_flags_tree
, hf_dcerpc_cn_flags_cancel_pending
, tvb
, offset
, 1, hdr
.flags
);
4566 proto_tree_add_boolean(cn_flags_tree
, hf_dcerpc_cn_flags_last_frag
, tvb
, offset
, 1, hdr
.flags
);
4567 proto_tree_add_boolean(cn_flags_tree
, hf_dcerpc_cn_flags_first_frag
, tvb
, offset
, 1, hdr
.flags
);
4570 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", Fragment: %s", fragment_type(hdr
.flags
));
4573 tf
= proto_tree_add_bytes(dcerpc_tree
, hf_dcerpc_drep
, tvb
, offset
, 4, hdr
.drep
);
4574 drep_tree
= proto_item_add_subtree(tf
, ett_dcerpc_drep
);
4576 proto_tree_add_uint(drep_tree
, hf_dcerpc_drep_byteorder
, tvb
, offset
, 1, hdr
.drep
[0] >> 4);
4577 proto_tree_add_uint(drep_tree
, hf_dcerpc_drep_character
, tvb
, offset
, 1, hdr
.drep
[0] & 0x0f);
4578 proto_tree_add_uint(drep_tree
, hf_dcerpc_drep_fp
, tvb
, offset
+1, 1, hdr
.drep
[1]);
4579 offset
+= (int)sizeof (hdr
.drep
);
4581 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_cn_frag_len
, tvb
, offset
, 2, hdr
.frag_len
);
4584 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_cn_auth_len
, tvb
, offset
, 2, hdr
.auth_len
);
4587 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_cn_call_id
, tvb
, offset
, 4, hdr
.call_id
);
4591 proto_item_append_text(ti
, ", FragLen: %u, Call: %u", hdr
.frag_len
, hdr
.call_id
);
4595 * None of the stuff done above should throw an exception, because
4596 * we would have rejected this as "not DCE RPC" if we didn't have all
4597 * of it. (XXX - perhaps we should request reassembly if we have
4598 * enough of the header to consider it DCE RPC but not enough to
4599 * get the fragment length; in that case the stuff still wouldn't
4600 * throw an exception.)
4602 * The rest of the stuff might, so return the PDU length to our caller.
4603 * XXX - should we construct a tvbuff containing only the PDU and
4604 * use that? Or should we have separate "is this a DCE RPC PDU",
4605 * "how long is it", and "dissect it" routines - which might let us
4606 * do most of the work in "tcp_dissect_pdus()"?
4608 if (pkt_len
!= NULL
)
4609 *pkt_len
= hdr
.frag_len
+ padding
;
4611 /* The remaining bytes in the current tvb might contain multiple
4612 * DCE/RPC fragments, so create a new tvb subset for this fragment.
4613 * Only limit the end of the fragment, but not the offset start,
4614 * as the authentication function dissect_dcerpc_cn_auth() will fail
4615 * (and other functions might fail as well) computing the right start
4618 subtvb_len
= MIN(hdr
.frag_len
, tvb_length(tvb
));
4619 fragment_tvb
= tvb_new_subset(tvb
, start_offset
,
4620 subtvb_len
/* length */,
4621 hdr
.frag_len
/* reported_length */);
4624 * Packet type specific stuff is next.
4626 switch (hdr
.ptype
) {
4629 dissect_dcerpc_cn_bind(fragment_tvb
, MIN(offset
- start_offset
, subtvb_len
), pinfo
, dcerpc_tree
, &hdr
);
4634 dissect_dcerpc_cn_bind_ack(fragment_tvb
, MIN(offset
- start_offset
, subtvb_len
), pinfo
, dcerpc_tree
, &hdr
);
4639 * Nothing after the common header other than credentials.
4641 dissect_dcerpc_cn_auth(fragment_tvb
, MIN(offset
- start_offset
, subtvb_len
), pinfo
, dcerpc_tree
, &hdr
, TRUE
,
4646 dissect_dcerpc_cn_rqst(fragment_tvb
, MIN(offset
- start_offset
, subtvb_len
), pinfo
, dcerpc_tree
, tree
, &hdr
);
4650 dissect_dcerpc_cn_resp(fragment_tvb
, MIN(offset
- start_offset
, subtvb_len
), pinfo
, dcerpc_tree
, tree
, &hdr
);
4654 dissect_dcerpc_cn_fault(fragment_tvb
, MIN(offset
- start_offset
, subtvb_len
), pinfo
, dcerpc_tree
, &hdr
);
4658 dissect_dcerpc_cn_bind_nak(fragment_tvb
, MIN(offset
- start_offset
, subtvb_len
), pinfo
, dcerpc_tree
, &hdr
);
4664 * Nothing after the common header other than an authentication
4667 dissect_dcerpc_cn_auth(fragment_tvb
, MIN(offset
- start_offset
, subtvb_len
), pinfo
, dcerpc_tree
, &hdr
, FALSE
,
4673 * Nothing after the common header, not even an authentication
4678 dissect_dcerpc_cn_rts(fragment_tvb
, MIN(offset
- start_offset
, subtvb_len
), pinfo
, dcerpc_tree
, &hdr
);
4682 /* might as well dissect the auth info */
4683 dissect_dcerpc_cn_auth(fragment_tvb
, MIN(offset
- start_offset
, subtvb_len
), pinfo
, dcerpc_tree
, &hdr
, FALSE
,
4691 * DCERPC dissector for connection oriented calls over packet-oriented
4695 dissect_dcerpc_cn_pk(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
4698 * Only one PDU per transport packet, and only one transport
4701 pinfo
->dcetransporttype
= DCE_TRANSPORT_UNKNOWN
;
4702 if (!dissect_dcerpc_cn(tvb
, 0, pinfo
, tree
, FALSE
, NULL
)) {
4704 * It wasn't a DCERPC PDU.
4716 * DCERPC dissector for connection oriented calls over byte-stream
4718 * we need to distinguish here between SMB and non-TCP (more in the future?)
4719 * to be able to know what kind of private_data structure to expect.
4722 dissect_dcerpc_cn_bs_body(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
4724 volatile int offset
= 0;
4726 volatile int dcerpc_pdus
= 0;
4727 volatile gboolean ret
= FALSE
;
4730 * There may be multiple PDUs per transport packet; keep
4733 while (tvb_reported_length_remaining(tvb
, offset
) != 0) {
4736 if (dissect_dcerpc_cn(tvb
, offset
, pinfo
, tree
,
4737 dcerpc_cn_desegment
, &pdu_len
)) {
4740 } CATCH_NONFATAL_ERRORS
{
4742 * Somebody threw an exception that means that there
4743 * was a problem dissecting the payload; that means
4744 * that a dissector was found, so we don't need to
4745 * dissect the payload as data or update the protocol
4748 * Just show the exception and then continue dissecting
4751 show_exception(tvb
, pinfo
, tree
, EXCEPT_CODE
, GET_MESSAGE
);
4753 * Presumably it looked enough like a DCE RPC PDU that we
4754 * dissected enough of it to throw an exception.
4759 if (dcerpc_pdus
== 0) {
4760 gboolean try_desegment
= FALSE
;
4761 if (dcerpc_cn_desegment
&& pinfo
->can_desegment
&&
4762 !tvb_bytes_exist(tvb
, offset
, sizeof(e_dce_cn_common_hdr_t
))) {
4763 /* look for a previous occurence of the DCE-RPC protocol */
4764 wmem_list_frame_t
*cur
;
4765 cur
= wmem_list_frame_prev(wmem_list_tail(pinfo
->layers
));
4766 while (cur
!= NULL
) {
4767 if (proto_dcerpc
== (gint
)GPOINTER_TO_UINT(wmem_list_frame_data(cur
))) {
4768 try_desegment
= TRUE
;
4771 cur
= wmem_list_frame_prev(cur
);
4775 if (try_desegment
) {
4776 /* It didn't look like DCE-RPC but we already had one DCE-RPC
4777 * layer in this packet and what we have is short. Assume that
4778 * it was just too short to tell and ask the TCP layer for more
4780 pinfo
->desegment_offset
= offset
;
4781 pinfo
->desegment_len
= (guint32
)(sizeof(e_dce_cn_common_hdr_t
) - tvb_length_remaining(tvb
, offset
));
4783 /* Really not DCE-RPC */
4789 * Well, we've seen at least one DCERPC PDU.
4793 /* if we had more than one Req/Resp in this PDU change the protocol column */
4794 /* this will formerly contain the last interface name, which may not be the same for all Req/Resp */
4795 if (dcerpc_pdus
>= 2)
4796 col_add_fstr(pinfo
->cinfo
, COL_PROTOCOL
, "%u*DCERPC", dcerpc_pdus
);
4800 * Desegmentation required - bail now, but give the user a hint that desegmentation might be done later.
4802 proto_tree_add_uint_format(tree
, hf_dcerpc_cn_deseg_req
, tvb
, offset
,
4804 tvb_reported_length_remaining(tvb
, offset
),
4805 "[DCE RPC: %u byte%s left, desegmentation might follow]",
4806 tvb_reported_length_remaining(tvb
, offset
),
4807 plurality(tvb_reported_length_remaining(tvb
, offset
), "", "s"));
4812 * Step to the next PDU.
4820 dissect_dcerpc_cn_bs(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
4822 pinfo
->dcetransporttype
= DCE_TRANSPORT_UNKNOWN
;
4823 return dissect_dcerpc_cn_bs_body(tvb
, pinfo
, tree
);
4827 dissect_dcerpc_cn_smbpipe(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
4829 pinfo
->dcetransporttype
= DCE_CN_TRANSPORT_SMBPIPE
;
4830 return dissect_dcerpc_cn_bs_body(tvb
, pinfo
, tree
);
4834 dissect_dcerpc_cn_smb2(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
4836 pinfo
->dcetransporttype
= DCE_TRANSPORT_UNKNOWN
;
4837 return dissect_dcerpc_cn_bs_body(tvb
, pinfo
, tree
);
4843 dissect_dcerpc_dg_auth(tvbuff_t
*tvb
, int offset
, proto_tree
*dcerpc_tree
,
4844 e_dce_dg_common_hdr_t
*hdr
, int *auth_level_p
)
4846 proto_item
*ti
= NULL
;
4847 proto_tree
*auth_tree
= NULL
;
4848 guint8 protection_level
;
4851 * Initially set "*auth_level_p" to -1 to indicate that we haven't
4852 * yet seen any authentication level information.
4854 if (auth_level_p
!= NULL
)
4858 * The authentication information is at the *end* of the PDU; in
4859 * request and response PDUs, the request and response stub data
4862 * If the full packet is here, and there's data past the end of the
4863 * packet body, then dissect the auth info.
4865 offset
+= hdr
->frag_len
;
4866 if (tvb_length_remaining(tvb
, offset
) > 0) {
4867 switch (hdr
->auth_proto
) {
4869 case DCE_C_RPC_AUTHN_PROTOCOL_KRB5
:
4870 ti
= proto_tree_add_text(dcerpc_tree
, tvb
, offset
, -1, "Kerberos authentication verifier");
4871 auth_tree
= proto_item_add_subtree(ti
, ett_dcerpc_krb5_auth_verf
);
4872 protection_level
= tvb_get_guint8(tvb
, offset
);
4873 if (auth_level_p
!= NULL
)
4874 *auth_level_p
= protection_level
;
4875 proto_tree_add_uint(auth_tree
, hf_dcerpc_krb5_av_prot_level
, tvb
, offset
, 1, protection_level
);
4877 proto_tree_add_item(auth_tree
, hf_dcerpc_krb5_av_key_vers_num
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
4879 if (protection_level
== DCE_C_AUTHN_LEVEL_PKT_PRIVACY
)
4880 offset
+= 6; /* 6 bytes of padding */
4882 offset
+= 2; /* 2 bytes of padding */
4883 proto_tree_add_item(auth_tree
, hf_dcerpc_krb5_av_key_auth_verifier
, tvb
, offset
, 16, ENC_NA
);
4888 proto_tree_add_text(dcerpc_tree
, tvb
, offset
, -1, "Authentication verifier");
4895 dissect_dcerpc_dg_cancel_ack(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
4896 proto_tree
*dcerpc_tree
,
4897 e_dce_dg_common_hdr_t
*hdr
)
4901 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
,
4902 hdr
->drep
, hf_dcerpc_dg_cancel_vers
,
4908 /* The only version we know about */
4909 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
,
4910 hdr
->drep
, hf_dcerpc_dg_cancel_id
,
4912 /*offset = */dissect_dcerpc_uint8(tvb
, offset
, pinfo
, dcerpc_tree
,
4913 hdr
->drep
, hf_dcerpc_dg_server_accepting_cancels
,
4920 dissect_dcerpc_dg_cancel(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
4921 proto_tree
*dcerpc_tree
,
4922 e_dce_dg_common_hdr_t
*hdr
)
4926 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
,
4927 hdr
->drep
, hf_dcerpc_dg_cancel_vers
,
4933 /* The only version we know about */
4934 /*offset = */dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
,
4935 hdr
->drep
, hf_dcerpc_dg_cancel_id
,
4937 /* XXX - are NDR Booleans 32 bits? */
4939 /* XXX - the RPC reference in chapter: "the cancel PDU" doesn't mention
4940 the accepting_cancels field (it's only in the cancel_ack PDU)! */
4941 /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4942 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
4949 dissect_dcerpc_dg_fack(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
4950 proto_tree
*dcerpc_tree
,
4951 e_dce_dg_common_hdr_t
*hdr
)
4958 offset
= dissect_dcerpc_uint8(tvb
, offset
, pinfo
, dcerpc_tree
,
4959 hdr
->drep
, hf_dcerpc_dg_fack_vers
,
4966 case 0: /* The only version documented in the DCE RPC 1.1 spec */
4967 case 1: /* This appears to be the same */
4968 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
,
4969 hdr
->drep
, hf_dcerpc_dg_fack_window_size
,
4971 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
,
4972 hdr
->drep
, hf_dcerpc_dg_fack_max_tsdu
,
4974 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
,
4975 hdr
->drep
, hf_dcerpc_dg_fack_max_frag_size
,
4977 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
,
4978 hdr
->drep
, hf_dcerpc_dg_fack_serial_num
,
4980 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " serial: %u",
4982 offset
= dissect_dcerpc_uint16(tvb
, offset
, pinfo
, dcerpc_tree
,
4983 hdr
->drep
, hf_dcerpc_dg_fack_selack_len
,
4985 for (i
= 0; i
< selack_len
; i
++) {
4986 offset
= dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
,
4987 hdr
->drep
, hf_dcerpc_dg_fack_selack
,
4996 dissect_dcerpc_dg_reject_fault(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
4997 proto_tree
*dcerpc_tree
,
4998 e_dce_dg_common_hdr_t
*hdr
)
5002 /*offset = */dissect_dcerpc_uint32(tvb
, offset
, pinfo
, dcerpc_tree
,
5003 hdr
->drep
, hf_dcerpc_dg_status
,
5006 col_append_fstr (pinfo
->cinfo
, COL_INFO
,
5008 val_to_str(status
, reject_status_vals
, "Unknown (0x%08x)"));
5012 dissect_dcerpc_dg_stub(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
5013 proto_tree
*dcerpc_tree
, proto_tree
*tree
,
5014 e_dce_dg_common_hdr_t
*hdr
, dcerpc_info
*di
)
5016 int length
, reported_length
, stub_length
;
5017 gboolean save_fragmented
;
5018 fragment_head
*fd_head
;
5021 proto_item
*parent_pi
;
5023 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " opnum: %u len: %u",
5024 di
->call_data
->opnum
, hdr
->frag_len
);
5026 length
= tvb_length_remaining(tvb
, offset
);
5027 reported_length
= tvb_reported_length_remaining(tvb
, offset
);
5028 stub_length
= hdr
->frag_len
;
5029 if (length
> stub_length
)
5030 length
= stub_length
;
5031 if (reported_length
> stub_length
)
5032 reported_length
= stub_length
;
5034 save_fragmented
= pinfo
->fragmented
;
5036 /* If we don't have reassembly enabled, or this packet contains
5037 the entire PDU, or if this is a short frame (or a frame
5038 not reassembled at a lower layer) that doesn't include all
5039 the data in the fragment, just call the handoff directly if
5040 this is the first fragment or the PDU isn't fragmented. */
5041 if ( (!dcerpc_reassemble
) || !(hdr
->flags1
& PFCL1_FRAG
) ||
5042 !tvb_bytes_exist(tvb
, offset
, stub_length
) ) {
5043 if (hdr
->frag_num
== 0) {
5046 /* First fragment, possibly the only fragment */
5049 * XXX - authentication info?
5051 pinfo
->fragmented
= (hdr
->flags1
& PFCL1_FRAG
);
5052 next_tvb
= tvb_new_subset(tvb
, offset
, length
,
5054 dcerpc_try_handoff(pinfo
, tree
, dcerpc_tree
, next_tvb
,
5055 next_tvb
, hdr
->drep
, di
, NULL
);
5057 /* PDU is fragmented and this isn't the first fragment */
5060 tvb_ensure_bytes_exist(tvb
, offset
, stub_length
);
5061 proto_tree_add_text(dcerpc_tree
, tvb
, offset
, stub_length
,
5062 "Fragment data (%d byte%s)",
5064 plurality(stub_length
, "", "s"));
5069 /* Reassembly is enabled, the PDU is fragmented, and
5070 we have all the data in the fragment; the first two
5071 of those mean we should attempt reassembly, and the
5072 third means we can attempt reassembly. */
5075 tvb_ensure_bytes_exist(tvb
, offset
, stub_length
);
5076 proto_tree_add_text(dcerpc_tree
, tvb
, offset
, stub_length
,
5077 "Fragment data (%d byte%s)", stub_length
,
5078 plurality(stub_length
, "", "s"));
5082 fd_head
= fragment_add_seq(&dcerpc_cl_reassembly_table
,
5084 pinfo
, hdr
->seqnum
, (void *)hdr
,
5085 hdr
->frag_num
, stub_length
,
5086 !(hdr
->flags1
& PFCL1_LASTFRAG
), 0);
5087 if (fd_head
!= NULL
) {
5088 /* We completed reassembly... */
5089 if (pinfo
->fd
->num
== fd_head
->reassembled_in
) {
5090 /* ...and this is the reassembled RPC PDU */
5091 next_tvb
= tvb_new_chain(tvb
, fd_head
->tvb_data
);
5092 add_new_data_source(pinfo
, next_tvb
, "Reassembled DCE/RPC");
5093 show_fragment_seq_tree(fd_head
, &dcerpc_frag_items
,
5094 tree
, pinfo
, next_tvb
, &pi
);
5097 * XXX - authentication info?
5099 pinfo
->fragmented
= FALSE
;
5100 dcerpc_try_handoff(pinfo
, tree
, dcerpc_tree
, next_tvb
,
5101 next_tvb
, hdr
->drep
, di
, NULL
);
5103 /* ...and this isn't the reassembled RPC PDU */
5104 pi
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_reassembled_in
,
5105 tvb
, 0, 0, fd_head
->reassembled_in
);
5106 PROTO_ITEM_SET_GENERATED(pi
);
5107 parent_pi
= proto_tree_get_parent(dcerpc_tree
);
5108 if (parent_pi
!= NULL
) {
5109 proto_item_append_text(parent_pi
, ", [Reas: #%u]", fd_head
->reassembled_in
);
5111 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
5112 " [DCE/RPC fragment, reas: #%u]", fd_head
->reassembled_in
);
5116 pinfo
->fragmented
= save_fragmented
;
5120 dissect_dcerpc_dg_rqst(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
5121 proto_tree
*dcerpc_tree
, proto_tree
*tree
,
5122 e_dce_dg_common_hdr_t
*hdr
, conversation_t
*conv
)
5125 dcerpc_call_value
*value
, v
;
5126 dcerpc_matched_key matched_key
, *new_matched_key
;
5128 proto_item
*parent_pi
;
5131 if (!(pinfo
->fd
->flags
.visited
)) {
5132 dcerpc_call_value
*call_value
;
5133 dcerpc_dg_call_key
*call_key
;
5135 call_key
= (dcerpc_dg_call_key
*)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_dg_call_key
));
5136 call_key
->conv
= conv
;
5137 call_key
->seqnum
= hdr
->seqnum
;
5138 call_key
->act_id
= hdr
->act_id
;
5140 call_value
= (dcerpc_call_value
*)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_call_value
));
5141 call_value
->uuid
= hdr
->if_id
;
5142 call_value
->ver
= hdr
->if_ver
;
5143 call_value
->object_uuid
= hdr
->obj_id
;
5144 call_value
->opnum
= hdr
->opnum
;
5145 call_value
->req_frame
= pinfo
->fd
->num
;
5146 call_value
->req_time
= pinfo
->fd
->abs_ts
;
5147 call_value
->rep_frame
= 0;
5148 call_value
->max_ptr
= 0;
5149 call_value
->se_data
= NULL
;
5150 call_value
->private_data
= NULL
;
5151 call_value
->pol
= NULL
;
5152 /* NDR64 is not available on dg transports ?*/
5153 call_value
->flags
= 0;
5155 g_hash_table_insert(dcerpc_dg_calls
, call_key
, call_value
);
5157 new_matched_key
= (dcerpc_matched_key
*)wmem_alloc(wmem_file_scope(), sizeof(dcerpc_matched_key
));
5158 new_matched_key
->frame
= pinfo
->fd
->num
;
5159 new_matched_key
->call_id
= hdr
->seqnum
;
5160 g_hash_table_insert(dcerpc_matched
, new_matched_key
, call_value
);
5163 matched_key
.frame
= pinfo
->fd
->num
;
5164 matched_key
.call_id
= hdr
->seqnum
;
5165 value
= (dcerpc_call_value
*)g_hash_table_lookup(dcerpc_matched
, &matched_key
);
5167 v
.uuid
= hdr
->if_id
;
5168 v
.ver
= hdr
->if_ver
;
5169 v
.object_uuid
= hdr
->obj_id
;
5170 v
.opnum
= hdr
->opnum
;
5171 v
.req_frame
= pinfo
->fd
->num
;
5175 v
.private_data
= NULL
;
5180 di
->call_id
= hdr
->seqnum
;
5182 di
->ptype
= PDU_REQ
;
5183 di
->call_data
= value
;
5185 if (value
->rep_frame
!= 0) {
5186 pi
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_response_in
,
5187 tvb
, 0, 0, value
->rep_frame
);
5188 PROTO_ITEM_SET_GENERATED(pi
);
5189 parent_pi
= proto_tree_get_parent(dcerpc_tree
);
5190 if (parent_pi
!= NULL
) {
5191 proto_item_append_text(parent_pi
, ", [Resp: #%u]", value
->rep_frame
);
5194 dissect_dcerpc_dg_stub(tvb
, offset
, pinfo
, dcerpc_tree
, tree
, hdr
, di
);
5198 dissect_dcerpc_dg_resp(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
5199 proto_tree
*dcerpc_tree
, proto_tree
*tree
,
5200 e_dce_dg_common_hdr_t
*hdr
, conversation_t
*conv
)
5203 dcerpc_call_value
*value
, v
;
5204 dcerpc_matched_key matched_key
, *new_matched_key
;
5206 proto_item
*parent_pi
;
5209 if (!(pinfo
->fd
->flags
.visited
)) {
5210 dcerpc_call_value
*call_value
;
5211 dcerpc_dg_call_key call_key
;
5213 call_key
.conv
= conv
;
5214 call_key
.seqnum
= hdr
->seqnum
;
5215 call_key
.act_id
= hdr
->act_id
;
5217 if ((call_value
= (dcerpc_call_value
*)g_hash_table_lookup(dcerpc_dg_calls
, &call_key
))) {
5218 new_matched_key
= (dcerpc_matched_key
*)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key
));
5219 new_matched_key
->frame
= pinfo
->fd
->num
;
5220 new_matched_key
->call_id
= hdr
->seqnum
;
5221 g_hash_table_insert(dcerpc_matched
, new_matched_key
, call_value
);
5222 if (call_value
->rep_frame
== 0) {
5223 call_value
->rep_frame
= pinfo
->fd
->num
;
5228 matched_key
.frame
= pinfo
->fd
->num
;
5229 matched_key
.call_id
= hdr
->seqnum
;
5230 value
= (dcerpc_call_value
*)g_hash_table_lookup(dcerpc_matched
, &matched_key
);
5232 v
.uuid
= hdr
->if_id
;
5233 v
.ver
= hdr
->if_ver
;
5234 v
.object_uuid
= hdr
->obj_id
;
5235 v
.opnum
= hdr
->opnum
;
5237 v
.rep_frame
= pinfo
->fd
->num
;
5239 v
.private_data
= NULL
;
5246 di
->ptype
= PDU_RESP
;
5247 di
->call_data
= value
;
5249 if (value
->req_frame
!= 0) {
5251 pi
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_request_in
,
5252 tvb
, 0, 0, value
->req_frame
);
5253 PROTO_ITEM_SET_GENERATED(pi
);
5254 parent_pi
= proto_tree_get_parent(dcerpc_tree
);
5255 if (parent_pi
!= NULL
) {
5256 proto_item_append_text(parent_pi
, ", [Req: #%u]", value
->req_frame
);
5258 nstime_delta(&delta_ts
, &pinfo
->fd
->abs_ts
, &value
->req_time
);
5259 pi
= proto_tree_add_time(dcerpc_tree
, hf_dcerpc_time
, tvb
, offset
, 0, &delta_ts
);
5260 PROTO_ITEM_SET_GENERATED(pi
);
5262 proto_tree_add_expert(dcerpc_tree
, pinfo
, &ei_dcerpc_no_request_found
, tvb
, 0, 0);
5264 dissect_dcerpc_dg_stub(tvb
, offset
, pinfo
, dcerpc_tree
, tree
, hdr
, di
);
5268 dissect_dcerpc_dg_ping_ack(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
5269 proto_tree
*dcerpc_tree
,
5270 e_dce_dg_common_hdr_t
*hdr
, conversation_t
*conv
)
5272 proto_item
*parent_pi
;
5273 /* if (!(pinfo->fd->flags.visited)) {*/
5274 dcerpc_call_value
*call_value
;
5275 dcerpc_dg_call_key call_key
;
5277 call_key
.conv
= conv
;
5278 call_key
.seqnum
= hdr
->seqnum
;
5279 call_key
.act_id
= hdr
->act_id
;
5281 if ((call_value
= (dcerpc_call_value
*)g_hash_table_lookup(dcerpc_dg_calls
, &call_key
))) {
5285 pi
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_request_in
,
5286 tvb
, 0, 0, call_value
->req_frame
);
5287 PROTO_ITEM_SET_GENERATED(pi
);
5288 parent_pi
= proto_tree_get_parent(dcerpc_tree
);
5289 if (parent_pi
!= NULL
) {
5290 proto_item_append_text(parent_pi
, ", [Req: #%u]", call_value
->req_frame
);
5293 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " [req: #%u]", call_value
->req_frame
);
5295 nstime_delta(&delta_ts
, &pinfo
->fd
->abs_ts
, &call_value
->req_time
);
5296 pi
= proto_tree_add_time(dcerpc_tree
, hf_dcerpc_time
, tvb
, offset
, 0, &delta_ts
);
5297 PROTO_ITEM_SET_GENERATED(pi
);
5303 * DCERPC dissector for connectionless calls
5306 dissect_dcerpc_dg(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
5308 proto_item
*ti
= NULL
;
5309 proto_item
*tf
= NULL
;
5310 proto_tree
*dcerpc_tree
= NULL
;
5311 proto_tree
*dg_flags1_tree
= NULL
;
5312 proto_tree
*dg_flags2_tree
= NULL
;
5313 proto_tree
*drep_tree
= NULL
;
5314 e_dce_dg_common_hdr_t hdr
;
5316 conversation_t
*conv
;
5319 const char *uuid_name
= NULL
;
5322 * Check if this looks like a CL DCERPC call. All dg packets
5323 * have an 80 byte header on them. Which starts with
5324 * version (4), pkt_type.
5326 if (tvb_length(tvb
) < sizeof (hdr
)) {
5330 /* Version must be 4 */
5331 hdr
.rpc_ver
= tvb_get_guint8(tvb
, offset
++);
5332 if (hdr
.rpc_ver
!= 4)
5335 /* Type must be <= 19 or it's not DCE/RPC */
5336 hdr
.ptype
= tvb_get_guint8(tvb
, offset
++);
5340 /* flags1 has bit 1 and 8 as reserved so if any of them are set, it is
5341 probably not a DCE/RPC packet
5343 hdr
.flags1
= tvb_get_guint8(tvb
, offset
++);
5344 if (hdr
.flags1
&0x81)
5347 /* flags2 has all bits except bit 2 as reserved so if any of them are set
5348 it is probably not DCE/RPC.
5350 hdr
.flags2
= tvb_get_guint8(tvb
, offset
++);
5351 if (hdr
.flags2
&0xfd)
5355 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "DCERPC");
5356 col_add_str(pinfo
->cinfo
, COL_INFO
, pckt_vals
[hdr
.ptype
].strptr
);
5358 tvb_memcpy(tvb
, (guint8
*)hdr
.drep
, offset
, sizeof (hdr
.drep
));
5359 offset
+= (int)sizeof (hdr
.drep
);
5360 hdr
.serial_hi
= tvb_get_guint8(tvb
, offset
++);
5361 dcerpc_tvb_get_uuid(tvb
, offset
, hdr
.drep
, &hdr
.obj_id
);
5363 dcerpc_tvb_get_uuid(tvb
, offset
, hdr
.drep
, &hdr
.if_id
);
5365 dcerpc_tvb_get_uuid(tvb
, offset
, hdr
.drep
, &hdr
.act_id
);
5367 hdr
.server_boot
= dcerpc_tvb_get_ntohl(tvb
, offset
, hdr
.drep
);
5369 hdr
.if_ver
= dcerpc_tvb_get_ntohl(tvb
, offset
, hdr
.drep
);
5371 hdr
.seqnum
= dcerpc_tvb_get_ntohl(tvb
, offset
, hdr
.drep
);
5373 hdr
.opnum
= dcerpc_tvb_get_ntohs(tvb
, offset
, hdr
.drep
);
5375 hdr
.ihint
= dcerpc_tvb_get_ntohs(tvb
, offset
, hdr
.drep
);
5377 hdr
.ahint
= dcerpc_tvb_get_ntohs(tvb
, offset
, hdr
.drep
);
5379 hdr
.frag_len
= dcerpc_tvb_get_ntohs(tvb
, offset
, hdr
.drep
);
5381 hdr
.frag_num
= dcerpc_tvb_get_ntohs(tvb
, offset
, hdr
.drep
);
5383 hdr
.auth_proto
= tvb_get_guint8(tvb
, offset
++);
5384 hdr
.serial_lo
= tvb_get_guint8(tvb
, offset
++);
5387 ti
= proto_tree_add_item(tree
, proto_dcerpc
, tvb
, 0, -1, ENC_NA
);
5389 dcerpc_tree
= proto_item_add_subtree(ti
, ett_dcerpc
);
5390 proto_item_append_text(ti
, " %s, Seq: %u, Serial: %u, Frag: %u, FragLen: %u",
5391 val_to_str(hdr
.ptype
, pckt_vals
, "Unknown (0x%02x)"),
5392 hdr
.seqnum
, hdr
.serial_hi
*256+hdr
.serial_lo
,
5393 hdr
.frag_num
, hdr
.frag_len
);
5399 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_ver
, tvb
, offset
, 1, hdr
.rpc_ver
);
5403 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_packet_type
, tvb
, offset
, 1, hdr
.ptype
);
5407 tf
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_dg_flags1
, tvb
, offset
, 1, hdr
.flags1
);
5408 dg_flags1_tree
= proto_item_add_subtree(tf
, ett_dcerpc_dg_flags1
);
5409 if (dg_flags1_tree
) {
5410 proto_tree_add_boolean(dg_flags1_tree
, hf_dcerpc_dg_flags1_rsrvd_80
, tvb
, offset
, 1, hdr
.flags1
);
5411 proto_tree_add_boolean(dg_flags1_tree
, hf_dcerpc_dg_flags1_broadcast
, tvb
, offset
, 1, hdr
.flags1
);
5412 proto_tree_add_boolean(dg_flags1_tree
, hf_dcerpc_dg_flags1_idempotent
, tvb
, offset
, 1, hdr
.flags1
);
5413 proto_tree_add_boolean(dg_flags1_tree
, hf_dcerpc_dg_flags1_maybe
, tvb
, offset
, 1, hdr
.flags1
);
5414 proto_tree_add_boolean(dg_flags1_tree
, hf_dcerpc_dg_flags1_nofack
, tvb
, offset
, 1, hdr
.flags1
);
5415 proto_tree_add_boolean(dg_flags1_tree
, hf_dcerpc_dg_flags1_frag
, tvb
, offset
, 1, hdr
.flags1
);
5416 proto_tree_add_boolean(dg_flags1_tree
, hf_dcerpc_dg_flags1_last_frag
, tvb
, offset
, 1, hdr
.flags1
);
5417 proto_tree_add_boolean(dg_flags1_tree
, hf_dcerpc_dg_flags1_rsrvd_01
, tvb
, offset
, 1, hdr
.flags1
);
5419 proto_item_append_text(tf
, " %s%s%s%s%s%s",
5420 (hdr
.flags1
& PFCL1_BROADCAST
) ? "\"Broadcast\" " : "",
5421 (hdr
.flags1
& PFCL1_IDEMPOTENT
) ? "\"Idempotent\" " : "",
5422 (hdr
.flags1
& PFCL1_MAYBE
) ? "\"Maybe\" " : "",
5423 (hdr
.flags1
& PFCL1_NOFACK
) ? "\"No Fack\" " : "",
5424 (hdr
.flags1
& PFCL1_FRAG
) ? "\"Fragment\" " : "",
5425 (hdr
.flags1
& PFCL1_LASTFRAG
) ? "\"Last Fragment\" " : "");
5432 tf
= proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_dg_flags2
, tvb
, offset
, 1, hdr
.flags2
);
5433 dg_flags2_tree
= proto_item_add_subtree(tf
, ett_dcerpc_dg_flags2
);
5434 if (dg_flags2_tree
) {
5435 proto_tree_add_boolean(dg_flags2_tree
, hf_dcerpc_dg_flags2_rsrvd_80
, tvb
, offset
, 1, hdr
.flags2
);
5436 proto_tree_add_boolean(dg_flags2_tree
, hf_dcerpc_dg_flags2_rsrvd_40
, tvb
, offset
, 1, hdr
.flags2
);
5437 proto_tree_add_boolean(dg_flags2_tree
, hf_dcerpc_dg_flags2_rsrvd_20
, tvb
, offset
, 1, hdr
.flags2
);
5438 proto_tree_add_boolean(dg_flags2_tree
, hf_dcerpc_dg_flags2_rsrvd_10
, tvb
, offset
, 1, hdr
.flags2
);
5439 proto_tree_add_boolean(dg_flags2_tree
, hf_dcerpc_dg_flags2_rsrvd_08
, tvb
, offset
, 1, hdr
.flags2
);
5440 proto_tree_add_boolean(dg_flags2_tree
, hf_dcerpc_dg_flags2_rsrvd_04
, tvb
, offset
, 1, hdr
.flags2
);
5441 proto_tree_add_boolean(dg_flags2_tree
, hf_dcerpc_dg_flags2_cancel_pending
, tvb
, offset
, 1, hdr
.flags2
);
5442 proto_tree_add_boolean(dg_flags2_tree
, hf_dcerpc_dg_flags2_rsrvd_01
, tvb
, offset
, 1, hdr
.flags2
);
5444 proto_item_append_text(tf
, " %s",
5445 (hdr
.flags2
& PFCL2_CANCEL_PENDING
) ? "\"Cancel Pending\" " : "");
5452 tf
= proto_tree_add_bytes(dcerpc_tree
, hf_dcerpc_drep
, tvb
, offset
, sizeof (hdr
.drep
), hdr
.drep
);
5453 drep_tree
= proto_item_add_subtree(tf
, ett_dcerpc_drep
);
5455 proto_tree_add_uint(drep_tree
, hf_dcerpc_drep_byteorder
, tvb
, offset
, 1, hdr
.drep
[0] >> 4);
5456 proto_tree_add_uint(drep_tree
, hf_dcerpc_drep_character
, tvb
, offset
, 1, hdr
.drep
[0] & 0x0f);
5457 proto_tree_add_uint(drep_tree
, hf_dcerpc_drep_fp
, tvb
, offset
+1, 1, hdr
.drep
[1]);
5458 proto_item_append_text(tf
, " (Order: %s, Char: %s, Float: %s)",
5459 val_to_str_const(hdr
.drep
[0] >> 4, drep_byteorder_vals
, "Unknown"),
5460 val_to_str_const(hdr
.drep
[0] & 0x0f, drep_character_vals
, "Unknown"),
5461 val_to_str_const(hdr
.drep
[1], drep_fp_vals
, "Unknown"));
5464 offset
+= (int)sizeof (hdr
.drep
);
5467 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_dg_serial_hi
, tvb
, offset
, 1, hdr
.serial_hi
);
5471 proto_tree_add_guid_format(dcerpc_tree
, hf_dcerpc_obj_id
, tvb
,
5472 offset
, 16, (e_guid_t
*) &hdr
.obj_id
, "Object UUID: %s",
5473 guid_to_str((e_guid_t
*) &hdr
.obj_id
));
5478 uuid_str
= guid_to_str((e_guid_t
*)&hdr
.if_id
);
5479 uuid_name
= guids_get_uuid_name(&hdr
.if_id
);
5481 proto_tree_add_guid_format(dcerpc_tree
, hf_dcerpc_dg_if_id
, tvb
,
5482 offset
, 16, (e_guid_t
*) &hdr
.if_id
, "Interface: %s UUID: %s", uuid_name
, uuid_str
);
5484 proto_tree_add_guid_format(dcerpc_tree
, hf_dcerpc_dg_if_id
, tvb
,
5485 offset
, 16, (e_guid_t
*) &hdr
.if_id
, "Interface UUID: %s", uuid_str
);
5491 proto_tree_add_guid_format(dcerpc_tree
, hf_dcerpc_dg_act_id
, tvb
,
5492 offset
, 16, (e_guid_t
*) &hdr
.act_id
, "Activity: %s",
5493 guid_to_str((e_guid_t
*) &hdr
.act_id
));
5498 nstime_t server_boot
;
5500 server_boot
.secs
= hdr
.server_boot
;
5501 server_boot
.nsecs
= 0;
5503 if (hdr
.server_boot
== 0)
5504 proto_tree_add_time_format_value(dcerpc_tree
, hf_dcerpc_dg_server_boot
,
5505 tvb
, offset
, 4, &server_boot
,
5508 proto_tree_add_time(dcerpc_tree
, hf_dcerpc_dg_server_boot
,
5509 tvb
, offset
, 4, &server_boot
);
5514 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_dg_if_ver
, tvb
, offset
, 4, hdr
.if_ver
);
5518 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_dg_seqnum
, tvb
, offset
, 4, hdr
.seqnum
);
5519 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ": seq: %u", hdr
.seqnum
);
5520 col_append_fstr(pinfo
->cinfo
, COL_DCE_CALL
, "%u", hdr
.seqnum
);
5524 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_opnum
, tvb
, offset
, 2, hdr
.opnum
);
5528 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_dg_ihint
, tvb
, offset
, 2, hdr
.ihint
);
5532 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_dg_ahint
, tvb
, offset
, 2, hdr
.ahint
);
5536 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_dg_frag_len
, tvb
, offset
, 2, hdr
.frag_len
);
5540 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_dg_frag_num
, tvb
, offset
, 2, hdr
.frag_num
);
5541 if (hdr
.flags1
& PFCL1_FRAG
) {
5542 /* Fragmented - put the fragment number into the Info column */
5543 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " frag: %u",
5549 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_dg_auth_proto
, tvb
, offset
, 1, hdr
.auth_proto
);
5553 proto_tree_add_uint(dcerpc_tree
, hf_dcerpc_dg_serial_lo
, tvb
, offset
, 1, hdr
.serial_lo
);
5554 if (hdr
.flags1
& PFCL1_FRAG
) {
5555 /* Fragmented - put the serial number into the Info column */
5556 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " serial: %u",
5557 (hdr
.serial_hi
<< 8) | hdr
.serial_lo
);
5563 * XXX - for Kerberos, we get a protection level; if it's
5564 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
5567 dissect_dcerpc_dg_auth(tvb
, offset
, dcerpc_tree
, &hdr
,
5572 * keeping track of the conversation shouldn't really be necessary
5573 * for connectionless packets, because everything we need to know
5574 * to dissect is in the header for each packet. Unfortunately,
5575 * Microsoft's implementation is buggy and often puts the
5576 * completely wrong if_id in the header. go figure. So, keep
5577 * track of the seqnum and use that if possible. Note: that's not
5578 * completely correct. It should really be done based on both the
5579 * activity_id and seqnum. I haven't seen anywhere that it would
5580 * make a difference, but for future reference...
5582 conv
= find_or_create_conversation(pinfo
);
5585 * Packet type specific stuff is next.
5588 switch (hdr
.ptype
) {
5590 case PDU_CANCEL_ACK
:
5591 /* Body is optional */
5592 /* XXX - we assume "frag_len" is the length of the body */
5593 if (hdr
.frag_len
!= 0)
5594 dissect_dcerpc_dg_cancel_ack(tvb
, offset
, pinfo
, dcerpc_tree
, &hdr
);
5599 * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
5600 * but in at least one capture none of the Cl_cancel PDUs had a
5603 /* XXX - we assume "frag_len" is the length of the body */
5604 if (hdr
.frag_len
!= 0)
5605 dissect_dcerpc_dg_cancel(tvb
, offset
, pinfo
, dcerpc_tree
, &hdr
);
5609 /* Body is optional; if present, it's the same as PDU_FACK */
5610 /* XXX - we assume "frag_len" is the length of the body */
5611 if (hdr
.frag_len
!= 0)
5612 dissect_dcerpc_dg_fack(tvb
, offset
, pinfo
, dcerpc_tree
, &hdr
);
5616 /* Body is optional */
5617 /* XXX - we assume "frag_len" is the length of the body */
5618 if (hdr
.frag_len
!= 0)
5619 dissect_dcerpc_dg_fack(tvb
, offset
, pinfo
, dcerpc_tree
, &hdr
);
5624 dissect_dcerpc_dg_reject_fault(tvb
, offset
, pinfo
, dcerpc_tree
, &hdr
);
5628 dissect_dcerpc_dg_rqst(tvb
, offset
, pinfo
, dcerpc_tree
, tree
, &hdr
, conv
);
5632 dissect_dcerpc_dg_resp(tvb
, offset
, pinfo
, dcerpc_tree
, tree
, &hdr
, conv
);
5635 /* these requests have no body */
5638 dissect_dcerpc_dg_ping_ack(tvb
, offset
, pinfo
, dcerpc_tree
, &hdr
, conv
);
5649 dcerpc_init_protocol(void)
5651 /* structures and data for BIND */
5653 g_hash_table_destroy(dcerpc_binds
);
5654 dcerpc_binds
= NULL
;
5656 if (!dcerpc_binds
) {
5657 dcerpc_binds
= g_hash_table_new(dcerpc_bind_hash
, dcerpc_bind_equal
);
5660 /* structures and data for CALL */
5661 if (dcerpc_cn_calls
) {
5662 g_hash_table_destroy(dcerpc_cn_calls
);
5664 dcerpc_cn_calls
= g_hash_table_new(dcerpc_cn_call_hash
, dcerpc_cn_call_equal
);
5665 if (dcerpc_dg_calls
) {
5666 g_hash_table_destroy(dcerpc_dg_calls
);
5668 dcerpc_dg_calls
= g_hash_table_new(dcerpc_dg_call_hash
, dcerpc_dg_call_equal
);
5670 /* structure and data for MATCHED */
5671 if (dcerpc_matched
) {
5672 g_hash_table_destroy(dcerpc_matched
);
5674 dcerpc_matched
= g_hash_table_new(dcerpc_matched_hash
, dcerpc_matched_equal
);
5676 /* call the registered hooks */
5677 g_hook_list_invoke(&dcerpc_hooks_init_protos
, FALSE
/* not may_recurse */);
5681 proto_register_dcerpc(void)
5683 static hf_register_info hf
[] = {
5684 { &hf_dcerpc_request_in
,
5685 { "Request in frame", "dcerpc.request_in", FT_FRAMENUM
, BASE_NONE
,
5686 NULL
, 0, "This packet is a response to the packet with this number", HFILL
}},
5687 { &hf_dcerpc_response_in
,
5688 { "Response in frame", "dcerpc.response_in", FT_FRAMENUM
, BASE_NONE
,
5689 NULL
, 0, "This packet will be responded in the packet with this number", HFILL
}},
5690 { &hf_dcerpc_referent_id
,
5691 { "Referent ID", "dcerpc.referent_id", FT_UINT32
, BASE_HEX
,
5692 NULL
, 0, "Referent ID for this NDR encoded pointer", HFILL
}},
5694 { "Version", "dcerpc.ver", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5695 { &hf_dcerpc_ver_minor
,
5696 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5697 { &hf_dcerpc_packet_type
,
5698 { "Packet type", "dcerpc.pkt_type", FT_UINT8
, BASE_DEC
, VALS(pckt_vals
), 0x0, NULL
, HFILL
}},
5699 { &hf_dcerpc_cn_flags
,
5700 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
5701 { &hf_dcerpc_cn_flags_first_frag
,
5702 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFC_FIRST_FRAG
, NULL
, HFILL
}},
5703 { &hf_dcerpc_cn_flags_last_frag
,
5704 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFC_LAST_FRAG
, NULL
, HFILL
}},
5705 { &hf_dcerpc_cn_flags_cancel_pending
,
5706 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFC_PENDING_CANCEL
, NULL
, HFILL
}},
5707 { &hf_dcerpc_cn_flags_reserved
,
5708 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFC_RESERVED_1
, NULL
, HFILL
}},
5709 { &hf_dcerpc_cn_flags_mpx
,
5710 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFC_CONC_MPX
, NULL
, HFILL
}},
5711 { &hf_dcerpc_cn_flags_dne
,
5712 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFC_DID_NOT_EXECUTE
, NULL
, HFILL
}},
5713 { &hf_dcerpc_cn_flags_maybe
,
5714 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFC_MAYBE
, NULL
, HFILL
}},
5715 { &hf_dcerpc_cn_flags_object
,
5716 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFC_OBJECT_UUID
, NULL
, HFILL
}},
5718 { "Data Representation", "dcerpc.drep", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
5719 { &hf_dcerpc_drep_byteorder
,
5720 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8
, BASE_DEC
, VALS(drep_byteorder_vals
), 0x0, NULL
, HFILL
}},
5721 { &hf_dcerpc_drep_character
,
5722 { "Character", "dcerpc.drep.character", FT_UINT8
, BASE_DEC
, VALS(drep_character_vals
), 0x0, NULL
, HFILL
}},
5723 { &hf_dcerpc_drep_fp
,
5724 { "Floating-point", "dcerpc.drep.fp", FT_UINT8
, BASE_DEC
, VALS(drep_fp_vals
), 0x0, NULL
, HFILL
}},
5725 { &hf_dcerpc_cn_frag_len
,
5726 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5727 { &hf_dcerpc_cn_auth_len
,
5728 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5729 { &hf_dcerpc_cn_call_id
,
5730 { "Call ID", "dcerpc.cn_call_id", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5731 { &hf_dcerpc_cn_max_xmit
,
5732 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5733 { &hf_dcerpc_cn_max_recv
,
5734 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5735 { &hf_dcerpc_cn_assoc_group
,
5736 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
5737 { &hf_dcerpc_cn_num_ctx_items
,
5738 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5739 { &hf_dcerpc_cn_ctx_item
,
5740 { "Ctx Item", "dcerpc.cn_ctx_item", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
5741 { &hf_dcerpc_cn_ctx_id
,
5742 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5743 { &hf_dcerpc_cn_num_trans_items
,
5744 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5745 { &hf_dcerpc_cn_bind_abstract_syntax
,
5746 { "Abstract Syntax", "dcerpc.cn_bind_abstract_syntax", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
5747 { &hf_dcerpc_cn_bind_if_id
,
5748 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_GUID
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
5749 { &hf_dcerpc_cn_bind_if_ver
,
5750 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5751 { &hf_dcerpc_cn_bind_if_ver_minor
,
5752 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5753 { &hf_dcerpc_cn_bind_trans_syntax
,
5754 { "Transfer Syntax", "dcerpc.cn_bind_trans", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
5755 { &hf_dcerpc_cn_bind_trans_id
,
5756 { "ID", "dcerpc.cn_bind_trans_id", FT_GUID
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
5757 { &hf_dcerpc_cn_bind_trans_ver
,
5758 { "ver", "dcerpc.cn_bind_trans_ver", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5759 { &hf_dcerpc_cn_bind_trans_btfn_01
, /* [MS-RPCE] 2.2.2.14 */
5760 { "Security Context Multiplexing Supported", "dcerpc.cn_bind_trans_btfn.01", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), 0x01, NULL
, HFILL
}},
5761 { &hf_dcerpc_cn_bind_trans_btfn_02
,
5762 { "Keep Connection On Orphan Supported", "dcerpc.cn_bind_trans_btfn.02", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), 0x02, NULL
, HFILL
}},
5763 { &hf_dcerpc_cn_alloc_hint
,
5764 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5765 { &hf_dcerpc_cn_sec_addr_len
,
5766 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5767 { &hf_dcerpc_cn_sec_addr
,
5768 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
5769 { &hf_dcerpc_cn_num_results
,
5770 { "Num results", "dcerpc.cn_num_results", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5771 { &hf_dcerpc_cn_ack_result
,
5772 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16
, BASE_DEC
, VALS(p_cont_result_vals
), 0x0, NULL
, HFILL
}},
5773 { &hf_dcerpc_cn_ack_reason
,
5774 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16
, BASE_DEC
, VALS(p_provider_reason_vals
), 0x0, NULL
, HFILL
}},
5775 { &hf_dcerpc_cn_ack_trans_id
,
5776 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_GUID
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
5777 { &hf_dcerpc_cn_ack_trans_ver
,
5778 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5779 { &hf_dcerpc_cn_ack_btfn
,
5780 { "Bind Time Feature Negotiation Bitmask", "dcerpc.cn_ack_btfn", FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
5781 { &hf_dcerpc_cn_reject_reason
,
5782 { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16
, BASE_DEC
, VALS(reject_reason_vals
), 0x0, NULL
, HFILL
}},
5783 { &hf_dcerpc_cn_num_protocols
,
5784 { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5785 { &hf_dcerpc_cn_protocol_ver_major
,
5786 { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5787 { &hf_dcerpc_cn_protocol_ver_minor
,
5788 { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5789 { &hf_dcerpc_cn_cancel_count
,
5790 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5791 { &hf_dcerpc_cn_status
,
5792 { "Status", "dcerpc.cn_status", FT_UINT32
, BASE_HEX
, VALS(reject_status_vals
), 0x0, NULL
, HFILL
}},
5793 { &hf_dcerpc_cn_deseg_req
,
5794 { "Desegmentation Required", "dcerpc.cn_deseg_req", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5795 { &hf_dcerpc_auth_type
,
5796 { "Auth type", "dcerpc.auth_type", FT_UINT8
, BASE_DEC
, VALS(authn_protocol_vals
), 0x0, NULL
, HFILL
}},
5797 { &hf_dcerpc_auth_level
,
5798 { "Auth level", "dcerpc.auth_level", FT_UINT8
, BASE_DEC
, VALS(authn_level_vals
), 0x0, NULL
, HFILL
}},
5799 { &hf_dcerpc_auth_pad_len
,
5800 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5801 { &hf_dcerpc_auth_rsrvd
,
5802 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5803 { &hf_dcerpc_auth_ctx_id
,
5804 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5805 { &hf_dcerpc_dg_flags1
,
5806 { "Flags1", "dcerpc.dg_flags1", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
5807 { &hf_dcerpc_dg_flags1_rsrvd_01
,
5808 { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL1_RESERVED_01
, NULL
, HFILL
}},
5809 { &hf_dcerpc_dg_flags1_last_frag
,
5810 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL1_LASTFRAG
, NULL
, HFILL
}},
5811 { &hf_dcerpc_dg_flags1_frag
,
5812 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL1_FRAG
, NULL
, HFILL
}},
5813 { &hf_dcerpc_dg_flags1_nofack
,
5814 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL1_NOFACK
, NULL
, HFILL
}},
5815 { &hf_dcerpc_dg_flags1_maybe
,
5816 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL1_MAYBE
, NULL
, HFILL
}},
5817 { &hf_dcerpc_dg_flags1_idempotent
,
5818 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL1_IDEMPOTENT
, NULL
, HFILL
}},
5819 { &hf_dcerpc_dg_flags1_broadcast
,
5820 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL1_BROADCAST
, NULL
, HFILL
}},
5821 { &hf_dcerpc_dg_flags1_rsrvd_80
,
5822 { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL1_RESERVED_80
, NULL
, HFILL
}},
5823 { &hf_dcerpc_dg_flags2
,
5824 { "Flags2", "dcerpc.dg_flags2", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
5825 { &hf_dcerpc_dg_flags2_rsrvd_01
,
5826 { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL2_RESERVED_01
, NULL
, HFILL
}},
5827 { &hf_dcerpc_dg_flags2_cancel_pending
,
5828 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL2_CANCEL_PENDING
, NULL
, HFILL
}},
5829 { &hf_dcerpc_dg_flags2_rsrvd_04
,
5830 { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL2_RESERVED_04
, NULL
, HFILL
}},
5831 { &hf_dcerpc_dg_flags2_rsrvd_08
,
5832 { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL2_RESERVED_08
, NULL
, HFILL
}},
5833 { &hf_dcerpc_dg_flags2_rsrvd_10
,
5834 { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL2_RESERVED_10
, NULL
, HFILL
}},
5835 { &hf_dcerpc_dg_flags2_rsrvd_20
,
5836 { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL2_RESERVED_20
, NULL
, HFILL
}},
5837 { &hf_dcerpc_dg_flags2_rsrvd_40
,
5838 { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL2_RESERVED_40
, NULL
, HFILL
}},
5839 { &hf_dcerpc_dg_flags2_rsrvd_80
,
5840 { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), PFCL2_RESERVED_80
, NULL
, HFILL
}},
5841 { &hf_dcerpc_dg_serial_lo
,
5842 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
5843 { &hf_dcerpc_dg_serial_hi
,
5844 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
5845 { &hf_dcerpc_dg_ahint
,
5846 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
5847 { &hf_dcerpc_dg_ihint
,
5848 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
5849 { &hf_dcerpc_dg_frag_len
,
5850 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5851 { &hf_dcerpc_dg_frag_num
,
5852 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5853 { &hf_dcerpc_dg_auth_proto
,
5854 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8
, BASE_DEC
, VALS(authn_protocol_vals
), 0x0, NULL
, HFILL
}},
5855 { &hf_dcerpc_dg_seqnum
,
5856 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5857 { &hf_dcerpc_dg_server_boot
,
5858 { "Server boot time", "dcerpc.dg_server_boot", FT_ABSOLUTE_TIME
, ABSOLUTE_TIME_LOCAL
, NULL
, 0x0, NULL
, HFILL
}},
5859 { &hf_dcerpc_dg_if_ver
,
5860 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5861 { &hf_dcerpc_krb5_av_prot_level
,
5862 { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8
, BASE_DEC
, VALS(authn_level_vals
), 0x0, NULL
, HFILL
}},
5863 { &hf_dcerpc_krb5_av_key_vers_num
,
5864 { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5865 { &hf_dcerpc_krb5_av_key_auth_verifier
,
5866 { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
5867 { &hf_dcerpc_obj_id
,
5868 { "Object", "dcerpc.obj_id", FT_GUID
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
5869 { &hf_dcerpc_dg_if_id
,
5870 { "Interface", "dcerpc.dg_if_id", FT_GUID
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
5871 { &hf_dcerpc_dg_act_id
,
5872 { "Activity", "dcerpc.dg_act_id", FT_GUID
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
5874 { "Opnum", "dcerpc.opnum", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5876 { &hf_dcerpc_dg_cancel_vers
,
5877 { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5879 { &hf_dcerpc_dg_cancel_id
,
5880 { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5882 { &hf_dcerpc_dg_server_accepting_cancels
,
5883 { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
5885 { &hf_dcerpc_dg_fack_vers
,
5886 { "FACK Version", "dcerpc.fack_vers", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5888 { &hf_dcerpc_dg_fack_window_size
,
5889 { "Window Size", "dcerpc.fack_window_size", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5891 { &hf_dcerpc_dg_fack_max_tsdu
,
5892 { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5894 { &hf_dcerpc_dg_fack_max_frag_size
,
5895 { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5897 { &hf_dcerpc_dg_fack_serial_num
,
5898 { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5900 { &hf_dcerpc_dg_fack_selack_len
,
5901 { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5903 { &hf_dcerpc_dg_fack_selack
,
5904 { "Selective ACK", "dcerpc.fack_selack", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
5906 { &hf_dcerpc_dg_status
,
5907 { "Status", "dcerpc.dg_status", FT_UINT32
, BASE_HEX
, VALS(reject_status_vals
), 0x0, NULL
, HFILL
}},
5909 { &hf_dcerpc_array_max_count
,
5910 { "Max Count", "dcerpc.array.max_count", FT_UINT32
, BASE_DEC
, NULL
, 0x0, "Maximum Count: Number of elements in the array", HFILL
}},
5912 { &hf_dcerpc_array_offset
,
5913 { "Offset", "dcerpc.array.offset", FT_UINT32
, BASE_DEC
, NULL
, 0x0, "Offset for first element in array", HFILL
}},
5915 { &hf_dcerpc_array_actual_count
,
5916 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32
, BASE_DEC
, NULL
, 0x0, "Actual Count: Actual number of elements in the array", HFILL
}},
5918 { &hf_dcerpc_array_buffer
,
5919 { "Buffer", "dcerpc.array.buffer", FT_BYTES
, BASE_NONE
, NULL
, 0x0, "Buffer: Buffer containing elements of the array", HFILL
}},
5922 { "Operation", "dcerpc.op", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5924 { &hf_dcerpc_fragments
,
5925 { "Reassembled DCE/RPC Fragments", "dcerpc.fragments", FT_NONE
, BASE_NONE
,
5926 NULL
, 0x0, "DCE/RPC Fragments", HFILL
}},
5928 { &hf_dcerpc_fragment
,
5929 { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM
, BASE_NONE
,
5930 NULL
, 0x0, NULL
, HFILL
}},
5932 { &hf_dcerpc_fragment_overlap
,
5933 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN
, BASE_NONE
,
5934 NULL
, 0x0, "Fragment overlaps with other fragments", HFILL
}},
5936 { &hf_dcerpc_fragment_overlap_conflict
,
5937 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN
, BASE_NONE
,
5938 NULL
, 0x0, "Overlapping fragments contained conflicting data", HFILL
}},
5940 { &hf_dcerpc_fragment_multiple_tails
,
5941 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN
, BASE_NONE
,
5942 NULL
, 0x0, "Several tails were found when defragmenting the packet", HFILL
}},
5944 { &hf_dcerpc_fragment_too_long_fragment
,
5945 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN
, BASE_NONE
,
5946 NULL
, 0x0, "Fragment contained data past end of packet", HFILL
}},
5948 { &hf_dcerpc_fragment_error
,
5949 { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM
, BASE_NONE
,
5950 NULL
, 0x0, "Defragmentation error due to illegal fragments", HFILL
}},
5952 { &hf_dcerpc_fragment_count
,
5953 { "Fragment count", "dcerpc.fragment.count", FT_UINT32
, BASE_DEC
,
5954 NULL
, 0x0, NULL
, HFILL
}},
5957 { "Time from request", "dcerpc.time", FT_RELATIVE_TIME
, BASE_NONE
,
5958 NULL
, 0, "Time between Request and Response for DCE-RPC calls", HFILL
}},
5960 { &hf_dcerpc_reassembled_in
,
5961 { "Reassembled PDU in frame", "dcerpc.reassembled_in", FT_FRAMENUM
, BASE_NONE
,
5962 NULL
, 0x0, "The DCE/RPC PDU is completely reassembled in the packet with this number", HFILL
}},
5964 { &hf_dcerpc_reassembled_length
,
5965 { "Reassembled DCE/RPC length", "dcerpc.reassembled.length", FT_UINT32
, BASE_DEC
,
5966 NULL
, 0x0, "The total length of the reassembled payload", HFILL
}},
5968 { &hf_dcerpc_unknown_if_id
,
5969 { "Unknown DCERPC interface id", "dcerpc.unknown_if_id", FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
5971 { &hf_dcerpc_cn_rts_flags
,
5972 { "RTS Flags", "dcerpc.cn_rts_flags", FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
5973 { &hf_dcerpc_cn_rts_flags_none
,
5974 {"None", "dcerpc.cn_rts_flags.none", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), RTS_FLAG_NONE
, NULL
, HFILL
}},
5975 { &hf_dcerpc_cn_rts_flags_ping
,
5976 { "Ping", "dcerpc.cn_rts.flags.ping", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), RTS_FLAG_PING
, NULL
, HFILL
}},
5977 { &hf_dcerpc_cn_rts_flags_other_cmd
,
5978 { "Other Cmd", "dcerpc.cn_rts_flags.other_cmd", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), RTS_FLAG_OTHER_CMD
, NULL
, HFILL
}},
5979 { &hf_dcerpc_cn_rts_flags_recycle_channel
,
5980 { "Recycle Channel", "dcerpc.cn_rts_flags.recycle_channel", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), RTS_FLAG_RECYCLE_CHANNEL
, NULL
, HFILL
}},
5981 { &hf_dcerpc_cn_rts_flags_in_channel
,
5982 { "In Channel", "dcerpc.cn_rts_flags.in_channel", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), RTS_FLAG_IN_CHANNEL
, NULL
, HFILL
}},
5983 { &hf_dcerpc_cn_rts_flags_out_channel
,
5984 { "Out Channel", "dcerpc.cn_rts_flags.out_channel", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), RTS_FLAG_OUT_CHANNEL
, NULL
, HFILL
}},
5985 { &hf_dcerpc_cn_rts_flags_eof
,
5986 { "EOF", "dcerpc.cn_rts_flags.eof", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), RTS_FLAG_EOF
, NULL
, HFILL
}},
5987 { &hf_dcerpc_cn_rts_commands_nb
,
5988 { "RTS Number of Commands", "dcerpc.cn_rts_commands_nb", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
5989 { &hf_dcerpc_cn_rts_command
,
5990 { "RTS Command", "dcerpc.cn_rts_command", FT_UINT32
, BASE_HEX
, VALS(rts_command_vals
), 0x0, NULL
, HFILL
}},
5991 { &hf_dcerpc_cn_rts_command_receivewindowsize
,
5992 {"Receive Window Size", "dcerpc.cn_rts_command.receivewindowsize", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
5993 { &hf_dcerpc_cn_rts_command_fack_bytesreceived
,
5994 {"Bytes Received", "dcerpc.cn_rts_command.fack.bytesreceived", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
5995 { &hf_dcerpc_cn_rts_command_fack_availablewindow
,
5996 {"Available Window", "dcerpc.cn_rts_command.fack.availablewindow", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
5997 { &hf_dcerpc_cn_rts_command_fack_channelcookie
,
5998 {"Channel Cookie", "dcerpc.cn_rts_command.fack.channelcookie", FT_GUID
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
5999 { &hf_dcerpc_cn_rts_command_connectiontimeout
,
6000 {"Connection Timeout", "dcerpc.cn_rts_command.connectiontimeout", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
6001 { &hf_dcerpc_cn_rts_command_cookie
,
6002 {"Cookie", "dcerpc.cn_rts_command.cookie", FT_GUID
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
6003 { &hf_dcerpc_cn_rts_command_channellifetime
,
6004 {"Channel Lifetime", "dcerpc.cn_rts_command.channellifetime", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
6005 { &hf_dcerpc_cn_rts_command_clientkeepalive
,
6006 {"Client Keepalive", "dcerpc.cn_rts_command.clientkeepalive", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
6007 { &hf_dcerpc_cn_rts_command_version
,
6008 {"Version", "dcerpc.cn_rts_command.version", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
6009 { &hf_dcerpc_cn_rts_command_conformancecount
,
6010 {"Conformance Count", "dcerpc.cn_rts_command.padding.conformancecount", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
6011 { &hf_dcerpc_cn_rts_command_padding
,
6012 { "Padding", "dcerpc.cn_rts_command.padding.padding", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
6013 { &hf_dcerpc_cn_rts_command_addrtype
,
6014 { "Address Type", "dcerpc.cn_rts_command.addrtype", FT_UINT32
, BASE_DEC
, VALS(rts_addresstype_vals
), 0x0, NULL
, HFILL
}},
6015 { &hf_dcerpc_cn_rts_command_associationgroupid
,
6016 {"Association Group ID", "dcerpc.cn_rts_command.associationgroupid", FT_GUID
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
6017 { &hf_dcerpc_cn_rts_command_forwarddestination
,
6018 {"Forward Destination", "dcerpc.cn_rts_command.forwarddestination", FT_UINT32
, BASE_DEC
, VALS(rts_forward_destination_vals
), 0x0, NULL
, HFILL
}},
6019 { &hf_dcerpc_cn_rts_command_pingtrafficsentnotify
,
6020 {"Ping Traffic Sent Notify", "dcerpc.cn_rts_command.pingtrafficsentnotify", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
6022 static gint
*ett
[] = {
6024 &ett_dcerpc_cn_flags
,
6026 &ett_dcerpc_cn_iface
,
6027 &ett_dcerpc_cn_trans_syntax
,
6028 &ett_dcerpc_cn_trans_btfn
,
6029 &ett_dcerpc_cn_rts_flags
,
6030 &ett_dcerpc_cn_rts_command
,
6031 &ett_dcerpc_cn_rts_pdu
,
6033 &ett_dcerpc_dg_flags1
,
6034 &ett_dcerpc_dg_flags2
,
6035 &ett_dcerpc_pointer_data
,
6037 &ett_dcerpc_fragments
,
6038 &ett_dcerpc_fragment
,
6039 &ett_dcerpc_krb5_auth_verf
,
6042 static ei_register_info ei
[] = {
6043 { &ei_dcerpc_fragment
, { "dcerpc.fragment", PI_REASSEMBLE
, PI_CHAT
, "%s fragment", EXPFILL
}},
6044 { &ei_dcerpc_fragment_reassembled
, { "dcerpc.fragment_reassembled", PI_REASSEMBLE
, PI_CHAT
, "%s fragment, reassembled", EXPFILL
}},
6045 { &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
}},
6046 { &ei_dcerpc_no_request_found
, { "dcerpc.no_request_found", PI_SEQUENCE
, PI_NOTE
, "No request to this DCE/RPC call found", EXPFILL
}},
6047 { &ei_dcerpc_cn_status
, { "dcerpc.cn_status.expert", PI_RESPONSE_CODE
, PI_NOTE
, "Fault: %s", EXPFILL
}},
6048 { &ei_dcerpc_fragment_multiple
, { "dcerpc.fragment_multiple", PI_SEQUENCE
, PI_CHAT
, "Multiple DCE/RPC fragments/PDU's in one packet", EXPFILL
}},
6049 { &ei_dcerpc_context_change
, { "dcerpc.context_change", PI_SEQUENCE
, PI_CHAT
, "Context change: %s", EXPFILL
}},
6050 { &ei_dcerpc_bind_not_acknowledged
, { "dcerpc.bind_not_acknowledged", PI_SEQUENCE
, PI_WARN
, "Bind not acknowledged", EXPFILL
}},
6053 module_t
*dcerpc_module
;
6054 expert_module_t
* expert_dcerpc
;
6056 proto_dcerpc
= proto_register_protocol("Distributed Computing Environment / Remote Procedure Call (DCE/RPC)", "DCERPC", "dcerpc");
6057 proto_register_field_array(proto_dcerpc
, hf
, array_length(hf
));
6058 proto_register_subtree_array(ett
, array_length(ett
));
6059 expert_dcerpc
= expert_register_protocol(proto_dcerpc
);
6060 expert_register_field_array(expert_dcerpc
, ei
, array_length(ei
));
6062 register_init_routine(dcerpc_init_protocol
);
6063 dcerpc_module
= prefs_register_protocol(proto_dcerpc
, NULL
);
6064 prefs_register_bool_preference(dcerpc_module
,
6066 "Reassemble DCE/RPC messages spanning multiple TCP segments",
6067 "Whether the DCE/RPC dissector should reassemble messages"
6068 " spanning multiple TCP segments."
6069 " To use this option, you must also enable"
6070 " \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
6071 &dcerpc_cn_desegment
);
6072 prefs_register_bool_preference(dcerpc_module
,
6073 "reassemble_dcerpc",
6074 "Reassemble DCE/RPC fragments",
6075 "Whether the DCE/RPC dissector should reassemble fragmented DCE/RPC PDUs",
6076 &dcerpc_reassemble
);
6077 register_init_routine(dcerpc_reassemble_init
);
6078 dcerpc_uuids
= g_hash_table_new(dcerpc_uuid_hash
, dcerpc_uuid_equal
);
6079 dcerpc_tap
= register_tap("dcerpc");
6081 g_hook_list_init(&dcerpc_hooks_init_protos
, sizeof(GHook
));
6085 proto_reg_handoff_dcerpc(void)
6087 heur_dissector_add("tcp", dissect_dcerpc_cn_bs
, proto_dcerpc
);
6088 heur_dissector_add("netbios", dissect_dcerpc_cn_pk
, proto_dcerpc
);
6089 heur_dissector_add("udp", dissect_dcerpc_dg
, proto_dcerpc
);
6090 heur_dissector_add("smb_transact", dissect_dcerpc_cn_smbpipe
, proto_dcerpc
);
6091 heur_dissector_add("smb2_heur_subdissectors", dissect_dcerpc_cn_smb2
, proto_dcerpc
);
6092 heur_dissector_add("http", dissect_dcerpc_cn_bs
, proto_dcerpc
);
6093 dcerpc_smb_init(proto_dcerpc
);
6095 guids_add_uuid(&uuid_data_repr_proto
, "32bit NDR");
6096 guids_add_uuid(&uuid_ndr64
, "64bit NDR");
6097 guids_add_uuid(&uuid_bind_time_feature_nego_00
, "bind time feature negotiation");
6098 guids_add_uuid(&uuid_bind_time_feature_nego_01
, "bind time feature negotiation");
6099 guids_add_uuid(&uuid_bind_time_feature_nego_02
, "bind time feature negotiation");
6100 guids_add_uuid(&uuid_bind_time_feature_nego_03
, "bind time feature negotiation");
6101 guids_add_uuid(&uuid_asyncemsmdb
, "async MAPI");
6105 * Editor modelines - http://www.wireshark.org/tools/modelines.html
6110 * indent-tabs-mode: nil
6113 * vi: set shiftwidth=4 tabstop=8 expandtab:
6114 * :indentSize=4:tabSize=8:noTabs=true: