2 * Routines for DCERPC packet disassembly
3 * Copyright 2001, Todd Sabin <tas[AT]webspan.net>
4 * Copyright 2003, Tim Potter <tpot[AT]samba.org>
5 * Copyright 2010, Julien Kerihuel <j.kerihuel[AT]openchange.org>
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 /* The DCE RPC specification can be found at:
29 * http://www.opengroup.org/dce/
38 #include <epan/packet.h>
39 #include <epan/exceptions.h>
40 #include <epan/conversation.h>
41 #include <epan/prefs.h>
42 #include <epan/reassemble.h>
44 #include <epan/wmem/wmem.h>
45 #include <epan/expert.h>
46 #include <epan/strutil.h>
47 #include <epan/addr_resolv.h>
48 #include <epan/show_exception.h>
49 #include <epan/decode_as.h>
50 #include <epan/dissectors/packet-dcerpc.h>
51 #include <epan/dissectors/packet-dcerpc-nt.h>
53 static int dcerpc_tap = -1;
55 /* 32bit Network Data Representation, see DCE/RPC Appendix I */
56 static e_uuid_t uuid_data_repr_proto = { 0x8a885d04, 0x1ceb, 0x11c9,
57 { 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60 } };
59 /* 64bit Network Data Representation, introduced in Windows Server 2008 */
60 static e_uuid_t uuid_ndr64 = { 0x71710533, 0xbeba, 0x4937,
61 { 0x83, 0x19, 0xb5, 0xdb, 0xef, 0x9c, 0xcc, 0x36 } };
63 /* Bind Time Feature Negotiation, see [MS-RPCE] 3.3.1.5.3 */
64 static e_uuid_t uuid_bind_time_feature_nego_00 = { 0x6cb71c2c, 0x9812, 0x4540, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
65 static e_uuid_t uuid_bind_time_feature_nego_01 = { 0x6cb71c2c, 0x9812, 0x4540, { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
66 static e_uuid_t uuid_bind_time_feature_nego_02 = { 0x6cb71c2c, 0x9812, 0x4540, { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
67 static e_uuid_t uuid_bind_time_feature_nego_03 = { 0x6cb71c2c, 0x9812, 0x4540, { 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
69 /* see [MS-OXRPC] Appendix A: Full IDL, http://msdn.microsoft.com/en-us/library/ee217991%28v=exchg.80%29.aspx */
70 static e_uuid_t uuid_asyncemsmdb = { 0x5261574a, 0x4572, 0x206e,
71 { 0xb2, 0x68, 0x6b, 0x19, 0x92, 0x13, 0xb4, 0xe4 } };
73 static const value_string pckt_vals[] = {
74 { PDU_REQ, "Request"},
76 { PDU_RESP, "Response"},
77 { PDU_FAULT, "Fault"},
78 { PDU_WORKING, "Working"},
79 { PDU_NOCALL, "Nocall"},
80 { PDU_REJECT, "Reject"},
82 { PDU_CL_CANCEL, "Cl_cancel"},
84 { PDU_CANCEL_ACK, "Cancel_ack"},
86 { PDU_BIND_ACK, "Bind_ack"},
87 { PDU_BIND_NAK, "Bind_nak"},
88 { PDU_ALTER, "Alter_context"},
89 { PDU_ALTER_ACK, "Alter_context_resp"},
90 { PDU_AUTH3, "AUTH3"},
91 { PDU_SHUTDOWN, "Shutdown"},
92 { PDU_CO_CANCEL, "Co_cancel"},
93 { PDU_ORPHANED, "Orphaned"},
94 { PDU_RTS, "RPC-over-HTTP RTS"},
98 static const value_string drep_byteorder_vals[] = {
100 { 1, "Little-endian" },
104 static const value_string drep_character_vals[] = {
110 #define DCE_RPC_DREP_FP_IEEE 0
111 #define DCE_RPC_DREP_FP_VAX 1
112 #define DCE_RPC_DREP_FP_CRAY 2
113 #define DCE_RPC_DREP_FP_IBM 3
115 static const value_string drep_fp_vals[] = {
116 { DCE_RPC_DREP_FP_IEEE, "IEEE" },
117 { DCE_RPC_DREP_FP_VAX, "VAX" },
118 { DCE_RPC_DREP_FP_CRAY, "Cray" },
119 { DCE_RPC_DREP_FP_IBM, "IBM" },
124 * Authentication services.
126 static const value_string authn_protocol_vals[] = {
127 { DCE_C_RPC_AUTHN_PROTOCOL_NONE, "None" },
128 { DCE_C_RPC_AUTHN_PROTOCOL_KRB5, "Kerberos 5" },
129 { DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO, "SPNEGO" },
130 { DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP, "NTLMSSP" },
131 { DCE_C_RPC_AUTHN_PROTOCOL_GSS_SCHANNEL, "SCHANNEL SSP" },
132 { DCE_C_RPC_AUTHN_PROTOCOL_GSS_KERBEROS, "Kerberos SSP" },
133 { DCE_C_RPC_AUTHN_PROTOCOL_DPA,
134 "Distributed Password Authentication SSP"},
135 { DCE_C_RPC_AUTHN_PROTOCOL_MSN, "MSN SSP"},
136 { DCE_C_RPC_AUTHN_PROTOCOL_DIGEST, "Digest SSP"},
137 { DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN, "NETLOGON Secure Channel" },
138 { DCE_C_RPC_AUTHN_PROTOCOL_MQ, "MSMQ SSP"},
145 static const value_string authn_level_vals[] = {
146 { DCE_C_AUTHN_LEVEL_NONE, "None" },
147 { DCE_C_AUTHN_LEVEL_CONNECT, "Connect" },
148 { DCE_C_AUTHN_LEVEL_CALL, "Call" },
149 { DCE_C_AUTHN_LEVEL_PKT, "Packet" },
150 { DCE_C_AUTHN_LEVEL_PKT_INTEGRITY, "Packet integrity" },
151 { DCE_C_AUTHN_LEVEL_PKT_PRIVACY, "Packet privacy" },
156 * Flag bits in first flag field in connectionless PDU header.
158 #define PFCL1_RESERVED_01 0x01 /* Reserved for use by implementations */
159 #define PFCL1_LASTFRAG 0x02 /* If set, the PDU is the last
160 * fragment of a multi-PDU
162 #define PFCL1_FRAG 0x04 /* If set, the PDU is a fragment of
163 a multi-PDU transmission */
164 #define PFCL1_NOFACK 0x08 /* If set, the receiver is not
165 * requested to send a `fack' PDU
166 * for the fragment */
167 #define PFCL1_MAYBE 0x10 /* If set, the PDU is for a `maybe'
169 #define PFCL1_IDEMPOTENT 0x20 /* If set, the PDU is for an idempotent
171 #define PFCL1_BROADCAST 0x40 /* If set, the PDU is for a broadcast
173 #define PFCL1_RESERVED_80 0x80 /* Reserved for use by implementations */
176 * Flag bits in second flag field in connectionless PDU header.
178 #define PFCL2_RESERVED_01 0x01 /* Reserved for use by implementations */
179 #define PFCL2_CANCEL_PENDING 0x02 /* Cancel pending at the call end */
180 #define PFCL2_RESERVED_04 0x04 /* Reserved for future use */
181 #define PFCL2_RESERVED_08 0x08 /* Reserved for future use */
182 #define PFCL2_RESERVED_10 0x10 /* Reserved for future use */
183 #define PFCL2_RESERVED_20 0x20 /* Reserved for future use */
184 #define PFCL2_RESERVED_40 0x40 /* Reserved for future use */
185 #define PFCL2_RESERVED_80 0x80 /* Reserved for future use */
188 * Flag bits in connection-oriented PDU header.
190 #define PFC_FIRST_FRAG 0x01 /* First fragment */
191 #define PFC_LAST_FRAG 0x02 /* Last fragment */
192 #define PFC_PENDING_CANCEL 0x04 /* Cancel was pending at sender */
193 #define PFC_RESERVED_1 0x08
194 #define PFC_CONC_MPX 0x10 /* supports concurrent multiplexing
195 * of a single connection. */
196 #define PFC_DID_NOT_EXECUTE 0x20 /* only meaningful on `fault' packet;
197 * if true, guaranteed call did not
199 #define PFC_MAYBE 0x40 /* `maybe' call semantics requested */
200 #define PFC_OBJECT_UUID 0x80 /* if true, a non-nil object UUID
201 * was specified in the handle, and
202 * is present in the optional object
203 * field. If false, the object field
207 * Tests whether a connection-oriented PDU is fragmented; returns TRUE if
208 * it's not fragmented (i.e., this is both the first *and* last fragment),
209 * and FALSE otherwise.
211 #define PFC_NOT_FRAGMENTED(hdr) \
212 ((hdr->flags&(PFC_FIRST_FRAG|PFC_LAST_FRAG)) == (PFC_FIRST_FRAG|PFC_LAST_FRAG))
215 * Presentation context negotiation result.
217 static const value_string p_cont_result_vals[] = {
219 { 1, "User rejection" },
220 { 2, "Provider rejection" },
221 { 3, "Negotiate ACK" }, /* [MS-RPCE] 2.2.2.4 */
226 * Presentation context negotiation rejection reasons.
228 static const value_string p_provider_reason_vals[] = {
229 { 0, "Reason not specified" },
230 { 1, "Abstract syntax not supported" },
231 { 2, "Proposed transfer syntaxes not supported" },
232 { 3, "Local limit exceeded" },
239 #define REASON_NOT_SPECIFIED 0
240 #define TEMPORARY_CONGESTION 1
241 #define LOCAL_LIMIT_EXCEEDED 2
242 #define CALLED_PADDR_UNKNOWN 3 /* not used */
243 #define PROTOCOL_VERSION_NOT_SUPPORTED 4
244 #define DEFAULT_CONTEXT_NOT_SUPPORTED 5 /* not used */
245 #define USER_DATA_NOT_READABLE 6 /* not used */
246 #define NO_PSAP_AVAILABLE 7 /* not used */
247 #define AUTH_TYPE_NOT_RECOGNIZED 8 /* [MS-RPCE] 2.2.2.5 */
248 #define INVALID_CHECKSUM 9 /* [MS-RPCE] 2.2.2.5 */
250 static const value_string reject_reason_vals[] = {
251 { REASON_NOT_SPECIFIED, "Reason not specified" },
252 { TEMPORARY_CONGESTION, "Temporary congestion" },
253 { LOCAL_LIMIT_EXCEEDED, "Local limit exceeded" },
254 { CALLED_PADDR_UNKNOWN, "Called paddr unknown" },
255 { PROTOCOL_VERSION_NOT_SUPPORTED, "Protocol version not supported" },
256 { DEFAULT_CONTEXT_NOT_SUPPORTED, "Default context not supported" },
257 { USER_DATA_NOT_READABLE, "User data not readable" },
258 { NO_PSAP_AVAILABLE, "No PSAP available" },
259 { AUTH_TYPE_NOT_RECOGNIZED, "Authentication type not recognized" },
260 { INVALID_CHECKSUM, "Invalid checksum" },
265 * Reject status codes.
267 static const value_string reject_status_vals[] = {
268 { 0, "Stub-defined exception" },
269 { 0x00000001, "nca_s_fault_other" },
270 { 0x00000005, "nca_s_fault_access_denied" },
271 { 0x000006f7, "nca_s_fault_ndr" },
272 { 0x000006d8, "nca_s_fault_cant_perform" },
273 { 0x1c000001, "nca_s_fault_int_div_by_zero" },
274 { 0x1c000002, "nca_s_fault_addr_error" },
275 { 0x1c000003, "nca_s_fault_fp_div_zero" },
276 { 0x1c000004, "nca_s_fault_fp_underflow" },
277 { 0x1c000005, "nca_s_fault_fp_overflow" },
278 { 0x1c000006, "nca_s_fault_invalid_tag" },
279 { 0x1c000007, "nca_s_fault_invalid_bound" },
280 { 0x1c000008, "nca_rpc_version_mismatch" },
281 { 0x1c000009, "nca_unspec_reject" },
282 { 0x1c00000a, "nca_s_bad_actid" },
283 { 0x1c00000b, "nca_who_are_you_failed" },
284 { 0x1c00000c, "nca_manager_not_entered" },
285 { 0x1c00000d, "nca_s_fault_cancel" },
286 { 0x1c00000e, "nca_s_fault_ill_inst" },
287 { 0x1c00000f, "nca_s_fault_fp_error" },
288 { 0x1c000010, "nca_s_fault_int_overflow" },
289 { 0x1c000014, "nca_s_fault_pipe_empty" },
290 { 0x1c000015, "nca_s_fault_pipe_closed" },
291 { 0x1c000016, "nca_s_fault_pipe_order" },
292 { 0x1c000017, "nca_s_fault_pipe_discipline" },
293 { 0x1c000018, "nca_s_fault_pipe_comm_error" },
294 { 0x1c000019, "nca_s_fault_pipe_memory" },
295 { 0x1c00001a, "nca_s_fault_context_mismatch" },
296 { 0x1c00001b, "nca_s_fault_remote_no_memory" },
297 { 0x1c00001c, "nca_invalid_pres_context_id" },
298 { 0x1c00001d, "nca_unsupported_authn_level" },
299 { 0x1c00001f, "nca_invalid_checksum" },
300 { 0x1c000020, "nca_invalid_crc" },
301 { 0x1c000021, "ncs_s_fault_user_defined" },
302 { 0x1c000022, "nca_s_fault_tx_open_failed" },
303 { 0x1c000023, "nca_s_fault_codeset_conv_error" },
304 { 0x1c000024, "nca_s_fault_object_not_found" },
305 { 0x1c000025, "nca_s_fault_no_client_stub" },
306 { 0x1c010002, "nca_op_rng_error" },
307 { 0x1c010003, "nca_unk_if"},
308 { 0x1c010006, "nca_wrong_boot_time" },
309 { 0x1c010009, "nca_s_you_crashed" },
310 { 0x1c01000b, "nca_proto_error" },
311 { 0x1c010013, "nca_out_args_too_big" },
312 { 0x1c010014, "nca_server_too_busy" },
313 { 0x1c010017, "nca_unsupported_type" },
314 /* MS Windows specific values
315 * see: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/system_error_codes__1700-3999_.asp
316 * and: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/seccrypto/security/common_hresult_values.asp
317 * and: http://www.megos.ch/support/doserrors.txt
319 * XXX - we might need a way to dynamically add entries here, as higher layer protocols use these values too,
320 * at least MS protocols (like DCOM) do it that way ... */
321 { 0x80004001, "E_NOTIMPL" },
322 { 0x80004003, "E_POINTER" },
323 { 0x80004004, "E_ABORT" },
324 { 0x8000FFFF, "E_UNEXPECTED" },
325 { 0x80010105, "RPC_E_SERVERFAULT" },
326 { 0x80010108, "RPC_E_DISCONNECTED" },
327 { 0x80010113, "RPC_E_INVALID_IPID" },
328 { 0x8001011F, "RPC_E_TIMEOUT" },
329 { 0x80020003, "DISP_E_MEMBERNOTFOUND" },
330 { 0x80020006, "DISP_E_UNKNOWNNAME" },
331 { 0x8002000E, "DISP_E_BADPARAMCOUNT" },
332 { 0x8004CB00, "CBA_E_MALFORMED" },
333 { 0x8004CB01, "CBA_E_UNKNOWNOBJECT" },
334 { 0x8004CB05, "CBA_E_INVALIDID" },
335 { 0x8004CB09, "CBA_E_INVALIDCOOKIE" },
336 { 0x8004CB0B, "CBA_E_QOSTYPEUNSUPPORTED" },
337 { 0x8004CB0C, "CBA_E_QOSVALUEUNSUPPORTED" },
338 { 0x8004CB0F, "CBA_E_NOTAPPLICABLE" },
339 { 0x8004CB12, "CBA_E_LIMITVIOLATION" },
340 { 0x8004CB13, "CBA_E_QOSTYPENOTAPPLICABLE" },
341 { 0x8004CB18, "CBA_E_OUTOFPARTNERACCOS" },
342 { 0x8004CB1C, "CBA_E_FLAGUNSUPPORTED" },
343 { 0x8004CB23, "CBA_E_FRAMECOUNTUNSUPPORTED" },
344 { 0x8004CB25, "CBA_E_MODECHANGE" },
345 { 0x8007000E, "E_OUTOFMEMORY" },
346 { 0x80070057, "E_INVALIDARG" },
347 { 0x800706d1, "RPC_S_PROCNUM_OUT_OF_RANGE" },
348 { 0x80070776, "OR_INVALID_OXID" },
356 #define RTS_FLAG_NONE 0x0000
357 #define RTS_FLAG_PING 0x0001
358 #define RTS_FLAG_OTHER_CMD 0x0002
359 #define RTS_FLAG_RECYCLE_CHANNEL 0x0004
360 #define RTS_FLAG_IN_CHANNEL 0x0008
361 #define RTS_FLAG_OUT_CHANNEL 0x0010
362 #define RTS_FLAG_EOF 0x0020
363 #define RTS_FLAG_ECHO 0x0040
369 #define RTS_CMD_RECEIVEWINDOWSIZE 0x0
370 #define RTS_CMD_FLOWCONTROLACK 0x1
371 #define RTS_CMD_CONNECTIONTIMEOUT 0x2
372 #define RTS_CMD_COOKIE 0x3
373 #define RTS_CMD_CHANNELLIFETIME 0x4
374 #define RTS_CMD_CLIENTKEEPALIVE 0x5
375 #define RTS_CMD_VERSION 0x6
376 #define RTS_CMD_EMPTY 0x7
377 #define RTS_CMD_PADDING 0x8
378 #define RTS_CMD_NEGATIVEANCE 0x9
379 #define RTS_CMD_ANCE 0xA
380 #define RTS_CMD_CLIENTADDRESS 0xB
381 #define RTS_CMD_ASSOCIATIONGROUPID 0xC
382 #define RTS_CMD_DESTINATION 0xD
383 #define RTS_CMD_PINGTRAFFICSENTNOTIFY 0xE
385 static const value_string rts_command_vals[] = {
386 { RTS_CMD_RECEIVEWINDOWSIZE, "ReceiveWindowSize" },
387 { RTS_CMD_FLOWCONTROLACK, "FlowControlAck" },
388 { RTS_CMD_CONNECTIONTIMEOUT, "ConnectionTimeOut" },
389 { RTS_CMD_COOKIE, "Cookie" },
390 { RTS_CMD_CHANNELLIFETIME, "ChannelLifetime" },
391 { RTS_CMD_CLIENTKEEPALIVE, "ClientKeepalive" },
392 { RTS_CMD_VERSION, "Version" },
393 { RTS_CMD_EMPTY, "Empty" },
394 { RTS_CMD_PADDING, "Padding" },
395 { RTS_CMD_NEGATIVEANCE, "NegativeANCE" },
396 { RTS_CMD_ANCE, "ANCE" },
397 { RTS_CMD_CLIENTADDRESS, "ClientAddress" },
398 { RTS_CMD_ASSOCIATIONGROUPID, "AssociationGroupId" },
399 { RTS_CMD_DESTINATION, "Destination" },
400 { RTS_CMD_PINGTRAFFICSENTNOTIFY, "PingTrafficSentNotify" },
405 * RTS client address type
410 static const value_string rts_addresstype_vals[] = {
411 { RTS_IPV4, "IPV4" },
412 { RTS_IPV6, "IPV6" },
417 * RTS Forward destination
420 static const value_string rts_forward_destination_vals[] = {
422 { 0x1, "FDInProxy" },
424 { 0x3, "FDOutProxy" },
428 /* we need to keep track of what transport were used, ie what handle we came
429 * in through so we know what kind of pinfo->dce_smb_fid was passed to us.
431 /* Value of -1 is reserved for "not DCE packet" in packet_info.dcetransporttype. */
432 #define DCE_TRANSPORT_UNKNOWN 0
433 #define DCE_CN_TRANSPORT_SMBPIPE 1
436 static int proto_dcerpc = -1;
439 static int hf_dcerpc_request_in = -1;
440 static int hf_dcerpc_time = -1;
441 static int hf_dcerpc_response_in = -1;
442 static int hf_dcerpc_ver = -1;
443 static int hf_dcerpc_ver_minor = -1;
444 static int hf_dcerpc_packet_type = -1;
445 static int hf_dcerpc_cn_flags = -1;
446 static int hf_dcerpc_cn_flags_first_frag = -1;
447 static int hf_dcerpc_cn_flags_last_frag = -1;
448 static int hf_dcerpc_cn_flags_cancel_pending = -1;
449 static int hf_dcerpc_cn_flags_reserved = -1;
450 static int hf_dcerpc_cn_flags_mpx = -1;
451 static int hf_dcerpc_cn_flags_dne = -1;
452 static int hf_dcerpc_cn_flags_maybe = -1;
453 static int hf_dcerpc_cn_flags_object = -1;
454 static int hf_dcerpc_drep = -1;
455 int hf_dcerpc_drep_byteorder = -1;
456 static int hf_dcerpc_drep_character = -1;
457 static int hf_dcerpc_drep_fp = -1;
458 static int hf_dcerpc_cn_frag_len = -1;
459 static int hf_dcerpc_cn_auth_len = -1;
460 static int hf_dcerpc_cn_call_id = -1;
461 static int hf_dcerpc_cn_max_xmit = -1;
462 static int hf_dcerpc_cn_max_recv = -1;
463 static int hf_dcerpc_cn_assoc_group = -1;
464 static int hf_dcerpc_cn_num_ctx_items = -1;
465 static int hf_dcerpc_cn_ctx_item = -1;
466 static int hf_dcerpc_cn_ctx_id = -1;
467 static int hf_dcerpc_cn_num_trans_items = -1;
468 static int hf_dcerpc_cn_bind_abstract_syntax = -1;
469 static int hf_dcerpc_cn_bind_if_id = -1;
470 static int hf_dcerpc_cn_bind_if_ver = -1;
471 static int hf_dcerpc_cn_bind_if_ver_minor = -1;
472 static int hf_dcerpc_cn_bind_trans_syntax = -1;
473 static int hf_dcerpc_cn_bind_trans_id = -1;
474 static int hf_dcerpc_cn_bind_trans_ver = -1;
475 static int hf_dcerpc_cn_bind_trans_btfn_01 = -1;
476 static int hf_dcerpc_cn_bind_trans_btfn_02 = -1;
477 static int hf_dcerpc_cn_alloc_hint = -1;
478 static int hf_dcerpc_cn_sec_addr_len = -1;
479 static int hf_dcerpc_cn_sec_addr = -1;
480 static int hf_dcerpc_cn_num_results = -1;
481 static int hf_dcerpc_cn_ack_result = -1;
482 static int hf_dcerpc_cn_ack_reason = -1;
483 static int hf_dcerpc_cn_ack_trans_id = -1;
484 static int hf_dcerpc_cn_ack_trans_ver = -1;
485 static int hf_dcerpc_cn_ack_btfn = -1;
486 static int hf_dcerpc_cn_reject_reason = -1;
487 static int hf_dcerpc_cn_num_protocols = -1;
488 static int hf_dcerpc_cn_protocol_ver_major = -1;
489 static int hf_dcerpc_cn_protocol_ver_minor = -1;
490 static int hf_dcerpc_cn_cancel_count = -1;
491 static int hf_dcerpc_cn_status = -1;
492 static int hf_dcerpc_cn_deseg_req = -1;
493 static int hf_dcerpc_cn_rts_flags = -1;
494 static int hf_dcerpc_cn_rts_flags_none = -1;
495 static int hf_dcerpc_cn_rts_flags_ping = -1;
496 static int hf_dcerpc_cn_rts_flags_other_cmd = -1;
497 static int hf_dcerpc_cn_rts_flags_recycle_channel = -1;
498 static int hf_dcerpc_cn_rts_flags_in_channel = -1;
499 static int hf_dcerpc_cn_rts_flags_out_channel = -1;
500 static int hf_dcerpc_cn_rts_flags_eof = -1;
501 static int hf_dcerpc_cn_rts_commands_nb = -1;
502 static int hf_dcerpc_cn_rts_command = -1;
503 static int hf_dcerpc_cn_rts_command_receivewindowsize = -1;
504 static int hf_dcerpc_cn_rts_command_fack_bytesreceived = -1;
505 static int hf_dcerpc_cn_rts_command_fack_availablewindow = -1;
506 static int hf_dcerpc_cn_rts_command_fack_channelcookie = -1;
507 static int hf_dcerpc_cn_rts_command_connectiontimeout = -1;
508 static int hf_dcerpc_cn_rts_command_cookie = -1;
509 static int hf_dcerpc_cn_rts_command_channellifetime = -1;
510 static int hf_dcerpc_cn_rts_command_clientkeepalive = -1;
511 static int hf_dcerpc_cn_rts_command_version = -1;
512 static int hf_dcerpc_cn_rts_command_conformancecount = -1;
513 static int hf_dcerpc_cn_rts_command_padding = -1;
514 static int hf_dcerpc_cn_rts_command_addrtype = -1;
515 static int hf_dcerpc_cn_rts_command_associationgroupid = -1;
516 static int hf_dcerpc_cn_rts_command_forwarddestination = -1;
517 static int hf_dcerpc_cn_rts_command_pingtrafficsentnotify = -1;
518 static int hf_dcerpc_auth_type = -1;
519 static int hf_dcerpc_auth_level = -1;
520 static int hf_dcerpc_auth_pad_len = -1;
521 static int hf_dcerpc_auth_rsrvd = -1;
522 static int hf_dcerpc_auth_ctx_id = -1;
523 static int hf_dcerpc_dg_flags1 = -1;
524 static int hf_dcerpc_dg_flags1_rsrvd_01 = -1;
525 static int hf_dcerpc_dg_flags1_last_frag = -1;
526 static int hf_dcerpc_dg_flags1_frag = -1;
527 static int hf_dcerpc_dg_flags1_nofack = -1;
528 static int hf_dcerpc_dg_flags1_maybe = -1;
529 static int hf_dcerpc_dg_flags1_idempotent = -1;
530 static int hf_dcerpc_dg_flags1_broadcast = -1;
531 static int hf_dcerpc_dg_flags1_rsrvd_80 = -1;
532 static int hf_dcerpc_dg_flags2 = -1;
533 static int hf_dcerpc_dg_flags2_rsrvd_01 = -1;
534 static int hf_dcerpc_dg_flags2_cancel_pending = -1;
535 static int hf_dcerpc_dg_flags2_rsrvd_04 = -1;
536 static int hf_dcerpc_dg_flags2_rsrvd_08 = -1;
537 static int hf_dcerpc_dg_flags2_rsrvd_10 = -1;
538 static int hf_dcerpc_dg_flags2_rsrvd_20 = -1;
539 static int hf_dcerpc_dg_flags2_rsrvd_40 = -1;
540 static int hf_dcerpc_dg_flags2_rsrvd_80 = -1;
541 static int hf_dcerpc_dg_serial_hi = -1;
542 static int hf_dcerpc_obj_id = -1;
543 static int hf_dcerpc_dg_if_id = -1;
544 static int hf_dcerpc_dg_act_id = -1;
545 static int hf_dcerpc_dg_serial_lo = -1;
546 static int hf_dcerpc_dg_ahint = -1;
547 static int hf_dcerpc_dg_ihint = -1;
548 static int hf_dcerpc_dg_frag_len = -1;
549 static int hf_dcerpc_dg_frag_num = -1;
550 static int hf_dcerpc_dg_auth_proto = -1;
551 static int hf_dcerpc_opnum = -1;
552 static int hf_dcerpc_dg_seqnum = -1;
553 static int hf_dcerpc_dg_server_boot = -1;
554 static int hf_dcerpc_dg_if_ver = -1;
555 static int hf_dcerpc_krb5_av_prot_level = -1;
556 static int hf_dcerpc_krb5_av_key_vers_num = -1;
557 static int hf_dcerpc_krb5_av_key_auth_verifier = -1;
558 static int hf_dcerpc_dg_cancel_vers = -1;
559 static int hf_dcerpc_dg_cancel_id = -1;
560 static int hf_dcerpc_dg_server_accepting_cancels = -1;
561 static int hf_dcerpc_dg_fack_vers = -1;
562 static int hf_dcerpc_dg_fack_window_size = -1;
563 static int hf_dcerpc_dg_fack_max_tsdu = -1;
564 static int hf_dcerpc_dg_fack_max_frag_size = -1;
565 static int hf_dcerpc_dg_fack_serial_num = -1;
566 static int hf_dcerpc_dg_fack_selack_len = -1;
567 static int hf_dcerpc_dg_fack_selack = -1;
568 static int hf_dcerpc_dg_status = -1;
569 static int hf_dcerpc_array_max_count = -1;
570 static int hf_dcerpc_array_offset = -1;
571 static int hf_dcerpc_array_actual_count = -1;
572 static int hf_dcerpc_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;
585 static int hf_dcerpc_sec_vt_command = -1;
586 static int hf_dcerpc_sec_vt_command_cmd = -1;
587 static int hf_dcerpc_sec_vt_command_end = -1;
588 static int hf_dcerpc_sec_vt_command_must = -1;
589 static int hf_dcerpc_sec_vt_command_length = -1;
590 static int hf_dcerpc_sec_vt_bitmask = -1;
591 static int hf_dcerpc_sec_vt_bitmask_sign = -1;
592 static int hf_dcerpc_sec_vt_pcontext_uuid = -1;
593 static int hf_dcerpc_sec_vt_pcontext_ver = -1;
595 static const int* sec_vt_command_fields[] = {
596 &hf_dcerpc_sec_vt_command_cmd,
597 &hf_dcerpc_sec_vt_command_end,
598 &hf_dcerpc_sec_vt_command_must,
602 static const int* sec_vt_bitmask_fields[] = {
603 &hf_dcerpc_sec_vt_bitmask_sign,
607 static const value_string sec_vt_command_cmd_vals[] = {
615 static gint ett_dcerpc = -1;
616 static gint ett_dcerpc_cn_flags = -1;
617 static gint ett_dcerpc_cn_ctx = -1;
618 static gint ett_dcerpc_cn_iface = -1;
619 static gint ett_dcerpc_cn_trans_syntax = -1;
620 static gint ett_dcerpc_cn_trans_btfn = -1;
621 static gint ett_dcerpc_cn_rts_flags = -1;
622 static gint ett_dcerpc_cn_rts_command = -1;
623 static gint ett_dcerpc_cn_rts_pdu = -1;
624 static gint ett_dcerpc_drep = -1;
625 static gint ett_dcerpc_dg_flags1 = -1;
626 static gint ett_dcerpc_dg_flags2 = -1;
627 static gint ett_dcerpc_pointer_data = -1;
628 static gint ett_dcerpc_string = -1;
629 static gint ett_dcerpc_fragments = -1;
630 static gint ett_dcerpc_fragment = -1;
631 static gint ett_dcerpc_krb5_auth_verf = -1;
632 static gint ett_dcerpc_verification_trailer = -1;
633 static gint ett_dcerpc_sec_vt_command = -1;
634 static gint ett_dcerpc_sec_vt_bitmask = -1;
635 static gint ett_dcerpc_sec_vt_pcontext = -1;
636 static gint ett_dcerpc_sec_vt_header = -1;
638 static expert_field ei_dcerpc_fragment_multiple = EI_INIT;
639 static expert_field ei_dcerpc_cn_status = EI_INIT;
640 static expert_field ei_dcerpc_fragment_reassembled = EI_INIT;
641 static expert_field ei_dcerpc_fragment = EI_INIT;
642 static expert_field ei_dcerpc_no_request_found = EI_INIT;
643 static expert_field ei_dcerpc_context_change = EI_INIT;
644 static expert_field ei_dcerpc_cn_ctx_id_no_bind = EI_INIT;
645 static expert_field ei_dcerpc_bind_not_acknowledged = EI_INIT;
648 static GSList *decode_dcerpc_bindings = NULL;
650 * To keep track of ctx_id mappings.
652 * Every time we see a bind call we update this table.
653 * Note that we always specify a SMB FID. For non-SMB transports this
656 static GHashTable *dcerpc_binds = NULL;
658 typedef struct _dcerpc_bind_key {
659 conversation_t *conv;
664 typedef struct _dcerpc_bind_value {
670 /* Extra data for DCERPC handling and tracking of context ids */
671 typedef struct _dcerpc_decode_as_data {
672 guint16 dcectxid; /**< Context ID (DCERPC-specific) */
673 int dcetransporttype; /**< Transport type
674 * Value -1 means "not a DCERPC packet"
676 guint16 dcetransportsalt; /**< fid: if transporttype==DCE_CN_TRANSPORT_SMBPIPE */
677 } dcerpc_decode_as_data;
679 static dcerpc_decode_as_data*
680 dcerpc_get_decode_data(packet_info* pinfo)
682 dcerpc_decode_as_data* data = (dcerpc_decode_as_data*)p_get_proto_data(pinfo->pool, pinfo, proto_dcerpc, 0);
685 data = wmem_new0(pinfo->pool, dcerpc_decode_as_data);
686 data->dcetransporttype = -1;
687 p_add_proto_data(pinfo->pool, pinfo, proto_dcerpc, 0, data);
694 * Registers a conversation/UUID binding association, so that
695 * we can invoke the proper sub-dissector for a given DCERPC
698 * @param binding all values needed to create and bind a new conversation
700 * @return Pointer to newly-added UUID/conversation binding.
702 static struct _dcerpc_bind_value *
703 dcerpc_add_conv_to_bind_table(decode_dcerpc_bind_values_t *binding)
705 dcerpc_bind_value *bind_value;
706 dcerpc_bind_key *key;
707 conversation_t *conv;
709 conv = find_conversation(
719 conv = conversation_new(
729 bind_value = (dcerpc_bind_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_value));
730 bind_value->uuid = binding->uuid;
731 bind_value->ver = binding->ver;
732 /* For now, assume all DCE/RPC we pick from "decode as" is using
733 standard ndr and not ndr64.
734 We should make this selectable from the dialog in the future
736 bind_value->transport = uuid_data_repr_proto;
738 key = (dcerpc_bind_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_key));
740 key->ctx_id = binding->ctx_id;
741 key->smb_fid = binding->smb_fid;
743 /* add this entry to the bind table */
744 g_hash_table_insert(dcerpc_binds, key, bind_value);
750 /* inject one of our bindings into the dcerpc binding table */
752 decode_dcerpc_inject_binding(gpointer data, gpointer user_data _U_)
754 dcerpc_add_conv_to_bind_table((decode_dcerpc_bind_values_t *) data);
757 /* inject all of our bindings into the dcerpc binding table */
759 decode_dcerpc_inject_bindings(void) {
760 g_slist_foreach(decode_dcerpc_bindings, decode_dcerpc_inject_binding, NULL /* user_data */);
765 decode_dcerpc_binding_free(void *binding_in)
767 decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t *)binding_in;
769 g_free((void *) binding->addr_a.data);
770 g_free((void *) binding->addr_b.data);
772 g_string_free(binding->ifname, TRUE);
777 dcerpc_decode_as_free(gpointer value)
779 decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t *)value;
781 decode_dcerpc_binding_free(binding);
784 /* removes all bindings */
786 decode_dcerpc_reset_all(void)
788 decode_dcerpc_bind_values_t *binding;
790 while (decode_dcerpc_bindings) {
791 binding = (decode_dcerpc_bind_values_t *)decode_dcerpc_bindings->data;
793 decode_dcerpc_binding_free(binding);
794 decode_dcerpc_bindings = g_slist_remove(
795 decode_dcerpc_bindings,
796 decode_dcerpc_bindings->data);
802 decode_dcerpc_add_show_list(decode_add_show_list_func func, gpointer user_data)
804 g_slist_foreach(decode_dcerpc_bindings, func, user_data);
808 dcerpc_prompt(packet_info *pinfo, gchar* result)
810 GString *str = g_string_new("Replace binding between:\r\n"),
811 *address_str = g_string_new("");
812 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
814 switch (pinfo->ptype) {
816 g_string_append(address_str, "Address: ToBeDone TCP port");
819 g_string_append(address_str, "Address: ToBeDone UDP port");
822 g_string_append(address_str, "Address: ToBeDone Unknown port type");
825 g_string_append_printf(str, "%s: %u\r\n", address_str->str, pinfo->srcport);
826 g_string_append(str, "&\r\n");
827 g_string_append_printf(str, "%s: %u\r\n", address_str->str, pinfo->destport);
828 g_string_append_printf(str, "&\r\nContext ID: %u\r\n", decode_data->dcectxid);
829 g_string_append_printf(str, "&\r\nSMB FID: %u\r\n", dcerpc_get_transport_salt(pinfo));
830 g_string_append(str, "with:\r\n");
832 g_strlcpy(result, str->str, MAX_DECODE_AS_PROMPT_LEN);
833 g_string_free(str, TRUE);
834 g_string_free(address_str, TRUE);
838 dcerpc_value(packet_info *pinfo)
840 decode_dcerpc_bind_values_t *binding;
841 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
844 binding = g_new(decode_dcerpc_bind_values_t,1);
845 COPY_ADDRESS(&binding->addr_a, &pinfo->src);
846 COPY_ADDRESS(&binding->addr_b, &pinfo->dst);
847 binding->ptype = pinfo->ptype;
848 binding->port_a = pinfo->srcport;
849 binding->port_b = pinfo->destport;
850 binding->ctx_id = decode_data->dcectxid;
851 binding->smb_fid = dcerpc_get_transport_salt(pinfo);
852 binding->ifname = NULL;
853 /*binding->uuid = NULL;*/
859 struct dcerpc_decode_as_populate
861 decode_as_add_to_list_func add_to_list;
866 decode_dcerpc_add_to_list(gpointer key, gpointer value, gpointer user_data)
868 struct dcerpc_decode_as_populate* populate = (struct dcerpc_decode_as_populate*)user_data;
870 /*dcerpc_uuid_key *k = key;*/
871 dcerpc_uuid_value *v = (dcerpc_uuid_value *)value;
873 if (strcmp(v->name, "(none)"))
874 populate->add_to_list("DCE-RPC", v->name, key, populate->ui_element);
878 dcerpc_populate_list(const gchar *table_name _U_, decode_as_add_to_list_func add_to_list, gpointer ui_element)
880 struct dcerpc_decode_as_populate populate;
882 populate.add_to_list = add_to_list;
883 populate.ui_element = ui_element;
885 g_hash_table_foreach(dcerpc_uuids, decode_dcerpc_add_to_list, &populate);
888 /* compare two bindings (except the interface related things, e.g. uuid) */
890 decode_dcerpc_binding_cmp(gconstpointer a, gconstpointer b)
892 const decode_dcerpc_bind_values_t *binding_a = (const decode_dcerpc_bind_values_t *)a;
893 const decode_dcerpc_bind_values_t *binding_b = (const decode_dcerpc_bind_values_t *)b;
896 /* don't compare uuid and ver! */
898 ADDRESSES_EQUAL(&binding_a->addr_a, &binding_b->addr_a) &&
899 ADDRESSES_EQUAL(&binding_a->addr_b, &binding_b->addr_b) &&
900 binding_a->ptype == binding_b->ptype &&
901 binding_a->port_a == binding_b->port_a &&
902 binding_a->port_b == binding_b->port_b &&
903 binding_a->ctx_id == binding_b->ctx_id &&
904 binding_a->smb_fid == binding_b->smb_fid)
914 /* remove a binding (looking the same way as the given one) */
916 decode_dcerpc_binding_reset(const char *name _U_, const gpointer pattern)
918 decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t*)pattern;
920 decode_dcerpc_bind_values_t *old_binding;
922 /* find the old binding (if it exists) */
923 le = g_slist_find_custom(decode_dcerpc_bindings,
925 decode_dcerpc_binding_cmp);
929 old_binding = (decode_dcerpc_bind_values_t *)le->data;
931 decode_dcerpc_bindings = g_slist_remove(decode_dcerpc_bindings, le->data);
933 g_free((void *) old_binding->addr_a.data);
934 g_free((void *) old_binding->addr_b.data);
935 g_string_free(old_binding->ifname, TRUE);
941 dcerpc_decode_as_change(const char *name, const gpointer pattern, gpointer handle, gchar* list_name)
943 decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t*)pattern;
944 decode_dcerpc_bind_values_t *stored_binding;
945 dcerpc_uuid_key *key = *((dcerpc_uuid_key**)handle);
948 binding->ifname = g_string_new(list_name);
949 binding->uuid = key->uuid;
950 binding->ver = key->ver;
952 /* remove a probably existing old binding */
953 decode_dcerpc_binding_reset(name, binding);
955 /* clone the new binding and append it to the list */
956 stored_binding = g_new(decode_dcerpc_bind_values_t,1);
957 *stored_binding = *binding;
958 COPY_ADDRESS(&stored_binding->addr_a, &binding->addr_a);
959 COPY_ADDRESS(&stored_binding->addr_b, &binding->addr_b);
960 stored_binding->ifname = g_string_new(binding->ifname->str);
962 decode_dcerpc_bindings = g_slist_append (decode_dcerpc_bindings, stored_binding);
967 static const fragment_items dcerpc_frag_items = {
968 &ett_dcerpc_fragments,
969 &ett_dcerpc_fragment,
971 &hf_dcerpc_fragments,
973 &hf_dcerpc_fragment_overlap,
974 &hf_dcerpc_fragment_overlap_conflict,
975 &hf_dcerpc_fragment_multiple_tails,
976 &hf_dcerpc_fragment_too_long_fragment,
977 &hf_dcerpc_fragment_error,
978 &hf_dcerpc_fragment_count,
980 &hf_dcerpc_reassembled_length,
981 /* Reassembled data field */
986 /* list of hooks to be called when init_protocols is done */
987 GHookList dcerpc_hooks_init_protos;
992 static dcerpc_info di[20];
993 static int di_counter = 0;
996 if (di_counter >= 20) {
1000 memset(&di[di_counter], 0, sizeof(dcerpc_info));
1001 di[di_counter].dcerpc_procedure_name = "";
1003 return &di[di_counter];
1006 /* try to desegment big DCE/RPC packets over TCP? */
1007 static gboolean dcerpc_cn_desegment = TRUE;
1009 /* reassemble DCE/RPC fragments */
1010 /* reassembly of cl dcerpc fragments will not work for the case where ONE frame
1011 might contain multiple dcerpc fragments for different PDUs.
1012 this case would be so unusual/weird so if you got captures like that:
1015 reassembly of co dcerpc fragments will not work for the case where TCP/SMB frames
1016 are coming in out of sequence, but that will hurt in a lot of other places as well.
1018 static gboolean dcerpc_reassemble = TRUE;
1019 static reassembly_table dcerpc_co_reassembly_table;
1020 static reassembly_table dcerpc_cl_reassembly_table;
1022 typedef struct _dcerpc_fragment_key {
1027 } dcerpc_fragment_key;
1030 dcerpc_fragment_hash(gconstpointer k)
1032 const dcerpc_fragment_key* key = (const dcerpc_fragment_key*) k;
1037 hash_val += key->id;
1038 hash_val += key->act_id.Data1;
1039 hash_val += key->act_id.Data2 << 16;
1040 hash_val += key->act_id.Data3;
1046 dcerpc_fragment_equal(gconstpointer k1, gconstpointer k2)
1048 const dcerpc_fragment_key* key1 = (const dcerpc_fragment_key*) k1;
1049 const dcerpc_fragment_key* key2 = (const dcerpc_fragment_key*) k2;
1051 /*key.id is the first item to compare since item is most
1052 likely to differ between sessions, thus shortcircuiting
1053 the comparison of addresses.
1055 return (((key1->id == key2->id)
1056 && (ADDRESSES_EQUAL(&key1->src, &key2->src))
1057 && (ADDRESSES_EQUAL(&key1->dst, &key2->dst))
1058 && (memcmp (&key1->act_id, &key2->act_id, sizeof (e_uuid_t)) == 0))
1062 /* allocate a persistent dcerpc fragment key to insert in the hash */
1064 dcerpc_fragment_temporary_key(const packet_info *pinfo, const guint32 id,
1067 dcerpc_fragment_key *key = g_slice_new(dcerpc_fragment_key);
1068 e_dce_dg_common_hdr_t *hdr = (e_dce_dg_common_hdr_t *)data;
1070 key->src = pinfo->src;
1071 key->dst = pinfo->dst;
1073 key->act_id = hdr->act_id;
1078 /* allocate a persistent dcerpc fragment key to insert in the hash */
1080 dcerpc_fragment_persistent_key(const packet_info *pinfo, const guint32 id,
1083 dcerpc_fragment_key *key = g_slice_new(dcerpc_fragment_key);
1084 e_dce_dg_common_hdr_t *hdr = (e_dce_dg_common_hdr_t *)data;
1086 COPY_ADDRESS(&key->src, &pinfo->src);
1087 COPY_ADDRESS(&key->dst, &pinfo->dst);
1089 key->act_id = hdr->act_id;
1095 dcerpc_fragment_free_temporary_key(gpointer ptr)
1097 dcerpc_fragment_key *key = (dcerpc_fragment_key *)ptr;
1100 g_slice_free(dcerpc_fragment_key, key);
1104 dcerpc_fragment_free_persistent_key(gpointer ptr)
1106 dcerpc_fragment_key *key = (dcerpc_fragment_key *)ptr;
1110 * Free up the copies of the addresses from the old key.
1112 g_free((gpointer)key->src.data);
1113 g_free((gpointer)key->dst.data);
1115 g_slice_free(dcerpc_fragment_key, key);
1119 static const reassembly_table_functions dcerpc_cl_reassembly_table_functions = {
1120 dcerpc_fragment_hash,
1121 dcerpc_fragment_equal,
1122 dcerpc_fragment_temporary_key,
1123 dcerpc_fragment_persistent_key,
1124 dcerpc_fragment_free_temporary_key,
1125 dcerpc_fragment_free_persistent_key
1129 dcerpc_reassemble_init(void)
1132 * XXX - addresses_ports_reassembly_table_functions?
1133 * Or can a single connection-oriented DCE RPC session persist
1134 * over multiple transport layer connections?
1136 reassembly_table_init(&dcerpc_co_reassembly_table,
1137 &addresses_reassembly_table_functions);
1138 reassembly_table_init(&dcerpc_cl_reassembly_table,
1139 &dcerpc_cl_reassembly_table_functions);
1143 * Authentication subdissectors. Used to dissect authentication blobs in
1144 * DCERPC binds, requests and responses.
1147 typedef struct _dcerpc_auth_subdissector {
1150 dcerpc_auth_subdissector_fns auth_fns;
1151 } dcerpc_auth_subdissector;
1153 static GSList *dcerpc_auth_subdissector_list;
1155 static dcerpc_auth_subdissector_fns *get_auth_subdissector_fns(
1156 guint8 auth_level, guint8 auth_type)
1161 for (i = 0; (data = g_slist_nth_data(dcerpc_auth_subdissector_list, i)); i++) {
1162 dcerpc_auth_subdissector *asd = (dcerpc_auth_subdissector *)data;
1164 if ((asd->auth_level == auth_level) &&
1165 (asd->auth_type == auth_type))
1166 return &asd->auth_fns;
1172 void register_dcerpc_auth_subdissector(guint8 auth_level, guint8 auth_type,
1173 dcerpc_auth_subdissector_fns *fns)
1175 dcerpc_auth_subdissector *d;
1177 if (get_auth_subdissector_fns(auth_level, auth_type))
1180 d = (dcerpc_auth_subdissector *)g_malloc(sizeof(dcerpc_auth_subdissector));
1182 d->auth_level = auth_level;
1183 d->auth_type = auth_type;
1184 memcpy(&d->auth_fns, fns, sizeof(dcerpc_auth_subdissector_fns));
1186 dcerpc_auth_subdissector_list = g_slist_append(dcerpc_auth_subdissector_list, d);
1189 /* Hand off verifier data to a registered dissector */
1191 static void dissect_auth_verf(tvbuff_t *auth_tvb, packet_info *pinfo,
1193 dcerpc_auth_subdissector_fns *auth_fns,
1194 e_dce_cn_common_hdr_t *hdr,
1195 dcerpc_auth_info *auth_info)
1197 dcerpc_dissect_fnct_t *volatile fn = NULL;
1198 /* XXX - "stub" a fake DCERPC INFO STRUCTURE
1199 If a dcerpc_info is really needed, update
1200 the call stacks to include it
1202 FAKE_DCERPC_INFO_STRUCTURE
1204 switch (hdr->ptype) {
1207 fn = auth_fns->bind_fn;
1211 fn = auth_fns->bind_ack_fn;
1214 fn = auth_fns->auth3_fn;
1217 fn = auth_fns->req_verf_fn;
1220 fn = auth_fns->resp_verf_fn;
1223 /* Don't know how to handle authentication data in this
1227 g_warning("attempt to dissect %s pdu authentication data",
1228 val_to_str(hdr->ptype, pckt_vals, "Unknown (%u)"));
1233 fn(auth_tvb, 0, pinfo, tree, &di, hdr->drep);
1235 tvb_ensure_bytes_exist(auth_tvb, 0, hdr->auth_len);
1236 proto_tree_add_text(tree, auth_tvb, 0, hdr->auth_len,
1238 val_to_str(auth_info->auth_type,
1239 authn_protocol_vals,
1245 proto_tree_add_dcerpc_drep(proto_tree *tree, tvbuff_t *tvb, int offset, guint8 drep[], int drep_len)
1247 const guint8 byteorder = drep[0] >> 4;
1248 const guint8 character = drep[0] & 0x0f;
1249 const guint8 fp = drep[1];
1250 proto_item *ti = proto_tree_add_bytes(tree, hf_dcerpc_drep, tvb, offset, drep_len, drep);
1251 proto_tree *tr = proto_item_add_subtree(ti, ett_dcerpc_drep);
1253 proto_tree_add_uint(tr, hf_dcerpc_drep_byteorder, tvb, offset, 1, byteorder);
1254 proto_tree_add_uint(tr, hf_dcerpc_drep_character, tvb, offset, 1, character);
1255 proto_tree_add_uint(tr, hf_dcerpc_drep_fp, tvb, offset+1, 1, fp);
1257 proto_item_append_text(ti, " (Order: %s, Char: %s, Float: %s)",
1258 val_to_str(byteorder, drep_byteorder_vals, "Unknown (%u)"),
1259 val_to_str(character, drep_character_vals, "Unknown (%u)"),
1260 val_to_str(fp, drep_fp_vals, "Unknown (%u)"));
1264 /* Hand off payload data to a registered dissector */
1266 static tvbuff_t *decode_encrypted_data(tvbuff_t *data_tvb,
1269 dcerpc_auth_subdissector_fns *auth_fns,
1270 gboolean is_request,
1271 dcerpc_auth_info *auth_info)
1273 dcerpc_decode_data_fnct_t *fn;
1276 fn = auth_fns->req_data_fn;
1278 fn = auth_fns->resp_data_fn;
1281 return fn(data_tvb, auth_tvb, 0, pinfo, auth_info);
1290 /* the registered subdissectors */
1291 GHashTable *dcerpc_uuids = NULL;
1294 dcerpc_uuid_equal(gconstpointer k1, gconstpointer k2)
1296 const dcerpc_uuid_key *key1 = (const dcerpc_uuid_key *)k1;
1297 const dcerpc_uuid_key *key2 = (const dcerpc_uuid_key *)k2;
1298 return ((memcmp(&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
1299 && (key1->ver == key2->ver));
1303 dcerpc_uuid_hash(gconstpointer k)
1305 const dcerpc_uuid_key *key = (const dcerpc_uuid_key *)k;
1306 /* This isn't perfect, but the Data1 part of these is almost always
1308 return key->uuid.Data1;
1312 dcerpc_init_uuid(int proto, int ett, e_uuid_t *uuid, guint16 ver,
1313 dcerpc_sub_dissector *procs, int opnum_hf)
1315 dcerpc_uuid_key *key = (dcerpc_uuid_key *)g_malloc(sizeof (*key));
1316 dcerpc_uuid_value *value = (dcerpc_uuid_value *)g_malloc(sizeof (*value));
1317 header_field_info *hf_info;
1318 module_t *samr_module;
1319 const char *filter_name = proto_get_protocol_filter_name(proto);
1324 value->proto = find_protocol_by_id(proto);
1325 value->proto_id = proto;
1327 value->name = proto_get_protocol_short_name(value->proto);
1328 value->procs = procs;
1329 value->opnum_hf = opnum_hf;
1331 g_hash_table_insert(dcerpc_uuids, key, value);
1333 hf_info = proto_registrar_get_nth(opnum_hf);
1334 hf_info->strings = value_string_from_subdissectors(procs);
1336 /* add this GUID to the global name resolving */
1337 guids_add_uuid(uuid, proto_get_protocol_short_name(value->proto));
1339 /* Register the samr.nt_password preference as obsolete */
1340 /* This should be in packet-dcerpc-samr.c */
1341 if (strcmp(filter_name, "samr") == 0) {
1342 samr_module = prefs_register_protocol(proto, NULL);
1343 prefs_register_obsolete_preference(samr_module, "nt_password");
1347 /* Function to find the name of a registered protocol
1348 * or NULL if the protocol/version is not known to wireshark.
1351 dcerpc_get_proto_name(e_uuid_t *uuid, guint16 ver)
1353 dcerpc_uuid_key key;
1354 dcerpc_uuid_value *sub_proto;
1358 if (!(sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key))) {
1361 return sub_proto->name;
1364 /* Function to find the opnum hf-field of a registered protocol
1365 * or -1 if the protocol/version is not known to wireshark.
1368 dcerpc_get_proto_hf_opnum(e_uuid_t *uuid, guint16 ver)
1370 dcerpc_uuid_key key;
1371 dcerpc_uuid_value *sub_proto;
1375 if (!(sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key))) {
1378 return sub_proto->opnum_hf;
1381 /* Create a value_string consisting of DCERPC opnum and name from a
1382 subdissector array. */
1384 value_string *value_string_from_subdissectors(dcerpc_sub_dissector *sd)
1386 value_string *vs = NULL;
1391 for (i = 0; sd[i].name; i++) {
1393 vs[i].value = sd[i].num;
1394 vs[i].strptr = sd[i].name;
1400 vs = (value_string *)wmem_alloc(wmem_epan_scope(), (num_sd + 1) * sizeof(value_string));
1404 vs[num_sd].value = 0;
1405 vs[num_sd].strptr = NULL;
1410 /* Function to find the subdissector table of a registered protocol
1411 * or NULL if the protocol/version is not known to wireshark.
1413 dcerpc_sub_dissector *
1414 dcerpc_get_proto_sub_dissector(e_uuid_t *uuid, guint16 ver)
1416 dcerpc_uuid_key key;
1417 dcerpc_uuid_value *sub_proto;
1421 if (!(sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key))) {
1424 return sub_proto->procs;
1430 dcerpc_bind_equal(gconstpointer k1, gconstpointer k2)
1432 const dcerpc_bind_key *key1 = (const dcerpc_bind_key *)k1;
1433 const dcerpc_bind_key *key2 = (const dcerpc_bind_key *)k2;
1434 return ((key1->conv == key2->conv)
1435 && (key1->ctx_id == key2->ctx_id)
1436 && (key1->smb_fid == key2->smb_fid));
1440 dcerpc_bind_hash(gconstpointer k)
1442 const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
1445 hash = GPOINTER_TO_UINT(key->conv) + key->ctx_id + key->smb_fid;
1451 * To keep track of callid mappings. Should really use some generic
1452 * conversation support instead.
1454 static GHashTable *dcerpc_cn_calls = NULL;
1455 static GHashTable *dcerpc_dg_calls = NULL;
1457 typedef struct _dcerpc_cn_call_key {
1458 conversation_t *conv;
1461 } dcerpc_cn_call_key;
1463 typedef struct _dcerpc_dg_call_key {
1464 conversation_t *conv;
1467 } dcerpc_dg_call_key;
1471 dcerpc_cn_call_equal(gconstpointer k1, gconstpointer k2)
1473 const dcerpc_cn_call_key *key1 = (const dcerpc_cn_call_key *)k1;
1474 const dcerpc_cn_call_key *key2 = (const dcerpc_cn_call_key *)k2;
1475 return ((key1->conv == key2->conv)
1476 && (key1->call_id == key2->call_id)
1477 && (key1->smb_fid == key2->smb_fid));
1481 dcerpc_dg_call_equal(gconstpointer k1, gconstpointer k2)
1483 const dcerpc_dg_call_key *key1 = (const dcerpc_dg_call_key *)k1;
1484 const dcerpc_dg_call_key *key2 = (const dcerpc_dg_call_key *)k2;
1485 return ((key1->conv == key2->conv)
1486 && (key1->seqnum == key2->seqnum)
1487 && ((memcmp(&key1->act_id, &key2->act_id, sizeof (e_uuid_t)) == 0)));
1491 dcerpc_cn_call_hash(gconstpointer k)
1493 const dcerpc_cn_call_key *key = (const dcerpc_cn_call_key *)k;
1494 return GPOINTER_TO_UINT(key->conv) + key->call_id + key->smb_fid;
1498 dcerpc_dg_call_hash(gconstpointer k)
1500 const dcerpc_dg_call_key *key = (const dcerpc_dg_call_key *)k;
1501 return (GPOINTER_TO_UINT(key->conv) + key->seqnum + key->act_id.Data1
1502 + (key->act_id.Data2 << 16) + key->act_id.Data3
1503 + (key->act_id.Data4[0] << 24) + (key->act_id.Data4[1] << 16)
1504 + (key->act_id.Data4[2] << 8) + (key->act_id.Data4[3] << 0)
1505 + (key->act_id.Data4[4] << 24) + (key->act_id.Data4[5] << 16)
1506 + (key->act_id.Data4[6] << 8) + (key->act_id.Data4[7] << 0));
1509 /* to keep track of matched calls/responses
1510 this one uses the same value struct as calls, but the key is the frame id
1511 and call id; there can be more than one call in a frame.
1513 XXX - why not just use the same keys as are used for calls?
1516 static GHashTable *dcerpc_matched = NULL;
1518 typedef struct _dcerpc_matched_key {
1521 } dcerpc_matched_key;
1524 dcerpc_matched_equal(gconstpointer k1, gconstpointer k2)
1526 const dcerpc_matched_key *key1 = (const dcerpc_matched_key *)k1;
1527 const dcerpc_matched_key *key2 = (const dcerpc_matched_key *)k2;
1528 return ((key1->frame == key2->frame)
1529 && (key1->call_id == key2->call_id));
1533 dcerpc_matched_hash(gconstpointer k)
1535 const dcerpc_matched_key *key = (const dcerpc_matched_key *)k;
1542 * Utility functions. Modeled after packet-rpc.c
1546 dissect_dcerpc_uint8(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1547 proto_tree *tree, guint8 *drep,
1548 int hfindex, guint8 *pdata)
1552 data = tvb_get_guint8(tvb, offset);
1554 proto_tree_add_item(tree, hfindex, tvb, offset, 1, DREP_ENC_INTEGER(drep));
1562 dissect_dcerpc_uint16(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1563 proto_tree *tree, guint8 *drep,
1564 int hfindex, guint16 *pdata)
1568 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1569 ? tvb_get_letohs(tvb, offset)
1570 : tvb_get_ntohs(tvb, offset));
1573 proto_tree_add_item(tree, hfindex, tvb, offset, 2, DREP_ENC_INTEGER(drep));
1581 dissect_dcerpc_uint32(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1582 proto_tree *tree, guint8 *drep,
1583 int hfindex, guint32 *pdata)
1587 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1588 ? tvb_get_letohl(tvb, offset)
1589 : tvb_get_ntohl(tvb, offset));
1592 proto_tree_add_item(tree, hfindex, tvb, offset, 4, DREP_ENC_INTEGER(drep));
1599 /* handles 32 bit unix time_t */
1601 dissect_dcerpc_time_t(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1602 proto_tree *tree, guint8 *drep,
1603 int hfindex, guint32 *pdata)
1608 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1609 ? tvb_get_letohl(tvb, offset)
1610 : tvb_get_ntohl(tvb, offset));
1615 if (data == 0xffffffff) {
1616 /* special case, no time specified */
1617 proto_tree_add_time_format_value(tree, hfindex, tvb, offset, 4, &tv, "No time specified");
1619 proto_tree_add_time(tree, hfindex, tvb, offset, 4, &tv);
1629 dissect_dcerpc_uint64(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1630 proto_tree *tree, guint8 *drep,
1631 int hfindex, guint64 *pdata)
1635 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1636 ? tvb_get_letoh64(tvb, offset)
1637 : tvb_get_ntoh64(tvb, offset));
1640 header_field_info *hfinfo;
1642 /* This might be a field that is either 32bit, in NDR or
1643 64 bits in NDR64. So we must be careful and call the right
1646 hfinfo = proto_registrar_get_nth(hfindex);
1648 switch (hfinfo->type) {
1650 proto_tree_add_uint64(tree, hfindex, tvb, offset, 8, data);
1653 proto_tree_add_int64(tree, hfindex, tvb, offset, 8, data);
1656 DISSECTOR_ASSERT(data <= G_MAXUINT32);
1657 proto_tree_add_uint(tree, hfindex, tvb, offset, 8, (guint32)data);
1667 dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1668 proto_tree *tree, guint8 *drep,
1669 int hfindex, gfloat *pdata)
1675 case(DCE_RPC_DREP_FP_IEEE):
1676 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1677 ? tvb_get_letohieee_float(tvb, offset)
1678 : tvb_get_ntohieee_float(tvb, offset));
1680 proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
1683 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
1684 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1685 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
1687 /* ToBeDone: non IEEE floating formats */
1688 /* Set data to a negative infinity value */
1691 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep[1]);
1701 dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1702 proto_tree *tree, guint8 *drep,
1703 int hfindex, gdouble *pdata)
1709 case(DCE_RPC_DREP_FP_IEEE):
1710 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1711 ? tvb_get_letohieee_double(tvb, offset)
1712 : tvb_get_ntohieee_double(tvb, offset));
1714 proto_tree_add_double(tree, hfindex, tvb, offset, 8, data);
1717 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
1718 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1719 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
1721 /* ToBeDone: non IEEE double formats */
1722 /* Set data to a negative infinity value */
1723 data = -G_MAXDOUBLE;
1725 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep[1]);
1735 dissect_dcerpc_uuid_t(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1736 proto_tree *tree, guint8 *drep,
1737 int hfindex, e_uuid_t *pdata)
1742 if (drep[0] & DREP_LITTLE_ENDIAN) {
1743 tvb_get_letohguid(tvb, offset, (e_guid_t *) &uuid);
1745 tvb_get_ntohguid(tvb, offset, (e_guid_t *) &uuid);
1748 proto_tree_add_guid(tree, hfindex, tvb, offset, 16, (e_guid_t *) &uuid);
1758 * a couple simpler things
1761 dcerpc_tvb_get_ntohs(tvbuff_t *tvb, gint offset, guint8 *drep)
1763 if (drep[0] & DREP_LITTLE_ENDIAN) {
1764 return tvb_get_letohs(tvb, offset);
1766 return tvb_get_ntohs(tvb, offset);
1771 dcerpc_tvb_get_ntohl(tvbuff_t *tvb, gint offset, guint8 *drep)
1773 if (drep[0] & DREP_LITTLE_ENDIAN) {
1774 return tvb_get_letohl(tvb, offset);
1776 return tvb_get_ntohl(tvb, offset);
1781 dcerpc_tvb_get_uuid(tvbuff_t *tvb, gint offset, guint8 *drep, e_uuid_t *uuid)
1783 if (drep[0] & DREP_LITTLE_ENDIAN) {
1784 tvb_get_letohguid(tvb, offset, (e_guid_t *) uuid);
1786 tvb_get_ntohguid(tvb, offset, (e_guid_t *) uuid);
1792 /* function to dissect a unidimensional conformant array */
1794 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1795 proto_tree *tree, dcerpc_info *di, guint8 *drep,
1796 dcerpc_dissect_fnct_t *fnct)
1800 int conformance_size = 4;
1802 if (di->call_data->flags & DCERPC_IS_NDR64) {
1803 conformance_size = 8;
1806 if (di->conformant_run) {
1809 /* conformant run, just dissect the max_count header */
1810 old_offset = offset;
1811 di->conformant_run = 0;
1812 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1813 hf_dcerpc_array_max_count, &val);
1814 di->array_max_count = (gint32)val;
1815 di->array_max_count_offset = offset-conformance_size;
1816 di->conformant_run = 1;
1817 di->conformant_eaten = offset-old_offset;
1819 /* we don't remember where in the bytestream this field was */
1820 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, conformance_size, di->array_max_count);
1822 /* real run, dissect the elements */
1823 for (i=0; i<di->array_max_count; i++) {
1824 offset = (*fnct)(tvb, offset, pinfo, tree, di, drep);
1831 /* function to dissect a unidimensional conformant and varying array
1832 * depending on the dissection function passed as a parameter,
1833 * content of the array will be dissected as a block or byte by byte
1836 dissect_ndr_ucvarray_core(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1837 proto_tree *tree, dcerpc_info *di, guint8 *drep,
1838 dcerpc_dissect_fnct_t *fnct_bytes,
1839 dcerpc_dissect_fnct_blk_t *fnct_block)
1843 int conformance_size = 4;
1845 if (di->call_data->flags & DCERPC_IS_NDR64) {
1846 conformance_size = 8;
1849 if (di->conformant_run) {
1852 /* conformant run, just dissect the max_count header */
1853 old_offset = offset;
1854 di->conformant_run = 0;
1855 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1856 hf_dcerpc_array_max_count, &val);
1857 DISSECTOR_ASSERT(val <= G_MAXUINT32);
1858 di->array_max_count = (guint32)val;
1859 di->array_max_count_offset = offset-conformance_size;
1860 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1861 hf_dcerpc_array_offset, &val);
1862 DISSECTOR_ASSERT(val <= G_MAXUINT32);
1863 di->array_offset = (guint32)val;
1864 di->array_offset_offset = offset-conformance_size;
1865 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1866 hf_dcerpc_array_actual_count, &val);
1867 DISSECTOR_ASSERT(val <= G_MAXUINT32);
1868 di->array_actual_count = (guint32)val;
1869 di->array_actual_count_offset = offset-conformance_size;
1870 di->conformant_run = 1;
1871 di->conformant_eaten = offset-old_offset;
1873 /* we don't remember where in the bytestream these fields were */
1874 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, conformance_size, di->array_max_count);
1875 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, conformance_size, di->array_offset);
1876 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, conformance_size, di->array_actual_count);
1878 /* real run, dissect the elements */
1880 offset = (*fnct_block)(tvb, offset, di->array_actual_count, pinfo, tree, drep);
1882 for (i=0 ;i<di->array_actual_count; i++) {
1883 old_offset = offset;
1884 offset = (*fnct_bytes)(tvb, offset, pinfo, tree, di, drep);
1885 if (offset <= old_offset)
1886 THROW(ReportedBoundsError);
1895 dissect_ndr_ucvarray_block(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1896 proto_tree *tree, dcerpc_info *di, guint8 *drep,
1897 dcerpc_dissect_fnct_blk_t *fnct)
1899 return dissect_ndr_ucvarray_core(tvb, offset, pinfo, tree, di, drep, NULL, fnct);
1903 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1904 proto_tree *tree, dcerpc_info *di, guint8 *drep,
1905 dcerpc_dissect_fnct_t *fnct)
1907 return dissect_ndr_ucvarray_core(tvb, offset, pinfo, tree, di, drep, fnct, NULL);
1909 /* function to dissect a unidimensional varying array */
1911 dissect_ndr_uvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1912 proto_tree *tree, dcerpc_info *di, guint8 *drep,
1913 dcerpc_dissect_fnct_t *fnct)
1917 int conformance_size = 4;
1919 if (di->call_data->flags & DCERPC_IS_NDR64) {
1920 conformance_size = 8;
1923 if (di->conformant_run) {
1926 /* conformant run, just dissect the max_count header */
1927 old_offset = offset;
1928 di->conformant_run = 0;
1929 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1930 hf_dcerpc_array_offset, &val);
1931 DISSECTOR_ASSERT(val <= G_MAXUINT32);
1932 di->array_offset = (guint32)val;
1933 di->array_offset_offset = offset-conformance_size;
1934 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1935 hf_dcerpc_array_actual_count, &val);
1936 DISSECTOR_ASSERT(val <= G_MAXUINT32);
1937 di->array_actual_count = (guint32)val;
1938 di->array_actual_count_offset = offset-conformance_size;
1939 di->conformant_run = 1;
1940 di->conformant_eaten = offset-old_offset;
1942 /* we don't remember where in the bytestream these fields were */
1943 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, conformance_size, di->array_offset);
1944 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, conformance_size, di->array_actual_count);
1946 /* real run, dissect the elements */
1947 for (i=0; i<di->array_actual_count; i++) {
1948 offset = (*fnct)(tvb, offset, pinfo, tree, di, drep);
1955 /* Dissect an string of bytes. This corresponds to
1956 IDL of the form '[string] byte *foo'.
1958 It can also be used for a conformant varying array of bytes if
1959 the contents of the array should be shown as a big blob, rather
1960 than showing each byte as an individual element.
1962 XXX - which of those is really the IDL type for, for example,
1963 the encrypted data in some MAPI packets? (Microsoft hasn't
1966 XXX - does this need to do all the conformant array stuff that
1967 "dissect_ndr_ucvarray()" does? These are presumably for strings
1968 that are conformant and varying - they're stored like conformant
1969 varying arrays of bytes. */
1971 dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo,
1972 proto_tree *tree, dcerpc_info *di, guint8 *drep)
1976 if (di->conformant_run) {
1977 /* just a run to handle conformant arrays, no scalars to dissect */
1981 /* NDR array header */
1983 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1984 hf_dcerpc_array_max_count, NULL);
1986 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1987 hf_dcerpc_array_offset, NULL);
1989 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1990 hf_dcerpc_array_actual_count, &len);
1992 DISSECTOR_ASSERT(len <= G_MAXUINT32);
1994 tvb_ensure_bytes_exist(tvb, offset, (guint32)len);
1995 proto_tree_add_item(tree, di->hf_index, tvb, offset, (guint32)len,
1999 offset += (guint32)len;
2004 /* For dissecting arrays that are to be interpreted as strings. */
2006 /* Dissect an NDR conformant varying string of elements.
2007 The length of each element is given by the 'size_is' parameter;
2008 the elements are assumed to be characters or wide characters.
2010 XXX - does this need to do all the conformant array stuff that
2011 "dissect_ndr_ucvarray()" does? */
2013 dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2014 proto_tree *tree, dcerpc_info *di, guint8 *drep, int size_is,
2015 int hfindex, gboolean add_subtree, char **data)
2017 header_field_info *hfinfo;
2018 proto_item *string_item;
2019 proto_tree *string_tree;
2024 /* Make sure this really is a string field. */
2025 hfinfo = proto_registrar_get_nth(hfindex);
2026 DISSECTOR_ASSERT(hfinfo->type == FT_STRING);
2028 if (di->conformant_run) {
2029 /* just a run to handle conformant arrays, no scalars to dissect */
2034 string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
2035 proto_registrar_get_name(hfindex));
2036 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
2042 /* NDR array header */
2044 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
2045 hf_dcerpc_array_max_count, NULL);
2047 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
2048 hf_dcerpc_array_offset, NULL);
2050 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
2051 hf_dcerpc_array_actual_count, &len);
2053 DISSECTOR_ASSERT(len <= G_MAXUINT32);
2054 buffer_len = size_is * (guint32)len;
2057 if (!di->no_align && (offset % size_is))
2058 offset += size_is - (offset % size_is);
2061 * "tvb_get_string_enc()" throws an exception if the entire string
2062 * isn't in the tvbuff. If the length is bogus, this should
2063 * keep us from trying to allocate an immensely large buffer.
2064 * (It won't help if the length is *valid* but immensely large,
2065 * but that's another matter; in any case, that would happen only
2066 * if we had an immensely large tvbuff....)
2068 * XXX - so why are we doing tvb_ensure_bytes_exist()?
2070 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
2071 if (size_is == sizeof(guint16)) {
2073 * Assume little-endian UTF-16.
2075 * XXX - is this always little-endian?
2077 s = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, buffer_len,
2078 ENC_UTF_16|ENC_LITTLE_ENDIAN);
2081 * XXX - what if size_is is neither 1 nor 2?
2083 s = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, buffer_len,
2084 DREP_ENC_CHAR(drep));
2086 if (tree && buffer_len)
2087 proto_tree_add_string(string_tree, hfindex, tvb, offset,
2090 if (string_item != NULL)
2091 proto_item_append_text(string_item, ": %s", s);
2096 offset += buffer_len;
2098 proto_item_set_end(string_item, tvb, offset);
2104 dissect_ndr_cstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2105 proto_tree *tree, dcerpc_info *di, guint8 *drep, int size_is,
2106 int hfindex, gboolean add_subtree, char **data)
2108 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep, size_is, hfindex, add_subtree, data);
2111 /* Dissect an conformant varying string of chars.
2112 This corresponds to IDL of the form '[string] char *foo'.
2114 XXX - at least according to the DCE RPC 1.1 spec, a string has
2115 a null terminator, which isn't necessary as a terminator for
2116 the transfer language (as there's a length), but is presumably
2117 there for the benefit of null-terminated-string languages
2118 such as C. Is this ever used for purely counted strings?
2119 (Not that it matters if it is.) */
2121 dissect_ndr_char_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2122 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2124 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep,
2125 sizeof(guint8), di->hf_index,
2129 /* Dissect a conformant varying string of wchars (wide characters).
2130 This corresponds to IDL of the form '[string] wchar *foo'
2132 XXX - at least according to the DCE RPC 1.1 spec, a string has
2133 a null terminator, which isn't necessary as a terminator for
2134 the transfer language (as there's a length), but is presumably
2135 there for the benefit of null-terminated-string languages
2136 such as C. Is this ever used for purely counted strings?
2137 (Not that it matters if it is.) */
2139 dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2140 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2142 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep,
2143 sizeof(guint16), di->hf_index,
2147 /* This function is aimed for PIDL usage and dissects a UNIQUE pointer to
2151 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)
2154 gint levels = CB_STR_ITEM_LEVELS(param);
2156 offset = dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep,
2160 if (!di->conformant_run) {
2161 /* Append string to COL_INFO */
2162 if (param & PIDL_SET_COL_INFO) {
2163 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", s);
2165 /* Save string to dcv->private_data */
2166 if ((param & PIDL_STR_SAVE)
2167 && (!pinfo->fd->flags.visited)) {
2168 dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2169 dcv->private_data = wmem_strdup(wmem_file_scope(), s);
2171 /* Append string to upper-level proto_items */
2172 if ((levels > 0) && tree && s && s[0]) {
2173 proto_item_append_text(tree, ": %s", s);
2174 tree = tree->parent;
2177 proto_item_append_text(tree, ": %s", s);
2178 tree = tree->parent;
2180 while (levels > 0) {
2181 proto_item_append_text(tree, " %s", s);
2182 tree = tree->parent;
2193 /* Dissect an NDR varying string of elements.
2194 The length of each element is given by the 'size_is' parameter;
2195 the elements are assumed to be characters or wide characters.
2198 dissect_ndr_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2199 proto_tree *tree, dcerpc_info *di, guint8 *drep, int size_is,
2200 int hfindex, gboolean add_subtree, char **data)
2202 header_field_info *hfinfo;
2203 proto_item *string_item;
2204 proto_tree *string_tree;
2209 /* Make sure this really is a string field. */
2210 hfinfo = proto_registrar_get_nth(hfindex);
2211 DISSECTOR_ASSERT(hfinfo->type == FT_STRING);
2213 if (di->conformant_run) {
2214 /* just a run to handle conformant arrays, no scalars to dissect */
2219 string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
2220 proto_registrar_get_name(hfindex));
2221 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
2227 /* NDR array header */
2228 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
2229 hf_dcerpc_array_offset, NULL);
2231 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
2232 hf_dcerpc_array_actual_count, &len);
2234 DISSECTOR_ASSERT(len <= G_MAXUINT32);
2235 buffer_len = size_is * (guint32)len;
2238 if (!di->no_align && (offset % size_is))
2239 offset += size_is - (offset % size_is);
2242 * "tvb_get_string_enc()" throws an exception if the entire string
2243 * isn't in the tvbuff. If the length is bogus, this should
2244 * keep us from trying to allocate an immensely large buffer.
2245 * (It won't help if the length is *valid* but immensely large,
2246 * but that's another matter; in any case, that would happen only
2247 * if we had an immensely large tvbuff....)
2249 * XXX - so why are we doing tvb_ensure_bytes_exist()?
2251 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
2252 if (size_is == sizeof(guint16)) {
2254 * Assume little-endian UTF-16.
2256 * XXX - is this always little-endian?
2258 s = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, buffer_len,
2259 ENC_UTF_16|ENC_LITTLE_ENDIAN);
2262 * XXX - what if size_is is neither 1 nor 2?
2264 s = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, buffer_len,
2265 DREP_ENC_CHAR(drep));
2267 if (tree && buffer_len)
2268 proto_tree_add_string(string_tree, hfindex, tvb, offset,
2271 if (string_item != NULL)
2272 proto_item_append_text(string_item, ": %s", s);
2277 offset += buffer_len;
2279 proto_item_set_end(string_item, tvb, offset);
2284 /* Dissect an varying string of chars.
2285 This corresponds to IDL of the form '[string] char *foo'.
2287 XXX - at least according to the DCE RPC 1.1 spec, a string has
2288 a null terminator, which isn't necessary as a terminator for
2289 the transfer language (as there's a length), but is presumably
2290 there for the benefit of null-terminated-string languages
2291 such as C. Is this ever used for purely counted strings?
2292 (Not that it matters if it is.) */
2294 dissect_ndr_char_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2295 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2297 return dissect_ndr_vstring(tvb, offset, pinfo, tree, di, drep,
2298 sizeof(guint8), di->hf_index,
2302 /* Dissect a varying string of wchars (wide characters).
2303 This corresponds to IDL of the form '[string] wchar *foo'
2305 XXX - at least according to the DCE RPC 1.1 spec, a string has
2306 a null terminator, which isn't necessary as a terminator for
2307 the transfer language (as there's a length), but is presumably
2308 there for the benefit of null-terminated-string languages
2309 such as C. Is this ever used for purely counted strings?
2310 (Not that it matters if it is.) */
2312 dissect_ndr_wchar_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2313 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2315 return dissect_ndr_vstring(tvb, offset, pinfo, tree, di, drep,
2316 sizeof(guint16), di->hf_index,
2321 /* ndr pointer handling */
2322 /* list of pointers encountered so far */
2323 static GSList *ndr_pointer_list = NULL;
2325 /* position where in the list to insert newly encountered pointers */
2326 static int ndr_pointer_list_pos = 0;
2328 /* Boolean controlling whether pointers are top-level or embedded */
2329 static gboolean pointers_are_top_level = TRUE;
2331 /* as a kludge, we represent all embedded reference pointers as id == -1
2332 hoping that his will not collide with any non-ref pointers */
2333 typedef struct ndr_pointer_data {
2335 proto_item *item; /* proto_item for pointer */
2336 proto_tree *tree; /* subtree of above item */
2337 dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
2339 dcerpc_callback_fnct_t *callback;
2340 void *callback_args;
2341 } ndr_pointer_data_t;
2344 init_ndr_pointer_list(dcerpc_info *di)
2346 di->conformant_run = 0;
2348 while (ndr_pointer_list) {
2349 ndr_pointer_data_t *npd = (ndr_pointer_data_t *)g_slist_nth_data(ndr_pointer_list, 0);
2350 ndr_pointer_list = g_slist_remove(ndr_pointer_list, npd);
2354 ndr_pointer_list = NULL;
2355 ndr_pointer_list_pos = 0;
2356 pointers_are_top_level = TRUE;
2360 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, dcerpc_info *di, guint8 *drep)
2362 int found_new_pointer;
2371 found_new_pointer = 0;
2372 len = g_slist_length(ndr_pointer_list);
2373 for (i=next_pointer; i<len; i++) {
2374 ndr_pointer_data_t *tnpd = (ndr_pointer_data_t *)g_slist_nth_data(ndr_pointer_list, i);
2376 dcerpc_dissect_fnct_t *fnct;
2379 found_new_pointer = 1;
2382 ndr_pointer_list_pos = i+1;
2383 di->hf_index = tnpd->hf_index;
2384 /* first a run to handle any conformant
2386 di->conformant_run = 1;
2387 di->conformant_eaten = 0;
2388 old_offset = offset;
2389 offset = (*(fnct))(tvb, offset, pinfo, NULL, di, drep);
2391 DISSECTOR_ASSERT((offset-old_offset) == di->conformant_eaten);
2392 /* This is to check for any bugs in the dissectors.
2394 * Basically, the NDR representation will store all
2395 * arrays in two blocks, one block with the dimension
2396 * description, like size, number of elements and such,
2397 * and another block that contains the actual data stored
2399 * If the array is embedded directly inside another,
2400 * encapsulating aggregate type, like a union or struct,
2401 * then these two blocks will be stored at different places
2402 * in the bytestream, with other data between the blocks.
2404 * For this reason, all pointers to types (both aggregate
2405 * and scalar, for simplicity no distinction is made)
2406 * will have its dissector called twice.
2407 * The dissector will first be called with conformant_run == 1
2408 * in which mode the dissector MUST NOT consume any data from
2409 * the tvbuff (i.e. may not dissect anything) except the
2410 * initial control block for arrays.
2411 * The second time the dissector is called, with
2412 * conformant_run == 0, all other data for the type will be
2415 * All dissect_ndr_<type> dissectors are already prepared
2416 * for this and knows when it should eat data from the tvb
2417 * and when not to, so implementors of dissectors will
2418 * normally not need to worry about this or even know about
2419 * it. However, if a dissector for an aggregate type calls
2420 * a subdissector from outside packet-dcerpc.c, such as
2421 * the dissector in packet-smb.c for NT Security Descriptors
2422 * as an example, then it is VERY important to encapsulate
2423 * this call to an external subdissector with the appropriate
2424 * test for conformant_run, i.e. it will need something like
2426 * dcerpc_info *di (received as function parameter)
2428 * if (di->conformant_run) {
2432 * to make sure it makes the right thing.
2433 * This assert will signal when someone has forgotten to
2434 * make the dissector aware of this requirement.
2437 /* now we dissect the actual pointer */
2438 di->conformant_run = 0;
2439 old_offset = offset;
2440 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, di, drep);
2442 tnpd->callback(pinfo, tnpd->tree, tnpd->item, di, tvb, old_offset, offset, tnpd->callback_args);
2443 proto_item_set_len(tnpd->item, offset - old_offset);
2447 } while (found_new_pointer);
2454 add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
2455 dcerpc_info *di, dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index,
2456 dcerpc_callback_fnct_t *callback, void *callback_args)
2458 ndr_pointer_data_t *npd;
2460 /* check if this pointer is valid */
2461 if (id != 0xffffffff) {
2462 dcerpc_call_value *value;
2464 value = di->call_data;
2466 if (di->ptype == PDU_REQ) {
2467 if (!(pinfo->fd->flags.visited)) {
2468 if (id > value->max_ptr) {
2469 value->max_ptr = id;
2473 /* if we haven't seen the request bail out since we cant
2474 know whether this is the first non-NULL instance
2476 if (value->req_frame == 0) {
2477 /* XXX THROW EXCEPTION */
2480 /* We saw this one in the request frame, nothing to
2482 if (id <= value->max_ptr) {
2488 npd = (ndr_pointer_data_t *)g_malloc(sizeof(ndr_pointer_data_t));
2493 npd->hf_index = hf_index;
2494 npd->callback = callback;
2495 npd->callback_args = callback_args;
2496 ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
2497 ndr_pointer_list_pos);
2498 ndr_pointer_list_pos++;
2503 find_pointer_index(guint32 id)
2505 ndr_pointer_data_t *npd;
2508 len = g_slist_length(ndr_pointer_list);
2509 for (i=0; i<len; i++) {
2510 npd = (ndr_pointer_data_t *)g_slist_nth_data(ndr_pointer_list, i);
2512 if (npd->id == id) {
2521 /* This function dissects an NDR pointer and stores the callback for later
2522 * deferred dissection.
2524 * fnct is the callback function for when we have reached this object in
2527 * type is what type of pointer.
2529 * this is text is what text we should put in any created tree node.
2531 * hf_index is what hf value we want to pass to the callback function when
2532 * it is called, the callback can later pick this one up from di->hf_index.
2534 * callback is executed after the pointer has been dereferenced.
2536 * callback_args is passed as an argument to the callback function
2538 * See packet-dcerpc-samr.c for examples
2541 dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2542 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2543 int type, const char *text, int hf_index,
2544 dcerpc_callback_fnct_t *callback, void *callback_args)
2546 proto_tree *tr = NULL;
2547 gint start_offset = offset;
2548 int pointer_size = 4;
2550 if (di->conformant_run) {
2551 /* this call was only for dissecting the header for any
2552 embedded conformant array. we will not parse any
2553 pointers in this mode.
2557 if (di->call_data->flags & DCERPC_IS_NDR64) {
2562 /*TOP LEVEL REFERENCE POINTER*/
2563 if ( pointers_are_top_level
2564 && (type == NDR_POINTER_REF) ) {
2567 /* we must find out a nice way to do the length here */
2568 item = proto_tree_add_text(tree, tvb, offset, 0,
2570 tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2572 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
2573 hf_index, callback, callback_args);
2577 /*TOP LEVEL FULL POINTER*/
2578 if ( pointers_are_top_level
2579 && (type == NDR_POINTER_PTR) ) {
2584 /* get the referent id */
2585 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
2587 tvb_ensure_bytes_exist(tvb, offset-pointer_size, pointer_size);
2588 /* we got a NULL pointer */
2590 proto_tree_add_text(tree, tvb, offset-pointer_size,
2592 "(NULL pointer) %s",text);
2596 /* see if we have seen this pointer before */
2597 DISSECTOR_ASSERT(id <= G_MAXUINT32);
2598 idx = find_pointer_index((guint32)id);
2600 /* we have seen this pointer before */
2602 proto_tree_add_text(tree, tvb, offset-pointer_size,
2604 "(duplicate PTR) %s",text);
2609 item = proto_tree_add_text(tree, tvb, offset-pointer_size,
2612 tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2613 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb,
2614 offset-pointer_size, pointer_size, (guint32)id);
2615 add_pointer_to_list(pinfo, tr, item, di, fnct, (guint32)id, hf_index,
2616 callback, callback_args);
2619 /*TOP LEVEL UNIQUE POINTER*/
2620 if ( pointers_are_top_level
2621 && (type == NDR_POINTER_UNIQUE) ) {
2625 /* get the referent id */
2626 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
2628 tvb_ensure_bytes_exist(tvb, offset-pointer_size, pointer_size);
2629 /* we got a NULL pointer */
2631 proto_tree_add_text(tree, tvb, offset-pointer_size,
2633 "(NULL pointer) %s",text);
2638 DISSECTOR_ASSERT(id <= G_MAXUINT32);
2639 item = proto_tree_add_text(tree, tvb, offset-pointer_size,
2642 tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2643 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb,
2644 offset-pointer_size, pointer_size, (guint32)id);
2645 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
2646 hf_index, callback, callback_args);
2650 /*EMBEDDED REFERENCE POINTER*/
2651 if ( (!pointers_are_top_level)
2652 && (type == NDR_POINTER_REF) ) {
2656 /* get the referent id */
2657 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
2659 tvb_ensure_bytes_exist(tvb, offset-pointer_size, pointer_size);
2661 item = proto_tree_add_text(tree, tvb, offset-pointer_size,
2664 tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2665 DISSECTOR_ASSERT(id <= G_MAXUINT32);
2666 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb,
2667 offset-pointer_size, pointer_size, (guint32)id);
2668 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
2669 hf_index, callback, callback_args);
2673 /*EMBEDDED UNIQUE POINTER*/
2674 if ( (!pointers_are_top_level)
2675 && (type == NDR_POINTER_UNIQUE) ) {
2679 /* get the referent id */
2680 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
2682 tvb_ensure_bytes_exist(tvb, offset-pointer_size, pointer_size);
2683 /* we got a NULL pointer */
2685 proto_tree_add_text(tree, tvb, offset-pointer_size,
2687 "(NULL pointer) %s", text);
2692 item = proto_tree_add_text(tree, tvb, offset-pointer_size,
2695 tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2696 DISSECTOR_ASSERT(id <= G_MAXUINT32);
2697 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb,
2698 offset-pointer_size, pointer_size, (guint32)id);
2699 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
2700 hf_index, callback, callback_args);
2704 /*EMBEDDED FULL POINTER*/
2705 if ( (!pointers_are_top_level)
2706 && (type == NDR_POINTER_PTR) ) {
2711 /* get the referent id */
2712 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
2714 tvb_ensure_bytes_exist(tvb, offset-pointer_size, pointer_size);
2715 /* we got a NULL pointer */
2717 proto_tree_add_text(tree, tvb, offset-pointer_size,
2719 "(NULL pointer) %s",text);
2723 /* see if we have seen this pointer before */
2724 DISSECTOR_ASSERT(id <= G_MAXUINT32);
2725 idx = find_pointer_index((guint32)id);
2727 /* we have seen this pointer before */
2729 proto_tree_add_text(tree, tvb, offset-pointer_size,
2731 "(duplicate PTR) %s",text);
2736 item = proto_tree_add_text(tree, tvb, offset-pointer_size,
2739 tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2740 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb,
2741 offset-pointer_size, pointer_size, (guint32)id);
2742 add_pointer_to_list(pinfo, tr, item, di, fnct, (guint32)id, hf_index,
2743 callback, callback_args);
2749 /* After each top level pointer we have dissected we have to
2750 dissect all deferrals before we move on to the next top level
2752 if (pointers_are_top_level == TRUE) {
2753 pointers_are_top_level = FALSE;
2754 offset = dissect_deferred_pointers(pinfo, tvb, offset, di, drep);
2755 pointers_are_top_level = TRUE;
2758 /* Set the length for the new subtree */
2760 proto_item_set_len(tr, offset-start_offset);
2766 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2767 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2768 int type, const char *text, int hf_index)
2770 return dissect_ndr_pointer_cb(
2771 tvb, offset, pinfo, tree, di, drep, fnct, type, text, hf_index,
2775 dissect_ndr_toplevel_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2776 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2777 int type, const char *text, int hf_index)
2781 pointers_are_top_level = TRUE;
2782 ret = dissect_ndr_pointer_cb(
2783 tvb, offset, pinfo, tree, di, drep, fnct, type, text, hf_index,
2788 dissect_ndr_embedded_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2789 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2790 int type, const char *text, int hf_index)
2794 pointers_are_top_level = FALSE;
2795 ret = dissect_ndr_pointer_cb(
2796 tvb, offset, pinfo, tree, di, drep, fnct, type, text, hf_index,
2802 show_stub_data(tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
2803 dcerpc_auth_info *auth_info, gboolean is_encrypted)
2805 int length, plain_length, auth_pad_len;
2806 guint auth_pad_offset;
2809 * We don't show stub data unless we have some in the tvbuff;
2810 * however, in the protocol tree, we show, as the number of
2811 * bytes, the reported number of bytes, not the number of bytes
2812 * that happen to be in the tvbuff.
2814 if (tvb_length_remaining(tvb, offset) > 0) {
2815 auth_pad_len = auth_info?auth_info->auth_pad_len:0;
2816 length = tvb_reported_length_remaining(tvb, offset);
2818 /* if auth_pad_len is larger than length then we ignore auth_pad_len totally */
2819 plain_length = length - auth_pad_len;
2820 if (plain_length < 1) {
2821 plain_length = length;
2824 auth_pad_offset = offset + plain_length;
2826 if ((auth_info != NULL) &&
2827 (auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)) {
2829 tvb_ensure_bytes_exist(tvb, offset, length);
2830 proto_tree_add_text(dcerpc_tree, tvb, offset, length,
2831 "Encrypted stub data (%d byte%s)",
2832 length, plurality(length, "", "s"));
2833 /* is the padding is still inside the encrypted blob, don't display it explicit */
2836 tvb_ensure_bytes_exist(tvb, offset, plain_length);
2837 proto_tree_add_text(dcerpc_tree, tvb, offset, plain_length,
2838 "Decrypted stub data (%d byte%s)",
2839 plain_length, plurality(plain_length, "", "s"));
2842 tvb_ensure_bytes_exist(tvb, offset, plain_length);
2843 proto_tree_add_text(dcerpc_tree, tvb, offset, plain_length,
2844 "Stub data (%d byte%s)", plain_length,
2845 plurality(plain_length, "", "s"));
2847 /* If there is auth padding at the end of the stub, display it */
2848 if (auth_pad_len != 0) {
2849 tvb_ensure_bytes_exist(tvb, auth_pad_offset, auth_pad_len);
2850 proto_tree_add_text(dcerpc_tree, tvb, auth_pad_offset,
2852 "Auth Padding (%u byte%s)",
2854 plurality(auth_pad_len, "", "s"));
2860 dissect_sec_vt_bitmask(proto_tree *tree, tvbuff_t *tvb, int offset)
2862 proto_tree_add_bitmask(tree, tvb, offset,
2863 hf_dcerpc_sec_vt_bitmask,
2864 ett_dcerpc_sec_vt_bitmask,
2865 sec_vt_bitmask_fields,
2870 dissect_sec_vt_pcontext(proto_tree *tree, tvbuff_t *tvb, int offset)
2872 proto_item *ti = proto_tree_add_text(tree, tvb, offset, -1, "pcontext");
2873 proto_tree *tr = proto_item_add_subtree(ti, ett_dcerpc_sec_vt_pcontext);
2875 const char *uuid_name;
2877 tvb_get_letohguid(tvb, offset, &uuid);
2878 uuid_name = guids_get_uuid_name(&uuid);
2880 uuid_name = guid_to_ep_str(&uuid);
2883 proto_tree_add_guid_format(tr, hf_dcerpc_sec_vt_pcontext_uuid, tvb,
2884 offset, 16, &uuid, "Abstract Syntax: %s", uuid_name);
2887 proto_tree_add_item(tr, hf_dcerpc_sec_vt_pcontext_ver,
2888 tvb, offset, 4, ENC_LITTLE_ENDIAN);
2891 tvb_get_letohguid(tvb, offset, &uuid);
2892 uuid_name = guids_get_uuid_name(&uuid);
2894 uuid_name = guid_to_ep_str(&uuid);
2897 proto_tree_add_guid_format(tr, hf_dcerpc_sec_vt_pcontext_uuid, tvb,
2898 offset, 16, &uuid, "Transfer Syntax: %s", uuid_name);
2901 proto_tree_add_item(tr, hf_dcerpc_sec_vt_pcontext_ver,
2902 tvb, offset, 4, ENC_LITTLE_ENDIAN);
2904 proto_item_set_end(ti, tvb, offset);
2908 dissect_sec_vt_header(proto_tree *tree, tvbuff_t *tvb, int offset)
2910 proto_item *ti = proto_tree_add_text(tree, tvb, offset, -1, "header2");
2911 proto_tree *tr = proto_item_add_subtree(ti, ett_dcerpc_sec_vt_header);
2912 guint32 drep, call_id;
2913 guint16 cont_id, opnum;
2914 guint8 ptype = tvb_get_guint8(tvb, offset);
2916 proto_tree_add_uint(tr, hf_dcerpc_packet_type, tvb, offset, 1, ptype);
2919 proto_tree_add_text(tr, tvb, offset, 1, "Reserved1");
2922 proto_tree_add_text(tr, tvb, offset, 2, "Reserved2");
2925 drep = tvb_get_letohl(tvb, offset); //??? dcerpc_tvb_get_ntohl
2926 proto_tree_add_dcerpc_drep(tr, tvb, offset, (guint8*)&drep, 4);
2930 call_id = tvb_get_letohl(tvb, offset); //??? dcerpc_tvb_get_ntohl
2931 proto_tree_add_uint(tr, hf_dcerpc_cn_call_id, tvb, offset, 4, call_id);
2934 //??? dissect_dcerpc_uint16
2935 cont_id = tvb_get_letohs(tvb, offset); //??? dcerpc_tvb_get_ntohs
2936 proto_tree_add_uint(tr, hf_dcerpc_cn_ctx_id, tvb, offset, 2, cont_id);
2939 //??? dissect_dcerpc_uint16
2940 opnum = tvb_get_letohs(tvb, offset); //??? dcerpc_tvb_get_ntohs
2941 proto_tree_add_uint(tr, hf_dcerpc_opnum, tvb, offset, 2, opnum);
2944 proto_item_set_end(ti, tvb, offset);
2948 dissect_verification_trailer(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *parent_tree)
2950 static const guint8 TRAILER_SIGNATUR[] = {0x8a, 0xe3, 0x13, 0x71, 0x02, 0xf4, 0x36, 0x71};
2952 SEC_VT_COMMAND_BITMASK_1 = 0x0001,
2953 SEC_VT_COMMAND_PCONTEXT = 0x0002,
2954 SEC_VT_COMMAND_HEADER2 = 0x0003,
2955 SEC_VT_COMMAND_END = 0x4000,
2956 SEC_VT_MUST_PROCESS_COMMAND = 0x8000,
2957 SEC_VT_COMMAND_MASK = 0x3fff,
2963 const guint8 *start, *pos;
2964 int remaining = tvb_length_remaining(tvb, offset);
2965 if (remaining < (int)sizeof(TRAILER_SIGNATUR)) {
2968 start = tvb_get_ptr(tvb, offset, remaining);
2969 pos = epan_memmem(start, remaining, TRAILER_SIGNATUR, sizeof(TRAILER_SIGNATUR));
2974 item = proto_tree_add_text(parent_tree, tvb, offset, -1, "Verification Trailer");
2975 tree = proto_item_add_subtree(item, ett_dcerpc_verification_trailer);
2978 int len = pos - start;
2979 proto_tree_add_text(tree, tvb, offset, len,
2980 "Padding (%d byte%s)", len, plurality(len, "", "s"));
2985 proto_tree_add_text(tree, tvb, offset, sizeof(TRAILER_SIGNATUR),
2986 "rpc_sec_verification_trailer");
2987 offset += sizeof(TRAILER_SIGNATUR);
2988 remaining -= sizeof(TRAILER_SIGNATUR);
2990 while (remaining >= 4) {
2993 gboolean cmd_end, cmd_must;
2997 cmd = (sec_vt_command)tvb_get_letohs(tvb, offset);
2998 len = tvb_get_letohs(tvb, offset + 2);
2999 cmd_end = cmd & SEC_VT_COMMAND_END;
3000 cmd_must = cmd & SEC_VT_MUST_PROCESS_COMMAND;
3001 cmd = (sec_vt_command)(cmd & SEC_VT_COMMAND_MASK);
3003 ti = proto_tree_add_text(tree, tvb, offset, -1, "Command: %s",
3004 val_to_str(cmd, sec_vt_command_cmd_vals,
3005 "Unknown (0x%04x)"));
3006 tr = proto_item_add_subtree(ti, ett_dcerpc_sec_vt_pcontext);
3009 proto_item_append_text(ti, "!!!");
3012 proto_item_append_text(ti, ", END");
3015 proto_tree_add_bitmask(tr, tvb, offset,
3016 hf_dcerpc_sec_vt_command,
3017 ett_dcerpc_sec_vt_command,
3018 sec_vt_command_fields,
3022 proto_tree_add_item(tr, hf_dcerpc_sec_vt_command_length, tvb,
3023 offset, 2, ENC_LITTLE_ENDIAN);
3027 case SEC_VT_COMMAND_BITMASK_1:
3028 dissect_sec_vt_bitmask(tr, tvb, offset);
3030 case SEC_VT_COMMAND_PCONTEXT:
3031 dissect_sec_vt_pcontext(tr, tvb, offset);
3033 case SEC_VT_COMMAND_HEADER2:
3034 dissect_sec_vt_header(tr, tvb, offset);
3037 proto_tree_add_text(tr, tvb, offset, len, "blob");
3041 remaining -= (4 + len);
3042 proto_item_set_end(ti, tvb, offset);
3044 if (cmd & SEC_VT_COMMAND_END) {
3049 proto_item_set_end(item, tvb, offset);
3054 dcerpc_try_handoff(packet_info *pinfo, proto_tree *tree,
3055 proto_tree *dcerpc_tree,
3056 tvbuff_t *volatile tvb, tvbuff_t *decrypted_tvb,
3057 guint8 *drep, dcerpc_info *info,
3058 dcerpc_auth_info *auth_info)
3060 volatile gint offset = 0;
3061 dcerpc_uuid_key key;
3062 dcerpc_uuid_value *sub_proto;
3063 proto_tree *volatile sub_tree = NULL;
3064 dcerpc_sub_dissector *proc;
3065 const gchar *name = NULL;
3066 const char *volatile saved_proto;
3067 guint length = 0, reported_length = 0;
3068 tvbuff_t *volatile stub_tvb;
3069 volatile guint auth_pad_len;
3070 volatile int auth_pad_offset;
3071 proto_item *sub_item = NULL;
3072 proto_item *pi, *hidden_item;
3074 dcerpc_dissect_fnct_t *volatile sub_dissect;
3076 key.uuid = info->call_data->uuid;
3077 key.ver = info->call_data->ver;
3079 if ((sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key)) == NULL
3080 || !proto_is_protocol_enabled(sub_proto->proto)) {
3082 * We don't have a dissector for this UUID, or the protocol
3083 * for that UUID is disabled.
3086 hidden_item = proto_tree_add_boolean(dcerpc_tree, hf_dcerpc_unknown_if_id,
3087 tvb, offset, 0, TRUE);
3088 PROTO_ITEM_SET_HIDDEN(hidden_item);
3089 col_append_fstr(pinfo->cinfo, COL_INFO, " %s V%u",
3090 guids_resolve_uuid_to_str(&info->call_data->uuid), info->call_data->ver);
3092 if (decrypted_tvb != NULL) {
3093 show_stub_data(decrypted_tvb, 0, dcerpc_tree, auth_info,
3096 show_stub_data(tvb, 0, dcerpc_tree, auth_info, TRUE);
3100 for (proc = sub_proto->procs; proc->name; proc++) {
3101 if (proc->num == info->call_data->opnum) {
3107 col_set_str(pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
3110 col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown operation %u %s",
3111 info->call_data->opnum,
3112 (info->ptype == PDU_REQ) ? "request" : "response");
3114 col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
3115 name, (info->ptype == PDU_REQ) ? "request" : "response");
3117 sub_dissect = (info->ptype == PDU_REQ) ?
3118 proc->dissect_rqst : proc->dissect_resp;
3121 sub_item = proto_tree_add_item(tree, sub_proto->proto_id,
3122 (decrypted_tvb != NULL)?decrypted_tvb:tvb,
3126 sub_tree = proto_item_add_subtree(sub_item, sub_proto->ett);
3128 proto_item_append_text(sub_item, ", unknown operation %u",
3129 info->call_data->opnum);
3131 proto_item_append_text(sub_item, ", %s", name);
3135 * Put the operation number into the tree along with
3136 * the operation's name.
3138 if (sub_proto->opnum_hf != -1)
3139 proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
3140 tvb, 0, 0, info->call_data->opnum,
3141 "Operation: %s (%u)",
3142 name ? name : "Unknown operation",
3143 info->call_data->opnum);
3145 proto_tree_add_uint_format_value(sub_tree, hf_dcerpc_op, tvb,
3146 0, 0, info->call_data->opnum,
3148 name ? name : "Unknown operation",
3149 info->call_data->opnum);
3151 if ((info->ptype == PDU_REQ) && (info->call_data->rep_frame != 0)) {
3152 pi = proto_tree_add_uint(sub_tree, hf_dcerpc_response_in,
3153 tvb, 0, 0, info->call_data->rep_frame);
3154 PROTO_ITEM_SET_GENERATED(pi);
3156 if ((info->ptype == PDU_RESP) && (info->call_data->req_frame != 0)) {
3157 pi = proto_tree_add_uint(sub_tree, hf_dcerpc_request_in,
3158 tvb, 0, 0, info->call_data->req_frame);
3159 PROTO_ITEM_SET_GENERATED(pi);
3163 if (decrypted_tvb != NULL) {
3164 /* Either there was no encryption or we successfully decrypted
3165 the encrypted payload. */
3167 /* We have a subdissector - call it. */
3168 saved_proto = pinfo->current_proto;
3169 pinfo->current_proto = sub_proto->name;
3171 init_ndr_pointer_list(info);
3173 length = tvb_length(decrypted_tvb);
3174 reported_length = tvb_reported_length(decrypted_tvb);
3177 * Remove the authentication padding from the stub data.
3179 if ((auth_info != NULL) && (auth_info->auth_pad_len != 0)) {
3180 if (reported_length >= auth_info->auth_pad_len) {
3182 * OK, the padding length isn't so big that it
3183 * exceeds the stub length. Trim the reported
3184 * length of the tvbuff.
3186 reported_length -= auth_info->auth_pad_len;
3189 * If that exceeds the actual amount of data in
3190 * the tvbuff (which means we have at least one
3191 * byte of authentication padding in the tvbuff),
3192 * trim the actual amount.
3194 if (length > reported_length)
3195 length = reported_length;
3197 stub_tvb = tvb_new_subset(decrypted_tvb, 0, length, reported_length);
3198 auth_pad_len = auth_info->auth_pad_len;
3199 auth_pad_offset = reported_length;
3202 * The padding length exceeds the stub length.
3203 * Don't bother dissecting the stub, trim the padding
3204 * length to what's in the stub data, and show the
3205 * entire stub as authentication padding.
3208 auth_pad_len = reported_length;
3209 auth_pad_offset = 0;
3214 * No authentication padding.
3216 stub_tvb = decrypted_tvb;
3218 auth_pad_offset = 0;
3222 proto_item_set_len(sub_item, length);
3225 if (stub_tvb != NULL) {
3227 * Catch all exceptions other than BoundsError, so that even
3228 * if the stub data is bad, we still show the authentication
3231 * If we get BoundsError, it means the frame was cut short
3232 * by a snapshot length, so there's nothing more to
3233 * dissect; just re-throw that exception.
3238 offset = sub_dissect(stub_tvb, 0, pinfo, sub_tree,
3240 proto_item_set_end(sub_item, tvb, offset);
3242 offset = dissect_verification_trailer(stub_tvb, offset,
3243 pinfo, dcerpc_tree);
3245 /* If we have a subdissector and it didn't dissect all
3246 data in the tvb, make a note of it. */
3247 remaining = tvb_reported_length_remaining(stub_tvb, offset);
3248 if (remaining > 0) {
3249 proto_tree_add_text(sub_tree, stub_tvb, offset,
3251 "[Long frame (%d byte%s)]",
3253 plurality(remaining, "", "s"));
3254 col_append_fstr(pinfo->cinfo, COL_INFO,
3255 "[Long frame (%d byte%s)]",
3257 plurality(remaining, "", "s"));
3260 } CATCH_NONFATAL_ERRORS {
3262 * Somebody threw an exception that means that there
3263 * was a problem dissecting the payload; that means
3264 * that a dissector was found, so we don't need to
3265 * dissect the payload as data or update the protocol
3268 * Just show the exception and then drive on to show
3269 * the authentication padding.
3271 show_exception(stub_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
3275 /* If there is auth padding at the end of the stub, display it */
3276 if (auth_pad_len != 0) {
3277 tvb_ensure_bytes_exist(tvb, auth_pad_offset, auth_pad_len);
3278 proto_tree_add_text(dcerpc_tree, decrypted_tvb, auth_pad_offset,
3280 "Auth Padding (%u byte%s)",
3282 plurality(auth_pad_len, "", "s"));
3285 pinfo->current_proto = saved_proto;
3287 /* No subdissector - show it as stub data. */
3288 if (decrypted_tvb) {
3289 show_stub_data(decrypted_tvb, 0, sub_tree, auth_info, FALSE);
3291 show_stub_data(tvb, 0, sub_tree, auth_info, TRUE);
3295 show_stub_data(tvb, 0, sub_tree, auth_info, TRUE);
3297 tap_queue_packet(dcerpc_tap, pinfo, info);
3302 dissect_dcerpc_verifier(tvbuff_t *tvb, packet_info *pinfo,
3303 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
3304 dcerpc_auth_info *auth_info)
3308 auth_info->auth_data = NULL;
3310 if (auth_info->auth_size != 0) {
3311 dcerpc_auth_subdissector_fns *auth_fns;
3314 auth_offset = hdr->frag_len - hdr->auth_len;
3316 auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
3319 auth_info->auth_data = auth_tvb;
3321 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
3322 auth_info->auth_type))) {
3324 * Catch all bounds-error exceptions, so that even if the
3325 * verifier is bad or we don't have all of it, we still
3326 * show the stub data.
3329 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
3331 } CATCH_BOUNDS_ERRORS {
3332 show_exception(auth_tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
3335 tvb_ensure_bytes_exist(tvb, 0, hdr->auth_len);
3336 proto_tree_add_text(dcerpc_tree, auth_tvb, 0, hdr->auth_len,
3341 return hdr->auth_len;
3345 dissect_dcerpc_cn_auth(tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
3346 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
3347 gboolean are_credentials, dcerpc_auth_info *auth_info)
3349 volatile int offset;
3352 * Initially set auth_level and auth_type to zero to indicate that we
3353 * haven't yet seen any authentication level information.
3355 auth_info->auth_level = 0;
3356 auth_info->auth_type = 0;
3357 auth_info->auth_size = 0;
3358 auth_info->auth_pad_len = 0;
3361 * The authentication information is at the *end* of the PDU; in
3362 * request and response PDUs, the request and response stub data
3365 * Is there any authentication data (i.e., is the authentication length
3366 * non-zero), and is the authentication length valid (i.e., is it, plus
3367 * 8 bytes for the type/level/pad length/reserved/context id, less than
3368 * or equal to the fragment length minus the starting offset of the
3373 && ((hdr->auth_len + 8) <= (hdr->frag_len - stub_offset))) {
3376 * Yes, there is authentication data, and the length is valid.
3377 * Do we have all the bytes of stub data?
3378 * (If not, we'd throw an exception dissecting *that*, so don't
3379 * bother trying to dissect the authentication information and
3380 * throwing another exception there.)
3382 offset = hdr->frag_len - (hdr->auth_len + 8);
3383 if (offset == 0 || tvb_offset_exists(tvb, offset - 1)) {
3385 * Either there's no stub data, or the last byte of the stub
3386 * data is present in the captured data, so we shouldn't
3387 * get a BoundsError dissecting the stub data.
3389 * Try dissecting the authentication data.
3390 * Catch all exceptions, so that even if the auth info is bad
3391 * or we don't have all of it, we still show the stuff we
3392 * dissect after this, such as stub data.
3395 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3396 hf_dcerpc_auth_type,
3397 &auth_info->auth_type);
3398 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3399 hf_dcerpc_auth_level,
3400 &auth_info->auth_level);
3402 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3403 hf_dcerpc_auth_pad_len,
3404 &auth_info->auth_pad_len);
3405 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3406 hf_dcerpc_auth_rsrvd, NULL);
3407 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3408 hf_dcerpc_auth_ctx_id, NULL);
3411 * Dissect the authentication data.
3413 if (are_credentials) {
3415 dcerpc_auth_subdissector_fns *auth_fns;
3417 auth_tvb = tvb_new_subset(tvb, offset,
3418 MIN(hdr->auth_len,tvb_length_remaining(tvb, offset)),
3421 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
3422 auth_info->auth_type)))
3423 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
3426 proto_tree_add_text(dcerpc_tree, tvb, offset, hdr->auth_len,
3427 "Auth Credentials");
3430 /* Compute the size of the auth block. Note that this should not
3431 include auth padding, since when NTLMSSP encryption is used, the
3432 padding is actually inside the encrypted stub */
3433 auth_info->auth_size = hdr->auth_len + 8;
3434 } CATCH_BOUNDS_ERRORS {
3435 show_exception(tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
3442 /* We need to hash in the SMB fid number to generate a unique hash table
3443 * key as DCERPC over SMB allows several pipes over the same TCP/IP
3445 * We pass this function the transport type here to make sure we only look
3446 * at this function if it came across an SMB pipe.
3447 * Other transports might need to mix in their own extra multiplexing data
3448 * as well in the future.
3451 guint16 dcerpc_get_transport_salt(packet_info *pinfo)
3453 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
3455 switch (decode_data->dcetransporttype) {
3456 case DCE_CN_TRANSPORT_SMBPIPE:
3457 /* DCERPC over smb */
3458 return decode_data->dcetransportsalt;
3461 /* Some other transport... */
3465 void dcerpc_set_transport_salt(guint16 dcetransportsalt, packet_info *pinfo)
3467 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
3469 decode_data->dcetransportsalt = dcetransportsalt;
3473 * Connection oriented packet types
3477 dissect_dcerpc_cn_bind(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3478 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
3480 conversation_t *conv = find_or_create_conversation(pinfo);
3481 guint8 num_ctx_items = 0;
3484 guint8 num_trans_items;
3489 guint16 if_ver, if_ver_minor;
3490 dcerpc_auth_info auth_info;
3492 const char *uuid_name = NULL;
3493 proto_item *iface_item = NULL;
3494 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
3496 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3497 hf_dcerpc_cn_max_xmit, NULL);
3499 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3500 hf_dcerpc_cn_max_recv, NULL);
3502 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3503 hf_dcerpc_cn_assoc_group, NULL);
3505 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3506 hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
3511 col_append_fstr(pinfo->cinfo, COL_INFO, ", %u context items:", num_ctx_items);
3513 for (i = 0; i < num_ctx_items; i++) {
3514 proto_item *ctx_item = NULL;
3515 proto_tree *ctx_tree = NULL, *iface_tree = NULL;
3516 gint ctx_offset = offset;
3518 dissect_dcerpc_uint16(tvb, offset, pinfo, NULL, hdr->drep,
3519 hf_dcerpc_cn_ctx_id, &ctx_id);
3521 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3522 /* (if we have multiple contexts, this might cause "decode as"
3523 * to behave unpredictably) */
3524 decode_data->dcectxid = ctx_id;
3527 ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_item,
3530 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
3533 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree, hdr->drep,
3534 hf_dcerpc_cn_ctx_id, &ctx_id);
3535 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, ctx_tree, hdr->drep,
3536 hf_dcerpc_cn_num_trans_items, &num_trans_items);
3539 proto_item_append_text(ctx_item, "[%u]: Context ID:%u", i+1, ctx_id);
3545 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &if_id);
3548 iface_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_abstract_syntax, tvb, offset, 0, ENC_NA);
3549 iface_tree = proto_item_add_subtree(iface_item, ett_dcerpc_cn_iface);
3551 uuid_str = guid_to_ep_str((e_guid_t*)&if_id);
3552 uuid_name = guids_get_uuid_name(&if_id);
3554 proto_tree_add_guid_format(iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
3555 offset, 16, (e_guid_t *) &if_id, "Interface: %s UUID: %s", uuid_name, uuid_str);
3556 proto_item_append_text(iface_item, ": %s", uuid_name);
3557 proto_item_append_text(ctx_item, ", %s", uuid_name);
3559 proto_tree_add_guid_format(iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
3560 offset, 16, (e_guid_t *) &if_id, "Interface UUID: %s", uuid_str);
3561 proto_item_append_text(iface_item, ": %s", uuid_str);
3562 proto_item_append_text(ctx_item, ", %s", uuid_str);
3567 if (hdr->drep[0] & DREP_LITTLE_ENDIAN) {
3568 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
3569 hf_dcerpc_cn_bind_if_ver, &if_ver);
3570 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
3571 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
3573 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
3574 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
3575 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
3576 hf_dcerpc_cn_bind_if_ver, &if_ver);
3580 proto_item_append_text(iface_item, " V%u.%u", if_ver, if_ver_minor);
3581 proto_item_set_len(iface_item, 20);
3584 memset(&trans_id, 0, sizeof(trans_id));
3585 for (j = 0; j < num_trans_items; j++) {
3586 proto_tree *trans_tree = NULL;
3587 proto_item *trans_item = NULL;
3588 proto_item *uuid_item = NULL;
3590 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &trans_id);
3593 trans_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_trans_syntax, tvb, offset, 0, ENC_NA);
3594 trans_tree = proto_item_add_subtree(trans_item, ett_dcerpc_cn_trans_syntax);
3596 uuid_str = guid_to_ep_str((e_guid_t *) &trans_id);
3597 uuid_name = guids_get_uuid_name(&trans_id);
3600 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);
3601 proto_item_append_text(trans_item, "[%u]: %s", j+1, uuid_name);
3602 proto_item_append_text(ctx_item, ", %s", uuid_name);
3604 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);
3605 proto_item_append_text(trans_item, "[%u]: %s", j+1, uuid_str);
3606 proto_item_append_text(ctx_item, ", %s", uuid_str);
3609 /* check for [MS-RPCE] 3.3.1.5.3 Bind Time Feature Negotiation */
3610 if (trans_id.Data1 == 0x6cb71c2c && trans_id.Data2 == 0x9812 && trans_id.Data3 == 0x4540) {
3611 proto_tree *uuid_tree = proto_item_add_subtree(uuid_item, ett_dcerpc_cn_trans_btfn);
3612 proto_tree_add_boolean(uuid_tree, hf_dcerpc_cn_bind_trans_btfn_01, tvb, offset+8, 1, trans_id.Data4[0]);
3613 proto_tree_add_boolean(uuid_tree, hf_dcerpc_cn_bind_trans_btfn_02, tvb, offset+8, 1, trans_id.Data4[0]);
3618 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, trans_tree, hdr->drep,
3619 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
3621 proto_item_set_len(trans_item, 20);
3622 proto_item_append_text(trans_item, " V%u", trans_ver);
3626 /* if this is the first time we've seen this packet, we need to
3627 update the dcerpc_binds table so that any later calls can
3628 match to the interface.
3629 XXX We assume that BINDs will NEVER be fragmented.
3631 if (!(pinfo->fd->flags.visited)) {
3632 dcerpc_bind_key *key;
3633 dcerpc_bind_value *value;
3635 key = (dcerpc_bind_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_key));
3637 key->ctx_id = ctx_id;
3638 key->smb_fid = dcerpc_get_transport_salt(pinfo);
3640 value = (dcerpc_bind_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_value));
3641 value->uuid = if_id;
3642 value->ver = if_ver;
3643 value->transport = trans_id;
3645 /* add this entry to the bind table */
3646 g_hash_table_insert(dcerpc_binds, key, value);
3650 col_append_fstr(pinfo->cinfo, COL_INFO, ",");
3651 col_append_fstr(pinfo->cinfo, COL_INFO, " %s V%u.%u (%s)",
3652 guids_resolve_uuid_to_str(&if_id), if_ver, if_ver_minor,
3653 guids_resolve_uuid_to_str(&trans_id));
3656 proto_item_set_len(ctx_item, offset - ctx_offset);
3661 * XXX - we should save the authentication type *if* we have
3662 * an authentication header, and associate it with an authentication
3663 * context, so subsequent PDUs can use that context.
3665 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
3669 dissect_dcerpc_cn_bind_ack(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3670 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
3672 guint16 max_xmit, max_recv;
3673 guint16 sec_addr_len;
3680 dcerpc_auth_info auth_info;
3681 const char *uuid_name = NULL;
3682 const char *result_str = NULL;
3684 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3685 hf_dcerpc_cn_max_xmit, &max_xmit);
3687 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3688 hf_dcerpc_cn_max_recv, &max_recv);
3690 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3691 hf_dcerpc_cn_assoc_group, NULL);
3693 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3694 hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
3695 if (sec_addr_len != 0) {
3696 tvb_ensure_bytes_exist(tvb, offset, sec_addr_len);
3697 proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
3698 sec_addr_len, ENC_ASCII|ENC_NA);
3699 offset += sec_addr_len;
3703 offset += 4 - offset % 4;
3706 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3707 hf_dcerpc_cn_num_results, &num_results);
3712 col_append_fstr(pinfo->cinfo, COL_INFO, ", max_xmit: %u max_recv: %u, %u results:",
3713 max_xmit, max_recv, num_results);
3715 for (i = 0; i < num_results; i++) {
3716 proto_tree *ctx_tree = NULL;
3717 proto_item *ctx_item = NULL;
3720 ctx_item = proto_tree_add_text(dcerpc_tree, tvb, offset, 24, "Ctx Item[%u]:", i+1);
3721 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
3724 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree,
3725 hdr->drep, hf_dcerpc_cn_ack_result,
3728 /* [MS-RPCE] 3.3.1.5.3 check if this Ctx Item is the response to a Bind Time Feature Negotiation request */
3730 const int old_offset = offset;
3731 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree, hdr->drep, hf_dcerpc_cn_ack_btfn, &reason);
3732 proto_tree_add_boolean(ctx_tree, hf_dcerpc_cn_bind_trans_btfn_01, tvb, old_offset, 1, reason);
3733 proto_tree_add_boolean(ctx_tree, hf_dcerpc_cn_bind_trans_btfn_02, tvb, old_offset, 1, reason);
3734 } else if (result != 0) {
3735 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree,
3736 hdr->drep, hf_dcerpc_cn_ack_reason,
3740 * The reason for rejection isn't meaningful, and often isn't
3741 * set, when the syntax was accepted.
3746 result_str = val_to_str(result, p_cont_result_vals, "Unknown result (%u)");
3749 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &trans_id);
3750 uuid_name = guids_get_uuid_name(&trans_id);
3752 uuid_name = guid_to_ep_str((e_guid_t *) &trans_id);
3754 proto_tree_add_guid_format(ctx_tree, hf_dcerpc_cn_ack_trans_id, tvb,
3755 offset, 16, (e_guid_t *) &trans_id, "Transfer Syntax: %s",
3757 proto_item_append_text(ctx_item, " %s, %s", result_str, uuid_name);
3761 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, ctx_tree, hdr->drep,
3762 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
3765 col_append_fstr(pinfo->cinfo, COL_INFO, ",");
3766 col_append_fstr(pinfo->cinfo, COL_INFO, " %s", result_str);
3770 * XXX - do we need to do anything with the authentication level
3771 * we get back from this?
3773 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
3777 dissect_dcerpc_cn_bind_nak(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3778 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
3781 guint8 num_protocols;
3784 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
3785 hdr->drep, hf_dcerpc_cn_reject_reason,
3788 col_append_fstr(pinfo->cinfo, COL_INFO, " reason: %s",
3789 val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
3791 if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
3792 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3793 hf_dcerpc_cn_num_protocols,
3796 for (i = 0; i < num_protocols; i++) {
3797 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
3798 hdr->drep, hf_dcerpc_cn_protocol_ver_major,
3800 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
3801 hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
3807 /* Return a string describing a DCE/RPC fragment as first, middle, or end
3810 #define PFC_FRAG_MASK 0x03
3813 fragment_type(guint8 flags)
3815 static const char* t[4] = {
3821 return t[flags & PFC_FRAG_MASK];
3824 /* Dissect stub data (payload) of a DCERPC packet. */
3827 dissect_dcerpc_cn_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
3828 proto_tree *dcerpc_tree, proto_tree *tree,
3829 e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
3830 dcerpc_auth_info *auth_info, guint32 alloc_hint _U_,
3833 gint length, reported_length;
3834 gboolean save_fragmented;
3835 fragment_head *fd_head = NULL;
3837 tvbuff_t *auth_tvb, *payload_tvb, *decrypted_tvb;
3839 proto_item *parent_pi;
3840 proto_item *dcerpc_tree_item;
3842 save_fragmented = pinfo->fragmented;
3844 length = tvb_length_remaining(tvb, offset);
3845 reported_length = tvb_reported_length_remaining(tvb, offset);
3846 if (reported_length < 0 ||
3847 (guint32)reported_length < auth_info->auth_size) {
3848 /* We don't even have enough bytes for the authentication
3852 reported_length -= auth_info->auth_size;
3853 if (length > reported_length)
3854 length = reported_length;
3855 payload_tvb = tvb_new_subset(tvb, offset, length, reported_length);
3858 /*don't bother if we don't have the entire tvb */
3859 /*XXX we should really make sure we calculate auth_info->auth_data
3860 and use that one instead of this auth_tvb hack
3862 if (tvb_length(tvb) == tvb_reported_length(tvb)) {
3863 if (tvb_length_remaining(tvb, offset+length) > 8) {
3864 auth_tvb = tvb_new_subset_remaining(tvb, offset+length+8);
3868 /* Decrypt the PDU if it is encrypted */
3870 if (auth_info->auth_type &&
3871 (auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)) {
3873 * We know the authentication type, and the authentication
3874 * level is "Packet privacy", meaning the payload is
3875 * encrypted; attempt to decrypt it.
3877 dcerpc_auth_subdissector_fns *auth_fns;
3879 /* Start out assuming we won't succeed in decrypting. */
3880 decrypted_tvb = NULL;
3881 /* Schannel needs information into the footer (verifier) in order to setup decryption keys
3882 * so we call it in order to have a chance to decipher the data
3884 if (DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN == auth_info->auth_type) {
3885 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, auth_info);
3888 if ((auth_fns = get_auth_subdissector_fns(
3889 auth_info->auth_level, auth_info->auth_type))) {
3892 result = decode_encrypted_data(
3893 payload_tvb, auth_tvb, pinfo, auth_fns,
3894 hdr->ptype == PDU_REQ, auth_info);
3898 proto_tree_add_text(
3899 dcerpc_tree, payload_tvb, 0, -1,
3900 "Encrypted stub data (%d byte%s)",
3901 tvb_reported_length(payload_tvb),
3903 plurality(tvb_length(payload_tvb), "", "s"));
3905 add_new_data_source(
3906 pinfo, result, "Decrypted stub data");
3909 decrypted_tvb = result;
3913 decrypted_tvb = payload_tvb;
3915 /* if this packet is not fragmented, just dissect it and exit */
3916 if (PFC_NOT_FRAGMENTED(hdr)) {
3917 pinfo->fragmented = FALSE;
3920 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
3921 hdr->drep, di, auth_info);
3923 pinfo->fragmented = save_fragmented;
3927 /* The packet is fragmented. */
3928 pinfo->fragmented = TRUE;
3930 /* debug output of essential fragment data. */
3931 /* leave it here for future debugging sessions */
3932 /*printf("DCE num:%u offset:%u frag_len:%u tvb_len:%u\n",
3933 pinfo->fd->num, offset, hdr->frag_len, tvb_length(decrypted_tvb));*/
3935 /* if we are not doing reassembly and this is the first fragment
3936 then just dissect it and exit
3937 XXX - if we're not doing reassembly, can we decrypt an
3940 if ( (!dcerpc_reassemble) && (hdr->flags & PFC_FIRST_FRAG) ) {
3943 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
3944 hdr->drep, di, auth_info);
3946 expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment, "%s fragment", fragment_type(hdr->flags));
3948 pinfo->fragmented = save_fragmented;
3952 /* if we have already seen this packet, see if it was reassembled
3953 and if so dissect the full pdu.
3956 if (pinfo->fd->flags.visited) {
3957 fd_head = fragment_get_reassembled(&dcerpc_co_reassembly_table, frame);
3961 /* if we are not doing reassembly and it was neither a complete PDU
3962 nor the first fragment then there is nothing more we can do
3963 so we just have to exit
3965 if ( !dcerpc_reassemble || (tvb_length(tvb) != tvb_reported_length(tvb)) )
3968 /* if we didn't get 'frame' we don't know where the PDU started and thus
3969 it is pointless to continue
3974 /* from now on we must attempt to reassemble the PDU
3977 /* if we get here we know it is the first time we see the packet
3978 and we also know it is only a fragment and not a full PDU,
3979 thus we must reassemble it.
3982 /* Do we have any non-encrypted data to reassemble? */
3983 if (decrypted_tvb == NULL) {
3984 /* No. We can't even try to reassemble. */
3988 /* defragmentation is a bit tricky, as there's no offset of the fragment
3989 * in the protocol data.
3991 * just use fragment_add_seq_next() and hope that TCP/SMB segments coming
3992 * in with the correct sequence.
3994 fd_head = fragment_add_seq_next(&dcerpc_co_reassembly_table,
3995 decrypted_tvb, 0, pinfo, frame, NULL,
3996 tvb_length(decrypted_tvb),
3997 hdr->flags&PFC_LAST_FRAG ? FALSE : TRUE /* more_frags */);
4001 /* if reassembly is complete and this is the last fragment
4002 * (multiple fragments in one PDU are possible!)
4003 * dissect the full PDU
4005 if (fd_head && (fd_head->flags & FD_DEFRAGMENTED) ) {
4007 if ((pinfo->fd->num == fd_head->reassembled_in) && (hdr->flags & PFC_LAST_FRAG) ) {
4009 proto_item *frag_tree_item;
4011 next_tvb = tvb_new_chain((decrypted_tvb)?decrypted_tvb:payload_tvb,
4014 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
4015 show_fragment_tree(fd_head, &dcerpc_frag_items,
4016 tree, pinfo, next_tvb, &frag_tree_item);
4017 /* the toplevel fragment subtree is now behind all desegmented data,
4018 * move it right behind the DCE/RPC tree */
4019 dcerpc_tree_item = proto_tree_get_parent(dcerpc_tree);
4020 if (frag_tree_item && dcerpc_tree_item) {
4021 proto_tree_move_item(tree, dcerpc_tree_item, frag_tree_item);
4024 pinfo->fragmented = FALSE;
4026 expert_add_info_format(pinfo, frag_tree_item, &ei_dcerpc_fragment_reassembled, "%s fragment, reassembled", fragment_type(hdr->flags));
4028 dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb,
4029 next_tvb, hdr->drep, di, auth_info);
4032 if (decrypted_tvb) {
4033 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
4034 decrypted_tvb, 0, 0, fd_head->reassembled_in);
4036 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
4037 payload_tvb, 0, 0, fd_head->reassembled_in);
4039 PROTO_ITEM_SET_GENERATED(pi);
4040 parent_pi = proto_tree_get_parent(dcerpc_tree);
4041 if (parent_pi != NULL) {
4042 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
4044 col_append_fstr(pinfo->cinfo, COL_INFO,
4045 " [DCE/RPC %s fragment, reas: #%u]", fragment_type(hdr->flags), fd_head->reassembled_in);
4046 expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment_reassembled, "%s fragment, reassembled in #%u", fragment_type(hdr->flags), fd_head->reassembled_in);
4049 /* Reassembly not complete - some fragments
4050 are missing. Just show the stub data. */
4051 expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment, "%s fragment", fragment_type(hdr->flags));
4053 if (decrypted_tvb) {
4054 show_stub_data(decrypted_tvb, 0, tree, auth_info, FALSE);
4056 show_stub_data(payload_tvb, 0, tree, auth_info, TRUE);
4060 pinfo->fragmented = save_fragmented;
4064 dissect_dcerpc_cn_rqst(tvbuff_t *tvb, gint offset, packet_info *pinfo,
4065 proto_tree *dcerpc_tree, proto_tree *tree,
4066 e_dce_cn_common_hdr_t *hdr)
4068 conversation_t *conv;
4071 e_uuid_t obj_id = DCERPC_UUID_NULL;
4072 dcerpc_auth_info auth_info;
4075 proto_item *parent_pi;
4076 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
4078 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4079 hf_dcerpc_cn_alloc_hint, &alloc_hint);
4081 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4082 hf_dcerpc_cn_ctx_id, &ctx_id);
4083 parent_pi = proto_tree_get_parent(dcerpc_tree);
4084 if (parent_pi != NULL) {
4085 proto_item_append_text(parent_pi, ", Ctx: %u", ctx_id);
4088 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4089 hf_dcerpc_opnum, &opnum);
4091 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
4092 decode_data->dcectxid = ctx_id;
4094 col_append_fstr(pinfo->cinfo, COL_INFO, ", opnum: %u, Ctx: %u",
4097 if (hdr->flags & PFC_OBJECT_UUID) {
4098 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &obj_id);
4100 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
4101 offset, 16, (e_guid_t *) &obj_id, "Object UUID: %s",
4102 guid_to_ep_str((e_guid_t *) &obj_id));
4108 * XXX - what if this was set when the connection was set up,
4109 * and we just have a security context?
4111 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
4113 conv = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
4114 pinfo->srcport, pinfo->destport, 0);
4116 show_stub_data(tvb, offset, dcerpc_tree, &auth_info, TRUE);
4118 dcerpc_matched_key matched_key, *new_matched_key;
4119 dcerpc_call_value *value;
4121 /* !!! we can NOT check flags.visited here since this will interact
4122 badly with when SMB handles (i.e. calls the subdissector)
4123 and desegmented pdu's .
4124 Instead we check if this pdu is already in the matched table or not
4126 matched_key.frame = pinfo->fd->num;
4127 matched_key.call_id = hdr->call_id;
4128 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
4130 dcerpc_bind_key bind_key;
4131 dcerpc_bind_value *bind_value;
4133 bind_key.conv = conv;
4134 bind_key.ctx_id = ctx_id;
4135 bind_key.smb_fid = dcerpc_get_transport_salt(pinfo);
4137 if ((bind_value = (dcerpc_bind_value *)g_hash_table_lookup(dcerpc_binds, &bind_key)) ) {
4138 if (!(hdr->flags&PFC_FIRST_FRAG)) {
4139 dcerpc_cn_call_key call_key;
4140 dcerpc_call_value *call_value;
4142 call_key.conv = conv;
4143 call_key.call_id = hdr->call_id;
4144 call_key.smb_fid = dcerpc_get_transport_salt(pinfo);
4145 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_cn_calls, &call_key))) {
4146 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
4147 *new_matched_key = matched_key;
4148 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
4152 dcerpc_cn_call_key *call_key;
4153 dcerpc_call_value *call_value;
4155 /* We found the binding and it is the first fragment
4156 (or a complete PDU) of a dcerpc pdu so just add
4157 the call to both the call table and the
4160 call_key = (dcerpc_cn_call_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_cn_call_key));
4161 call_key->conv = conv;
4162 call_key->call_id = hdr->call_id;
4163 call_key->smb_fid = dcerpc_get_transport_salt(pinfo);
4165 /* if there is already a matching call in the table
4166 remove it so it is replaced with the new one */
4167 if (g_hash_table_lookup(dcerpc_cn_calls, call_key)) {
4168 g_hash_table_remove(dcerpc_cn_calls, call_key);
4171 call_value = (dcerpc_call_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_call_value));
4172 call_value->uuid = bind_value->uuid;
4173 call_value->ver = bind_value->ver;
4174 call_value->object_uuid = obj_id;
4175 call_value->opnum = opnum;
4176 call_value->req_frame = pinfo->fd->num;
4177 call_value->req_time = pinfo->fd->abs_ts;
4178 call_value->rep_frame = 0;
4179 call_value->max_ptr = 0;
4180 call_value->se_data = NULL;
4181 call_value->private_data = NULL;
4182 call_value->pol = NULL;
4183 call_value->flags = 0;
4184 if (!memcmp(&bind_value->transport, &uuid_ndr64, sizeof(uuid_ndr64))) {
4185 call_value->flags |= DCERPC_IS_NDR64;
4188 g_hash_table_insert(dcerpc_cn_calls, call_key, call_value);
4190 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
4191 *new_matched_key = matched_key;
4192 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
4202 /* handoff this call */
4204 di->call_id = hdr->call_id;
4205 di->smb_fid = dcerpc_get_transport_salt(pinfo);
4206 di->ptype = PDU_REQ;
4207 di->call_data = value;
4210 if (value->rep_frame != 0) {
4211 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
4212 tvb, 0, 0, value->rep_frame);
4213 PROTO_ITEM_SET_GENERATED(pi);
4214 if (parent_pi != NULL) {
4215 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
4219 dissect_dcerpc_cn_stub(tvb, offset, pinfo, dcerpc_tree, tree,
4220 hdr, di, &auth_info, alloc_hint,
4223 /* no bind information, simply show stub data */
4224 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);
4225 show_stub_data(tvb, offset, dcerpc_tree, &auth_info, TRUE);
4229 /* Dissect the verifier */
4230 dissect_dcerpc_verifier(tvb, pinfo, dcerpc_tree, hdr, &auth_info);
4235 dissect_dcerpc_cn_resp(tvbuff_t *tvb, gint offset, packet_info *pinfo,
4236 proto_tree *dcerpc_tree, proto_tree *tree,
4237 e_dce_cn_common_hdr_t *hdr)
4239 dcerpc_call_value *value = NULL;
4240 conversation_t *conv;
4242 dcerpc_auth_info auth_info;
4245 proto_item *parent_pi;
4246 e_uuid_t obj_id_null = DCERPC_UUID_NULL;
4247 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
4249 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4250 hf_dcerpc_cn_alloc_hint, &alloc_hint);
4252 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4253 hf_dcerpc_cn_ctx_id, &ctx_id);
4254 parent_pi = proto_tree_get_parent(dcerpc_tree);
4255 if (parent_pi != NULL) {
4256 proto_item_append_text(parent_pi, ", Ctx: %u", ctx_id);
4259 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
4260 decode_data->dcectxid = ctx_id;
4262 col_append_fstr(pinfo->cinfo, COL_INFO, ", Ctx: %u", ctx_id);
4264 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4265 hf_dcerpc_cn_cancel_count, NULL);
4270 * XXX - what if this was set when the connection was set up,
4271 * and we just have a security context?
4273 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
4275 conv = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
4276 pinfo->srcport, pinfo->destport, 0);
4279 /* no point in creating one here, really */
4280 show_stub_data(tvb, offset, dcerpc_tree, &auth_info, TRUE);
4282 dcerpc_matched_key matched_key, *new_matched_key;
4284 /* !!! we can NOT check flags.visited here since this will interact
4285 badly with when SMB handles (i.e. calls the subdissector)
4286 and desegmented pdu's .
4287 Instead we check if this pdu is already in the matched table or not
4289 matched_key.frame = pinfo->fd->num;
4290 matched_key.call_id = hdr->call_id;
4291 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
4293 dcerpc_cn_call_key call_key;
4294 dcerpc_call_value *call_value;
4296 call_key.conv = conv;
4297 call_key.call_id = hdr->call_id;
4298 call_key.smb_fid = dcerpc_get_transport_salt(pinfo);
4300 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_cn_calls, &call_key))) {
4301 /* extra sanity check, only match them if the reply
4302 came after the request */
4303 if (call_value->req_frame<pinfo->fd->num) {
4304 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
4305 *new_matched_key = matched_key;
4306 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
4308 if (call_value->rep_frame == 0) {
4309 call_value->rep_frame = pinfo->fd->num;
4319 /* handoff this call */
4321 di->call_id = hdr->call_id;
4322 di->smb_fid = dcerpc_get_transport_salt(pinfo);
4323 di->ptype = PDU_RESP;
4324 di->call_data = value;
4326 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
4328 /* (optional) "Object UUID" from request */
4329 if (dcerpc_tree && (memcmp(&value->object_uuid, &obj_id_null, sizeof(obj_id_null)) != 0)) {
4330 pi = proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
4331 offset, 0, (e_guid_t *) &value->object_uuid, "Object UUID: %s",
4332 guid_to_ep_str((e_guid_t *) &value->object_uuid));
4333 PROTO_ITEM_SET_GENERATED(pi);
4337 if (value->req_frame != 0) {
4339 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4340 tvb, 0, 0, value->req_frame);
4341 PROTO_ITEM_SET_GENERATED(pi);
4342 if (parent_pi != NULL) {
4343 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
4345 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
4346 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
4347 PROTO_ITEM_SET_GENERATED(pi);
4349 proto_tree_add_expert(dcerpc_tree, pinfo, &ei_dcerpc_no_request_found, tvb, 0, 0);
4352 dissect_dcerpc_cn_stub(tvb, offset, pinfo, dcerpc_tree, tree,
4353 hdr, di, &auth_info, alloc_hint,
4356 /* no bind information, simply show stub data */
4357 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);
4358 show_stub_data(tvb, offset, dcerpc_tree, &auth_info, TRUE);
4362 /* Dissect the verifier */
4363 dissect_dcerpc_verifier(tvb, pinfo, dcerpc_tree, hdr, &auth_info);
4367 dissect_dcerpc_cn_fault(tvbuff_t *tvb, gint offset, packet_info *pinfo,
4368 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
4370 dcerpc_call_value *value = NULL;
4371 conversation_t *conv;
4375 dcerpc_auth_info auth_info;
4376 proto_item *pi = NULL;
4377 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
4379 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4380 hf_dcerpc_cn_alloc_hint, &alloc_hint);
4382 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4383 hf_dcerpc_cn_ctx_id, &ctx_id);
4385 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4386 hf_dcerpc_cn_cancel_count, NULL);
4391 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4392 hf_dcerpc_cn_status, &status);
4394 status = ((hdr->drep[0] & DREP_LITTLE_ENDIAN)
4395 ? tvb_get_letohl(tvb, offset)
4396 : tvb_get_ntohl(tvb, offset));
4398 pi = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_status, tvb, offset, 4, DREP_ENC_INTEGER(hdr->drep));
4401 expert_add_info_format(pinfo, pi, &ei_dcerpc_cn_status, "Fault: %s", val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
4403 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
4404 decode_data->dcectxid = ctx_id;
4406 col_append_fstr(pinfo->cinfo, COL_INFO,
4407 ", Ctx: %u, status: %s", ctx_id,
4408 val_to_str(status, reject_status_vals,
4409 "Unknown (0x%08x)"));
4415 * XXX - what if this was set when the connection was set up,
4416 * and we just have a security context?
4418 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
4420 conv = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
4421 pinfo->srcport, pinfo->destport, 0);
4423 /* no point in creating one here, really */
4425 dcerpc_matched_key matched_key, *new_matched_key;
4427 /* !!! we can NOT check flags.visited here since this will interact
4428 badly with when SMB handles (i.e. calls the subdissector)
4429 and desegmented pdu's .
4430 Instead we check if this pdu is already in the matched table or not
4432 matched_key.frame = pinfo->fd->num;
4433 matched_key.call_id = hdr->call_id;
4434 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
4436 dcerpc_cn_call_key call_key;
4437 dcerpc_call_value *call_value;
4439 call_key.conv = conv;
4440 call_key.call_id = hdr->call_id;
4441 call_key.smb_fid = dcerpc_get_transport_salt(pinfo);
4443 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_cn_calls, &call_key))) {
4444 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
4445 *new_matched_key = matched_key;
4446 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
4449 if (call_value->rep_frame == 0) {
4450 call_value->rep_frame = pinfo->fd->num;
4457 int length, stub_length;
4459 proto_item *parent_pi;
4462 /* handoff this call */
4464 di->call_id = hdr->call_id;
4465 di->smb_fid = dcerpc_get_transport_salt(pinfo);
4466 di->ptype = PDU_FAULT;
4467 di->call_data = value;
4469 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
4470 if (value->req_frame != 0) {
4472 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4473 tvb, 0, 0, value->req_frame);
4474 PROTO_ITEM_SET_GENERATED(pi);
4475 parent_pi = proto_tree_get_parent(dcerpc_tree);
4476 if (parent_pi != NULL) {
4477 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
4479 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
4480 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
4481 PROTO_ITEM_SET_GENERATED(pi);
4483 proto_tree_add_expert(dcerpc_tree, pinfo, &ei_dcerpc_no_request_found, tvb, 0, 0);
4486 length = tvb_length_remaining(tvb, offset);
4487 /* as we now create a tvb in dissect_dcerpc_cn() containing only the
4488 * stub_data, the following calculation is no longer valid:
4489 * stub_length = hdr->frag_len - offset - auth_info.auth_size;
4490 * simply use the remaining length of the tvb instead.
4491 * XXX - or better use the reported_length?!?
4493 stub_length = length;
4494 if (length > stub_length)
4495 length = stub_length;
4497 /* If we don't have reassembly enabled, or this packet contains
4498 the entire PDU, or if we don't have all the data in this
4499 fragment, just call the handoff directly if this is the
4500 first fragment or the PDU isn't fragmented. */
4501 if ( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
4502 !tvb_bytes_exist(tvb, offset, stub_length) ) {
4503 if (hdr->flags&PFC_FIRST_FRAG) {
4504 /* First fragment, possibly the only fragment */
4506 * XXX - should there be a third routine for each
4507 * function in an RPC subdissector, to handle
4508 * fault responses? The DCE RPC 1.1 spec says
4509 * three's "stub data" here, which I infer means
4510 * that it's protocol-specific and call-specific.
4512 * It should probably get passed the status code
4513 * as well, as that might be protocol-specific.
4516 if (stub_length > 0) {
4517 tvb_ensure_bytes_exist(tvb, offset, stub_length);
4518 proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
4519 "Fault stub data (%d byte%s)",
4521 plurality(stub_length, "", "s"));
4525 /* PDU is fragmented and this isn't the first fragment */
4527 if (stub_length > 0) {
4528 tvb_ensure_bytes_exist(tvb, offset, stub_length);
4529 proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
4530 "Fragment data (%d byte%s)",
4532 plurality(stub_length, "", "s"));
4537 /* Reassembly is enabled, the PDU is fragmented, and
4538 we have all the data in the fragment; the first two
4539 of those mean we should attempt reassembly, and the
4540 third means we can attempt reassembly. */
4543 tvb_ensure_bytes_exist(tvb, offset, stub_length);
4544 proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
4545 "Fragment data (%d byte%s)",
4547 plurality(stub_length, "", "s"));
4550 if (hdr->flags&PFC_FIRST_FRAG) { /* FIRST fragment */
4551 if ( (!pinfo->fd->flags.visited) && value->rep_frame ) {
4552 fragment_add_seq_next(&dcerpc_co_reassembly_table,
4554 pinfo, value->rep_frame, NULL,
4558 } else if (hdr->flags&PFC_LAST_FRAG) { /* LAST fragment */
4559 if ( value->rep_frame ) {
4560 fragment_head *fd_head;
4562 fd_head = fragment_add_seq_next(&dcerpc_co_reassembly_table,
4564 pinfo, value->rep_frame, NULL,
4569 /* We completed reassembly */
4571 proto_item *frag_tree_item;
4573 next_tvb = tvb_new_chain(tvb, fd_head->tvb_data);
4574 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
4575 show_fragment_tree(fd_head, &dcerpc_frag_items,
4576 dcerpc_tree, pinfo, next_tvb, &frag_tree_item);
4579 * XXX - should there be a third routine for each
4580 * function in an RPC subdissector, to handle
4581 * fault responses? The DCE RPC 1.1 spec says
4582 * three's "stub data" here, which I infer means
4583 * that it's protocol-specific and call-specific.
4585 * It should probably get passed the status code
4586 * as well, as that might be protocol-specific.
4590 tvb_ensure_bytes_exist(tvb, offset, stub_length);
4591 proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
4592 "Fault stub data (%d byte%s)",
4594 plurality(stub_length, "", "s"));
4599 } else { /* MIDDLE fragment(s) */
4600 if ( (!pinfo->fd->flags.visited) && value->rep_frame ) {
4601 fragment_add_seq_next(&dcerpc_co_reassembly_table,
4603 pinfo, value->rep_frame, NULL,
4614 dissect_dcerpc_cn_rts(tvbuff_t *tvb, gint offset, packet_info *pinfo,
4615 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
4617 proto_item *tf = NULL;
4618 proto_item *parent_pi = NULL;
4619 proto_tree *cn_rts_pdu_tree = NULL;
4621 guint16 commands_nb = 0;
4624 const char *info_str = NULL;
4626 /* Dissect specific RTS header */
4627 rts_flags = dcerpc_tvb_get_ntohs(tvb, offset, hdr->drep);
4629 proto_tree *cn_rts_flags_tree;
4631 tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_rts_flags, tvb, offset, 2, rts_flags);
4632 cn_rts_flags_tree = proto_item_add_subtree(tf, ett_dcerpc_cn_rts_flags);
4633 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_none, tvb, offset, 1, rts_flags);
4634 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_ping, tvb, offset, 1, rts_flags);
4635 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_other_cmd, tvb, offset, 1, rts_flags);
4636 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_recycle_channel, tvb, offset, 1, rts_flags);
4637 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_in_channel, tvb, offset, 1, rts_flags);
4638 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_out_channel, tvb, offset, 1, rts_flags);
4639 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_eof, tvb, offset, 1, rts_flags);
4643 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4644 hf_dcerpc_cn_rts_commands_nb, &commands_nb);
4646 /* Create the RTS PDU tree - we do not yet know its name */
4647 tf = proto_tree_add_text(dcerpc_tree, tvb, offset, tvb_length_remaining(tvb, offset), "RTS PDU: %u commands", commands_nb);
4648 cn_rts_pdu_tree = proto_item_add_subtree(tf, ett_dcerpc_cn_rts_pdu);
4650 cmd = (guint32 *)wmem_alloc(wmem_packet_scope(), sizeof (guint32) * (commands_nb + 1));
4652 /* Dissect commands */
4653 for (i = 0; i < commands_nb; ++i) {
4654 proto_tree *cn_rts_command_tree = NULL;
4655 const guint32 command = dcerpc_tvb_get_ntohl(tvb, offset, hdr->drep);
4657 tf = proto_tree_add_uint(cn_rts_pdu_tree, hf_dcerpc_cn_rts_command, tvb, offset, 4, command);
4658 cn_rts_command_tree = proto_item_add_subtree(tf, ett_dcerpc_cn_rts_command);
4661 case RTS_CMD_RECEIVEWINDOWSIZE:
4662 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_receivewindowsize, NULL);
4664 case RTS_CMD_FLOWCONTROLACK:
4665 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_fack_bytesreceived, NULL);
4666 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_fack_availablewindow, NULL);
4667 offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_fack_channelcookie, NULL);
4669 case RTS_CMD_CONNECTIONTIMEOUT:
4670 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_connectiontimeout, NULL);
4672 case RTS_CMD_COOKIE:
4673 offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_cookie, NULL);
4675 case RTS_CMD_CHANNELLIFETIME:
4676 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_channellifetime, NULL);
4678 case RTS_CMD_CLIENTKEEPALIVE:
4679 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_clientkeepalive, NULL);
4681 case RTS_CMD_VERSION:
4682 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_version, NULL);
4686 case RTS_CMD_PADDING: {
4688 const guint32 conformance_count = dcerpc_tvb_get_ntohl(tvb, offset, hdr->drep);
4689 proto_tree_add_uint(cn_rts_command_tree, hf_dcerpc_cn_rts_command_conformancecount, tvb, offset, 4, conformance_count);
4691 padding = (guint8 *)tvb_memdup(NULL, tvb, offset, conformance_count);
4692 proto_tree_add_bytes(cn_rts_command_tree, hf_dcerpc_cn_rts_command_padding, tvb, offset, conformance_count, padding);
4693 offset += conformance_count;
4695 case RTS_CMD_NEGATIVEANCE:
4699 case RTS_CMD_CLIENTADDRESS: {
4701 const guint32 addrtype = dcerpc_tvb_get_ntohl(tvb, offset, hdr->drep);
4702 proto_tree_add_uint(cn_rts_command_tree, hf_dcerpc_cn_rts_command_addrtype, tvb, offset, 4, addrtype);
4706 const guint32 addr4 = tvb_get_ipv4(tvb, offset);
4707 proto_tree_add_text(cn_rts_command_tree, tvb, offset, 4, "%s", get_hostname(addr4));
4711 struct e_in6_addr addr6;
4712 tvb_get_ipv6(tvb, offset, &addr6);
4713 proto_tree_add_text(cn_rts_command_tree, tvb, offset, 16, "%s", get_hostname6(&addr6));
4717 padding = (guint8 *)tvb_memdup(NULL, tvb, offset, 12);
4718 proto_tree_add_bytes(cn_rts_command_tree, hf_dcerpc_cn_rts_command_padding, tvb, offset, 12, padding);
4721 case RTS_CMD_ASSOCIATIONGROUPID:
4722 offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_associationgroupid, NULL);
4724 case RTS_CMD_DESTINATION:
4725 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_forwarddestination, NULL);
4727 case RTS_CMD_PINGTRAFFICSENTNOTIFY:
4728 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_pingtrafficsentnotify, NULL);
4731 proto_tree_add_text(cn_rts_command_tree, tvb, offset, 0, "unknown RTS command number");
4736 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RPCH");
4738 /* Define which PDU Body we are dealing with */
4739 info_str = "unknown RTS PDU";
4741 switch (rts_flags) {
4743 switch (commands_nb) {
4745 if (cmd[0] == 0x2) {
4746 info_str = "CONN/A3";
4747 } else if (cmd[0] == 0x3) {
4748 info_str = "IN_R1/A5,IN_R1/A6,IN_R2/A2,IN_R2/A5,OUT_R2/A4";
4749 } else if (cmd[0] == 0x7) {
4750 info_str = "IN_R1/B1";
4751 } else if (cmd[0] == 0x0) {
4752 info_str = "IN_R1/B2";
4753 } else if (cmd[0] == 0xD) {
4754 info_str = "IN_R2/A3,IN_R2/A4";
4755 } else if (cmd[0] == 0xA) {
4756 info_str = "OUT_R1/A9,OUT_R1/A10,OUT_R1/A11,OUT_R2/B1,OUT_R2/B2";
4760 if ((cmd[0] == 0x0) && (cmd[1] == 0x6)) {
4761 info_str = "CONN/B3";
4762 } else if ((cmd[0] == 0xD) && (cmd[1] == 0xA)) {
4763 info_str = "OUT_R2/A5,OUT_R2/A6";
4767 if ((cmd[0] == 0x6) && (cmd[1] == 0x0) && (cmd[2] == 0x2)) {
4768 info_str = "CONN/C1,CONN/C2";
4772 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x0)) {
4773 info_str = "CONN/A1";
4774 } else if ((cmd[0] == 0xD) && (cmd[1] == 0x6) && (cmd[2] == 0x0) && (cmd[3] == 0x2)) {
4775 info_str = "IN_R1/A3,IN_R1/A4";
4779 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x4) && (cmd[4] == 0x5) && (cmd[5] == 0xC)) {
4780 info_str = "CONN/B1";
4788 switch (commands_nb) {
4793 if ((cmd[0] == 0x7) || (cmd[0] == 0x8)) {
4794 info_str = "OUT_R2/C1";
4801 case RTS_FLAG_OTHER_CMD:
4802 switch (commands_nb) {
4804 if (cmd[0] == 0x5) {
4805 info_str = "Keep-Alive";
4806 } else if (cmd[0] == 0xE) {
4807 info_str = "PingTrafficSentNotify";
4808 } else if (cmd[0] == 0x1) {
4809 info_str = "FlowControlAck";
4813 if ((cmd[0] == 0xD) && (cmd[1] == 0x1)) {
4814 info_str = "FlowControlAckWithDestination";
4821 case RTS_FLAG_RECYCLE_CHANNEL:
4822 switch (commands_nb) {
4824 if (cmd[0] == 0xD) {
4825 info_str = "OUT_R1/A1,OUT_R1/A2,OUT_R2/A1,OUT_R2/A2";
4829 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3)) {
4830 info_str = "IN_R1/A1,IN_R2/A1";
4834 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3) && (cmd[4] == 0x0)) {
4835 info_str = "OUT_R1/A3,OUT_R2/A3";
4842 case RTS_FLAG_IN_CHANNEL|RTS_FLAG_RECYCLE_CHANNEL:
4843 switch (commands_nb) {
4845 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3) && (cmd[4] == 0x0) && (cmd[5] == 0x2)) {
4846 info_str = "IN_R1/A2";
4852 case RTS_FLAG_IN_CHANNEL:
4853 switch (commands_nb) {
4855 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x0) && (cmd[4] == 0x2) && (cmd[5] == 0xC) && (cmd[6] == 0xB)) {
4856 info_str = "CONN/B2";
4862 case RTS_FLAG_OUT_CHANNEL|RTS_FLAG_RECYCLE_CHANNEL:
4863 switch (commands_nb) {
4865 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3) && (cmd[4] == 0x4) && (cmd[5] == 0) && (cmd[6] == 0x2)) {
4866 info_str = "OUT_R1/A4";
4873 case RTS_FLAG_OUT_CHANNEL:
4874 switch (commands_nb) {
4876 if ((cmd[0] == 0xD) && (cmd[1] == 0x3)) {
4877 info_str = "OUT_R1/A7,OUT_R1/A8,OUT_R2/A8";
4881 if ((cmd[0] == 0xD) && (cmd[1] == 0x6) && (cmd[2] == 0x2)) {
4882 info_str = "OUT_R1/A5,OUT_R1/A6";
4883 } else if ((cmd[0] == 0xD) && (cmd[1] == 0x3) && (cmd[2] == 0x6)) {
4884 info_str = "OUT_R2/A7";
4888 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x4) && (cmd[4] == 0x0)) {
4889 info_str = "CONN/A2";
4896 switch (commands_nb) {
4898 if (cmd[0] == 0xA) {
4899 info_str = "OUT_R2/B3";
4907 switch (commands_nb) {
4919 col_add_fstr(pinfo->cinfo, COL_INFO, "%s, ", info_str);
4920 col_set_fence(pinfo->cinfo,COL_INFO);
4922 parent_pi = proto_tree_get_parent(dcerpc_tree);
4923 if (parent_pi != NULL) {
4924 proto_item_append_text(parent_pi, ", %s", info_str);
4929 * DCERPC dissector for connection oriented calls.
4930 * We use transport type to later multiplex between what kind of
4931 * pinfo->private_data structure to expect.
4934 dissect_dcerpc_cn(tvbuff_t *tvb, int offset, packet_info *pinfo,
4935 proto_tree *tree, gboolean can_desegment, int *pkt_len)
4937 static const guint8 nulls[4] = { 0 };
4941 proto_item *ti = NULL;
4942 proto_item *tf = NULL;
4943 proto_tree *dcerpc_tree = NULL;
4944 proto_tree *cn_flags_tree = NULL;
4945 e_dce_cn_common_hdr_t hdr;
4946 dcerpc_auth_info auth_info;
4947 tvbuff_t *fragment_tvb;
4948 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
4951 * when done over nbt, dcerpc requests are padded with 4 bytes of null
4952 * data for some reason.
4954 * XXX - if that's always the case, the right way to do this would
4955 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
4956 * the 4 bytes of null padding, and make that the dissector
4957 * used for "netbios".
4959 if (tvb_memeql(tvb, offset, nulls, 4) == 0) {
4968 * Check if this looks like a C/O DCERPC call
4970 if (!tvb_bytes_exist(tvb, offset, sizeof (hdr))) {
4971 return FALSE; /* not enough information to check */
4973 start_offset = offset;
4974 hdr.rpc_ver = tvb_get_guint8(tvb, offset++);
4975 if (hdr.rpc_ver != 5)
4977 hdr.rpc_ver_minor = tvb_get_guint8(tvb, offset++);
4978 if ((hdr.rpc_ver_minor != 0) && (hdr.rpc_ver_minor != 1))
4980 hdr.ptype = tvb_get_guint8(tvb, offset++);
4981 if (hdr.ptype > PDU_RTS)
4984 hdr.flags = tvb_get_guint8(tvb, offset++);
4985 tvb_memcpy(tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
4986 offset += (int)sizeof (hdr.drep);
4988 hdr.frag_len = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
4990 hdr.auth_len = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
4992 hdr.call_id = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
4995 if (decode_data->dcectxid == 0) {
4996 col_append_fstr(pinfo->cinfo, COL_DCE_CALL, "%u", hdr.call_id);
4998 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
4999 * prepend a delimiter */
5000 col_append_fstr(pinfo->cinfo, COL_DCE_CALL, "#%u", hdr.call_id);
5003 if (can_desegment && pinfo->can_desegment
5004 && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
5005 pinfo->desegment_offset = start_offset;
5006 pinfo->desegment_len = hdr.frag_len - tvb_length_remaining(tvb, start_offset);
5007 *pkt_len = 0; /* desegmentation required */
5011 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCERPC");
5013 if (decode_data->dcectxid != 0) {
5014 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
5015 * append a delimiter and set a column fence */
5016 col_append_str(pinfo->cinfo, COL_INFO, " # ");
5017 col_set_fence(pinfo->cinfo,COL_INFO);
5019 col_add_fstr(pinfo->cinfo, COL_INFO, "%s: call_id: %u",
5020 pckt_vals[hdr.ptype].strptr, hdr.call_id);
5022 if (decode_data->dcectxid != 0) {
5023 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU */
5024 expert_add_info(pinfo, NULL, &ei_dcerpc_fragment_multiple);
5027 offset = start_offset;
5028 tvb_ensure_bytes_exist(tvb, offset, 16);
5030 ti = proto_tree_add_item(tree, proto_dcerpc, tvb, offset, hdr.frag_len, ENC_NA);
5031 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
5034 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
5037 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset, 1, hdr.rpc_ver_minor);
5040 tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
5043 #if 0 /* XXX - too much "output noise", removed for now */
5044 if (hdr.ptype == PDU_BIND || hdr.ptype == PDU_ALTER ||
5045 hdr.ptype == PDU_BIND_ACK || hdr.ptype == PDU_ALTER_ACK)
5046 expert_add_info_format(pinfo, tf, &ei_dcerpc_context_change, "Context change: %s", val_to_str(hdr.ptype, pckt_vals, "(0x%x)"));
5048 if (hdr.ptype == PDU_BIND_NAK)
5049 expert_add_info(pinfo, tf, &ei_dcerpc_bind_not_acknowledged);
5052 proto_item_append_text(ti, " %s, Fragment: %s",
5053 val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"),
5054 fragment_type(hdr.flags));
5056 tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
5057 cn_flags_tree = proto_item_add_subtree(tf, ett_dcerpc_cn_flags);
5059 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
5060 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
5061 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
5062 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
5063 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
5064 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
5065 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
5066 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
5069 col_append_fstr(pinfo->cinfo, COL_INFO, ", Fragment: %s", fragment_type(hdr.flags));
5071 proto_tree_add_dcerpc_drep(dcerpc_tree, tvb, offset, hdr.drep, (int)sizeof (hdr.drep));
5072 offset += (int)sizeof (hdr.drep);
5074 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
5077 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
5080 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
5084 proto_item_append_text(ti, ", FragLen: %u, Call: %u", hdr.frag_len, hdr.call_id);
5088 * None of the stuff done above should throw an exception, because
5089 * we would have rejected this as "not DCE RPC" if we didn't have all
5090 * of it. (XXX - perhaps we should request reassembly if we have
5091 * enough of the header to consider it DCE RPC but not enough to
5092 * get the fragment length; in that case the stuff still wouldn't
5093 * throw an exception.)
5095 * The rest of the stuff might, so return the PDU length to our caller.
5096 * XXX - should we construct a tvbuff containing only the PDU and
5097 * use that? Or should we have separate "is this a DCE RPC PDU",
5098 * "how long is it", and "dissect it" routines - which might let us
5099 * do most of the work in "tcp_dissect_pdus()"?
5101 if (pkt_len != NULL)
5102 *pkt_len = hdr.frag_len + padding;
5104 /* The remaining bytes in the current tvb might contain multiple
5105 * DCE/RPC fragments, so create a new tvb subset for this fragment.
5106 * Only limit the end of the fragment, but not the offset start,
5107 * as the authentication function dissect_dcerpc_cn_auth() will fail
5108 * (and other functions might fail as well) computing the right start
5111 subtvb_len = MIN(hdr.frag_len, tvb_length(tvb));
5112 fragment_tvb = tvb_new_subset(tvb, start_offset,
5113 subtvb_len /* length */,
5114 hdr.frag_len /* reported_length */);
5117 * Packet type specific stuff is next.
5119 switch (hdr.ptype) {
5122 dissect_dcerpc_cn_bind(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
5127 dissect_dcerpc_cn_bind_ack(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
5132 * Nothing after the common header other than credentials.
5134 dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr, TRUE,
5139 dissect_dcerpc_cn_rqst(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, tree, &hdr);
5143 dissect_dcerpc_cn_resp(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, tree, &hdr);
5147 dissect_dcerpc_cn_fault(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
5151 dissect_dcerpc_cn_bind_nak(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
5157 * Nothing after the common header other than an authentication
5160 dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr, FALSE,
5166 * Nothing after the common header, not even an authentication
5171 dissect_dcerpc_cn_rts(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
5175 /* might as well dissect the auth info */
5176 dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr, FALSE,
5184 * DCERPC dissector for connection oriented calls over packet-oriented
5188 dissect_dcerpc_cn_pk(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5190 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
5193 * Only one PDU per transport packet, and only one transport
5196 decode_data->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
5197 if (!dissect_dcerpc_cn(tvb, 0, pinfo, tree, FALSE, NULL)) {
5199 * It wasn't a DCERPC PDU.
5211 * DCERPC dissector for connection oriented calls over byte-stream
5213 * we need to distinguish here between SMB and non-TCP (more in the future?)
5214 * to be able to know what kind of private_data structure to expect.
5217 dissect_dcerpc_cn_bs_body(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
5219 volatile int offset = 0;
5221 volatile int dcerpc_pdus = 0;
5222 volatile gboolean ret = FALSE;
5225 * There may be multiple PDUs per transport packet; keep
5228 while (tvb_reported_length_remaining(tvb, offset) != 0) {
5231 if (dissect_dcerpc_cn(tvb, offset, pinfo, tree,
5232 dcerpc_cn_desegment, &pdu_len)) {
5235 } CATCH_NONFATAL_ERRORS {
5237 * Somebody threw an exception that means that there
5238 * was a problem dissecting the payload; that means
5239 * that a dissector was found, so we don't need to
5240 * dissect the payload as data or update the protocol
5243 * Just show the exception and then continue dissecting
5246 show_exception(tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
5248 * Presumably it looked enough like a DCE RPC PDU that we
5249 * dissected enough of it to throw an exception.
5254 if (dcerpc_pdus == 0) {
5255 gboolean try_desegment = FALSE;
5256 if (dcerpc_cn_desegment && pinfo->can_desegment &&
5257 !tvb_bytes_exist(tvb, offset, sizeof(e_dce_cn_common_hdr_t))) {
5258 /* look for a previous occurrence of the DCE-RPC protocol */
5259 wmem_list_frame_t *cur;
5260 cur = wmem_list_frame_prev(wmem_list_tail(pinfo->layers));
5261 while (cur != NULL) {
5262 if (proto_dcerpc == (gint)GPOINTER_TO_UINT(wmem_list_frame_data(cur))) {
5263 try_desegment = TRUE;
5266 cur = wmem_list_frame_prev(cur);
5270 if (try_desegment) {
5271 /* It didn't look like DCE-RPC but we already had one DCE-RPC
5272 * layer in this packet and what we have is short. Assume that
5273 * it was just too short to tell and ask the TCP layer for more
5275 pinfo->desegment_offset = offset;
5276 pinfo->desegment_len = (guint32)(sizeof(e_dce_cn_common_hdr_t) - tvb_length_remaining(tvb, offset));
5278 /* Really not DCE-RPC */
5284 * Well, we've seen at least one DCERPC PDU.
5288 /* if we had more than one Req/Resp in this PDU change the protocol column */
5289 /* this will formerly contain the last interface name, which may not be the same for all Req/Resp */
5290 if (dcerpc_pdus >= 2)
5291 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "%u*DCERPC", dcerpc_pdus);
5295 * Desegmentation required - bail now, but give the user a hint that desegmentation might be done later.
5297 proto_tree_add_uint_format(tree, hf_dcerpc_cn_deseg_req, tvb, offset,
5299 tvb_reported_length_remaining(tvb, offset),
5300 "[DCE RPC: %u byte%s left, desegmentation might follow]",
5301 tvb_reported_length_remaining(tvb, offset),
5302 plurality(tvb_reported_length_remaining(tvb, offset), "", "s"));
5307 * Step to the next PDU.
5315 dissect_dcerpc_cn_bs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5317 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
5319 decode_data->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
5320 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
5324 dissect_dcerpc_cn_smbpipe(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5326 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
5328 decode_data->dcetransporttype = DCE_CN_TRANSPORT_SMBPIPE;
5329 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
5333 dissect_dcerpc_cn_smb2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5335 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
5337 decode_data->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
5338 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
5344 dissect_dcerpc_dg_auth(tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
5345 e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
5347 proto_item *ti = NULL;
5348 proto_tree *auth_tree = NULL;
5349 guint8 protection_level;
5352 * Initially set "*auth_level_p" to -1 to indicate that we haven't
5353 * yet seen any authentication level information.
5355 if (auth_level_p != NULL)
5359 * The authentication information is at the *end* of the PDU; in
5360 * request and response PDUs, the request and response stub data
5363 * If the full packet is here, and there's data past the end of the
5364 * packet body, then dissect the auth info.
5366 offset += hdr->frag_len;
5367 if (tvb_length_remaining(tvb, offset) > 0) {
5368 switch (hdr->auth_proto) {
5370 case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
5371 ti = proto_tree_add_text(dcerpc_tree, tvb, offset, -1, "Kerberos authentication verifier");
5372 auth_tree = proto_item_add_subtree(ti, ett_dcerpc_krb5_auth_verf);
5373 protection_level = tvb_get_guint8(tvb, offset);
5374 if (auth_level_p != NULL)
5375 *auth_level_p = protection_level;
5376 proto_tree_add_uint(auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
5378 proto_tree_add_item(auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, ENC_BIG_ENDIAN);
5380 if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
5381 offset += 6; /* 6 bytes of padding */
5383 offset += 2; /* 2 bytes of padding */
5384 proto_tree_add_item(auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, ENC_NA);
5389 proto_tree_add_text(dcerpc_tree, tvb, offset, -1, "Authentication verifier");
5396 dissect_dcerpc_dg_cancel_ack(tvbuff_t *tvb, int offset, packet_info *pinfo,
5397 proto_tree *dcerpc_tree,
5398 e_dce_dg_common_hdr_t *hdr)
5402 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5403 hdr->drep, hf_dcerpc_dg_cancel_vers,
5409 /* The only version we know about */
5410 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5411 hdr->drep, hf_dcerpc_dg_cancel_id,
5413 /*offset = */dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
5414 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
5421 dissect_dcerpc_dg_cancel(tvbuff_t *tvb, int offset, packet_info *pinfo,
5422 proto_tree *dcerpc_tree,
5423 e_dce_dg_common_hdr_t *hdr)
5427 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5428 hdr->drep, hf_dcerpc_dg_cancel_vers,
5434 /* The only version we know about */
5435 /*offset = */dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5436 hdr->drep, hf_dcerpc_dg_cancel_id,
5438 /* XXX - are NDR Booleans 32 bits? */
5440 /* XXX - the RPC reference in chapter: "the cancel PDU" doesn't mention
5441 the accepting_cancels field (it's only in the cancel_ack PDU)! */
5442 /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
5443 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
5450 dissect_dcerpc_dg_fack(tvbuff_t *tvb, int offset, packet_info *pinfo,
5451 proto_tree *dcerpc_tree,
5452 e_dce_dg_common_hdr_t *hdr)
5459 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
5460 hdr->drep, hf_dcerpc_dg_fack_vers,
5467 case 0: /* The only version documented in the DCE RPC 1.1 spec */
5468 case 1: /* This appears to be the same */
5469 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
5470 hdr->drep, hf_dcerpc_dg_fack_window_size,
5472 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5473 hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
5475 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5476 hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
5478 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
5479 hdr->drep, hf_dcerpc_dg_fack_serial_num,
5481 col_append_fstr(pinfo->cinfo, COL_INFO, " serial: %u",
5483 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
5484 hdr->drep, hf_dcerpc_dg_fack_selack_len,
5486 for (i = 0; i < selack_len; i++) {
5487 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5488 hdr->drep, hf_dcerpc_dg_fack_selack,
5497 dissect_dcerpc_dg_reject_fault(tvbuff_t *tvb, int offset, packet_info *pinfo,
5498 proto_tree *dcerpc_tree,
5499 e_dce_dg_common_hdr_t *hdr)
5503 /*offset = */dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5504 hdr->drep, hf_dcerpc_dg_status,
5507 col_append_fstr (pinfo->cinfo, COL_INFO,
5509 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
5513 dissect_dcerpc_dg_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
5514 proto_tree *dcerpc_tree, proto_tree *tree,
5515 e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
5517 int length, reported_length, stub_length;
5518 gboolean save_fragmented;
5519 fragment_head *fd_head;
5522 proto_item *parent_pi;
5524 col_append_fstr(pinfo->cinfo, COL_INFO, " opnum: %u len: %u",
5525 di->call_data->opnum, hdr->frag_len );
5527 length = tvb_length_remaining(tvb, offset);
5528 reported_length = tvb_reported_length_remaining(tvb, offset);
5529 stub_length = hdr->frag_len;
5530 if (length > stub_length)
5531 length = stub_length;
5532 if (reported_length > stub_length)
5533 reported_length = stub_length;
5535 save_fragmented = pinfo->fragmented;
5537 /* If we don't have reassembly enabled, or this packet contains
5538 the entire PDU, or if this is a short frame (or a frame
5539 not reassembled at a lower layer) that doesn't include all
5540 the data in the fragment, just call the handoff directly if
5541 this is the first fragment or the PDU isn't fragmented. */
5542 if ( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
5543 !tvb_bytes_exist(tvb, offset, stub_length) ) {
5544 if (hdr->frag_num == 0) {
5547 /* First fragment, possibly the only fragment */
5550 * XXX - authentication info?
5552 pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
5553 next_tvb = tvb_new_subset(tvb, offset, length,
5555 dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb,
5556 next_tvb, hdr->drep, di, NULL);
5558 /* PDU is fragmented and this isn't the first fragment */
5561 tvb_ensure_bytes_exist(tvb, offset, stub_length);
5562 proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
5563 "Fragment data (%d byte%s)",
5565 plurality(stub_length, "", "s"));
5570 /* Reassembly is enabled, the PDU is fragmented, and
5571 we have all the data in the fragment; the first two
5572 of those mean we should attempt reassembly, and the
5573 third means we can attempt reassembly. */
5576 tvb_ensure_bytes_exist(tvb, offset, stub_length);
5577 proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
5578 "Fragment data (%d byte%s)", stub_length,
5579 plurality(stub_length, "", "s"));
5583 fd_head = fragment_add_seq(&dcerpc_cl_reassembly_table,
5585 pinfo, hdr->seqnum, (void *)hdr,
5586 hdr->frag_num, stub_length,
5587 !(hdr->flags1 & PFCL1_LASTFRAG), 0);
5588 if (fd_head != NULL) {
5589 /* We completed reassembly... */
5590 if (pinfo->fd->num == fd_head->reassembled_in) {
5591 /* ...and this is the reassembled RPC PDU */
5592 next_tvb = tvb_new_chain(tvb, fd_head->tvb_data);
5593 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
5594 show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
5595 tree, pinfo, next_tvb, &pi);
5598 * XXX - authentication info?
5600 pinfo->fragmented = FALSE;
5601 dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb,
5602 next_tvb, hdr->drep, di, NULL);
5604 /* ...and this isn't the reassembled RPC PDU */
5605 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
5606 tvb, 0, 0, fd_head->reassembled_in);
5607 PROTO_ITEM_SET_GENERATED(pi);
5608 parent_pi = proto_tree_get_parent(dcerpc_tree);
5609 if (parent_pi != NULL) {
5610 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
5612 col_append_fstr(pinfo->cinfo, COL_INFO,
5613 " [DCE/RPC fragment, reas: #%u]", fd_head->reassembled_in);
5617 pinfo->fragmented = save_fragmented;
5621 dissect_dcerpc_dg_rqst(tvbuff_t *tvb, int offset, packet_info *pinfo,
5622 proto_tree *dcerpc_tree, proto_tree *tree,
5623 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
5626 dcerpc_call_value *value, v;
5627 dcerpc_matched_key matched_key, *new_matched_key;
5629 proto_item *parent_pi;
5632 if (!(pinfo->fd->flags.visited)) {
5633 dcerpc_call_value *call_value;
5634 dcerpc_dg_call_key *call_key;
5636 call_key = (dcerpc_dg_call_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_dg_call_key));
5637 call_key->conv = conv;
5638 call_key->seqnum = hdr->seqnum;
5639 call_key->act_id = hdr->act_id;
5641 call_value = (dcerpc_call_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_call_value));
5642 call_value->uuid = hdr->if_id;
5643 call_value->ver = hdr->if_ver;
5644 call_value->object_uuid = hdr->obj_id;
5645 call_value->opnum = hdr->opnum;
5646 call_value->req_frame = pinfo->fd->num;
5647 call_value->req_time = pinfo->fd->abs_ts;
5648 call_value->rep_frame = 0;
5649 call_value->max_ptr = 0;
5650 call_value->se_data = NULL;
5651 call_value->private_data = NULL;
5652 call_value->pol = NULL;
5653 /* NDR64 is not available on dg transports ?*/
5654 call_value->flags = 0;
5656 g_hash_table_insert(dcerpc_dg_calls, call_key, call_value);
5658 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof(dcerpc_matched_key));
5659 new_matched_key->frame = pinfo->fd->num;
5660 new_matched_key->call_id = hdr->seqnum;
5661 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
5664 matched_key.frame = pinfo->fd->num;
5665 matched_key.call_id = hdr->seqnum;
5666 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
5668 v.uuid = hdr->if_id;
5669 v.ver = hdr->if_ver;
5670 v.object_uuid = hdr->obj_id;
5671 v.opnum = hdr->opnum;
5672 v.req_frame = pinfo->fd->num;
5676 v.private_data = NULL;
5681 di->call_id = hdr->seqnum;
5683 di->ptype = PDU_REQ;
5684 di->call_data = value;
5686 if (value->rep_frame != 0) {
5687 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
5688 tvb, 0, 0, value->rep_frame);
5689 PROTO_ITEM_SET_GENERATED(pi);
5690 parent_pi = proto_tree_get_parent(dcerpc_tree);
5691 if (parent_pi != NULL) {
5692 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
5695 dissect_dcerpc_dg_stub(tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
5699 dissect_dcerpc_dg_resp(tvbuff_t *tvb, int offset, packet_info *pinfo,
5700 proto_tree *dcerpc_tree, proto_tree *tree,
5701 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
5704 dcerpc_call_value *value, v;
5705 dcerpc_matched_key matched_key, *new_matched_key;
5707 proto_item *parent_pi;
5710 if (!(pinfo->fd->flags.visited)) {
5711 dcerpc_call_value *call_value;
5712 dcerpc_dg_call_key call_key;
5714 call_key.conv = conv;
5715 call_key.seqnum = hdr->seqnum;
5716 call_key.act_id = hdr->act_id;
5718 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_dg_calls, &call_key))) {
5719 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
5720 new_matched_key->frame = pinfo->fd->num;
5721 new_matched_key->call_id = hdr->seqnum;
5722 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
5723 if (call_value->rep_frame == 0) {
5724 call_value->rep_frame = pinfo->fd->num;
5729 matched_key.frame = pinfo->fd->num;
5730 matched_key.call_id = hdr->seqnum;
5731 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
5733 v.uuid = hdr->if_id;
5734 v.ver = hdr->if_ver;
5735 v.object_uuid = hdr->obj_id;
5736 v.opnum = hdr->opnum;
5738 v.rep_frame = pinfo->fd->num;
5740 v.private_data = NULL;
5747 di->ptype = PDU_RESP;
5748 di->call_data = value;
5750 if (value->req_frame != 0) {
5752 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
5753 tvb, 0, 0, value->req_frame);
5754 PROTO_ITEM_SET_GENERATED(pi);
5755 parent_pi = proto_tree_get_parent(dcerpc_tree);
5756 if (parent_pi != NULL) {
5757 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
5759 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
5760 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
5761 PROTO_ITEM_SET_GENERATED(pi);
5763 proto_tree_add_expert(dcerpc_tree, pinfo, &ei_dcerpc_no_request_found, tvb, 0, 0);
5765 dissect_dcerpc_dg_stub(tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
5769 dissect_dcerpc_dg_ping_ack(tvbuff_t *tvb, int offset, packet_info *pinfo,
5770 proto_tree *dcerpc_tree,
5771 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
5773 proto_item *parent_pi;
5774 /* if (!(pinfo->fd->flags.visited)) {*/
5775 dcerpc_call_value *call_value;
5776 dcerpc_dg_call_key call_key;
5778 call_key.conv = conv;
5779 call_key.seqnum = hdr->seqnum;
5780 call_key.act_id = hdr->act_id;
5782 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_dg_calls, &call_key))) {
5786 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
5787 tvb, 0, 0, call_value->req_frame);
5788 PROTO_ITEM_SET_GENERATED(pi);
5789 parent_pi = proto_tree_get_parent(dcerpc_tree);
5790 if (parent_pi != NULL) {
5791 proto_item_append_text(parent_pi, ", [Req: #%u]", call_value->req_frame);
5794 col_append_fstr(pinfo->cinfo, COL_INFO, " [req: #%u]", call_value->req_frame);
5796 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &call_value->req_time);
5797 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
5798 PROTO_ITEM_SET_GENERATED(pi);
5804 * DCERPC dissector for connectionless calls
5807 dissect_dcerpc_dg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5809 proto_item *ti = NULL;
5810 proto_item *tf = NULL;
5811 proto_tree *dcerpc_tree = NULL;
5812 proto_tree *dg_flags1_tree = NULL;
5813 proto_tree *dg_flags2_tree = NULL;
5814 e_dce_dg_common_hdr_t hdr;
5816 conversation_t *conv;
5819 const char *uuid_name = NULL;
5822 * Check if this looks like a CL DCERPC call. All dg packets
5823 * have an 80 byte header on them. Which starts with
5824 * version (4), pkt_type.
5826 if (tvb_length(tvb) < sizeof (hdr)) {
5830 /* Version must be 4 */
5831 hdr.rpc_ver = tvb_get_guint8(tvb, offset++);
5832 if (hdr.rpc_ver != 4)
5835 /* Type must be <= 19 or it's not DCE/RPC */
5836 hdr.ptype = tvb_get_guint8(tvb, offset++);
5840 /* flags1 has bit 1 and 8 as reserved so if any of them are set, it is
5841 probably not a DCE/RPC packet
5843 hdr.flags1 = tvb_get_guint8(tvb, offset++);
5844 if (hdr.flags1&0x81)
5847 /* flags2 has all bits except bit 2 as reserved so if any of them are set
5848 it is probably not DCE/RPC.
5850 hdr.flags2 = tvb_get_guint8(tvb, offset++);
5851 if (hdr.flags2&0xfd)
5855 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCERPC");
5856 col_add_str(pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
5858 tvb_memcpy(tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
5859 offset += (int)sizeof (hdr.drep);
5860 hdr.serial_hi = tvb_get_guint8(tvb, offset++);
5861 dcerpc_tvb_get_uuid(tvb, offset, hdr.drep, &hdr.obj_id);
5863 dcerpc_tvb_get_uuid(tvb, offset, hdr.drep, &hdr.if_id);
5865 dcerpc_tvb_get_uuid(tvb, offset, hdr.drep, &hdr.act_id);
5867 hdr.server_boot = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
5869 hdr.if_ver = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
5871 hdr.seqnum = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
5873 hdr.opnum = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5875 hdr.ihint = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5877 hdr.ahint = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5879 hdr.frag_len = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5881 hdr.frag_num = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5883 hdr.auth_proto = tvb_get_guint8(tvb, offset++);
5884 hdr.serial_lo = tvb_get_guint8(tvb, offset++);
5887 ti = proto_tree_add_item(tree, proto_dcerpc, tvb, 0, -1, ENC_NA);
5889 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
5890 proto_item_append_text(ti, " %s, Seq: %u, Serial: %u, Frag: %u, FragLen: %u",
5891 val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"),
5892 hdr.seqnum, hdr.serial_hi*256+hdr.serial_lo,
5893 hdr.frag_num, hdr.frag_len);
5899 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
5903 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
5907 tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
5908 dg_flags1_tree = proto_item_add_subtree(tf, ett_dcerpc_dg_flags1);
5909 if (dg_flags1_tree) {
5910 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
5911 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
5912 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
5913 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
5914 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
5915 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
5916 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
5917 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
5919 proto_item_append_text(tf, " %s%s%s%s%s%s",
5920 (hdr.flags1 & PFCL1_BROADCAST) ? "\"Broadcast\" " : "",
5921 (hdr.flags1 & PFCL1_IDEMPOTENT) ? "\"Idempotent\" " : "",
5922 (hdr.flags1 & PFCL1_MAYBE) ? "\"Maybe\" " : "",
5923 (hdr.flags1 & PFCL1_NOFACK) ? "\"No Fack\" " : "",
5924 (hdr.flags1 & PFCL1_FRAG) ? "\"Fragment\" " : "",
5925 (hdr.flags1 & PFCL1_LASTFRAG) ? "\"Last Fragment\" " : "");
5932 tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
5933 dg_flags2_tree = proto_item_add_subtree(tf, ett_dcerpc_dg_flags2);
5934 if (dg_flags2_tree) {
5935 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
5936 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
5937 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
5938 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
5939 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
5940 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
5941 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
5942 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
5944 proto_item_append_text(tf, " %s",
5945 (hdr.flags2 & PFCL2_CANCEL_PENDING) ? "\"Cancel Pending\" " : "");
5952 proto_tree_add_dcerpc_drep(dcerpc_tree, tvb, offset, hdr.drep, (int)sizeof (hdr.drep));
5954 offset += (int)sizeof (hdr.drep);
5957 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
5961 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
5962 offset, 16, (e_guid_t *) &hdr.obj_id, "Object UUID: %s",
5963 guid_to_ep_str((e_guid_t *) &hdr.obj_id));
5968 uuid_str = guid_to_ep_str((e_guid_t*)&hdr.if_id);
5969 uuid_name = guids_get_uuid_name(&hdr.if_id);
5971 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
5972 offset, 16, (e_guid_t *) &hdr.if_id, "Interface: %s UUID: %s", uuid_name, uuid_str);
5974 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
5975 offset, 16, (e_guid_t *) &hdr.if_id, "Interface UUID: %s", uuid_str);
5981 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
5982 offset, 16, (e_guid_t *) &hdr.act_id, "Activity: %s",
5983 guid_to_ep_str((e_guid_t *) &hdr.act_id));
5988 nstime_t server_boot;
5990 server_boot.secs = hdr.server_boot;
5991 server_boot.nsecs = 0;
5993 if (hdr.server_boot == 0)
5994 proto_tree_add_time_format_value(dcerpc_tree, hf_dcerpc_dg_server_boot,
5995 tvb, offset, 4, &server_boot,
5998 proto_tree_add_time(dcerpc_tree, hf_dcerpc_dg_server_boot,
5999 tvb, offset, 4, &server_boot);
6004 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
6008 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
6009 col_append_fstr(pinfo->cinfo, COL_INFO, ": seq: %u", hdr.seqnum);
6010 col_append_fstr(pinfo->cinfo, COL_DCE_CALL, "%u", hdr.seqnum);
6014 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
6018 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
6022 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
6026 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
6030 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
6031 if (hdr.flags1 & PFCL1_FRAG) {
6032 /* Fragmented - put the fragment number into the Info column */
6033 col_append_fstr(pinfo->cinfo, COL_INFO, " frag: %u",
6039 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
6043 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
6044 if (hdr.flags1 & PFCL1_FRAG) {
6045 /* Fragmented - put the serial number into the Info column */
6046 col_append_fstr(pinfo->cinfo, COL_INFO, " serial: %u",
6047 (hdr.serial_hi << 8) | hdr.serial_lo);
6053 * XXX - for Kerberos, we get a protection level; if it's
6054 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
6057 dissect_dcerpc_dg_auth(tvb, offset, dcerpc_tree, &hdr,
6062 * keeping track of the conversation shouldn't really be necessary
6063 * for connectionless packets, because everything we need to know
6064 * to dissect is in the header for each packet. Unfortunately,
6065 * Microsoft's implementation is buggy and often puts the
6066 * completely wrong if_id in the header. go figure. So, keep
6067 * track of the seqnum and use that if possible. Note: that's not
6068 * completely correct. It should really be done based on both the
6069 * activity_id and seqnum. I haven't seen anywhere that it would
6070 * make a difference, but for future reference...
6072 conv = find_or_create_conversation(pinfo);
6075 * Packet type specific stuff is next.
6078 switch (hdr.ptype) {
6080 case PDU_CANCEL_ACK:
6081 /* Body is optional */
6082 /* XXX - we assume "frag_len" is the length of the body */
6083 if (hdr.frag_len != 0)
6084 dissect_dcerpc_dg_cancel_ack(tvb, offset, pinfo, dcerpc_tree, &hdr);
6089 * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
6090 * but in at least one capture none of the Cl_cancel PDUs had a
6093 /* XXX - we assume "frag_len" is the length of the body */
6094 if (hdr.frag_len != 0)
6095 dissect_dcerpc_dg_cancel(tvb, offset, pinfo, dcerpc_tree, &hdr);
6099 /* Body is optional; if present, it's the same as PDU_FACK */
6100 /* XXX - we assume "frag_len" is the length of the body */
6101 if (hdr.frag_len != 0)
6102 dissect_dcerpc_dg_fack(tvb, offset, pinfo, dcerpc_tree, &hdr);
6106 /* Body is optional */
6107 /* XXX - we assume "frag_len" is the length of the body */
6108 if (hdr.frag_len != 0)
6109 dissect_dcerpc_dg_fack(tvb, offset, pinfo, dcerpc_tree, &hdr);
6114 dissect_dcerpc_dg_reject_fault(tvb, offset, pinfo, dcerpc_tree, &hdr);
6118 dissect_dcerpc_dg_rqst(tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
6122 dissect_dcerpc_dg_resp(tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
6125 /* these requests have no body */
6128 dissect_dcerpc_dg_ping_ack(tvb, offset, pinfo, dcerpc_tree, &hdr, conv);
6139 dcerpc_init_protocol(void)
6141 /* structures and data for BIND */
6143 g_hash_table_destroy(dcerpc_binds);
6144 dcerpc_binds = NULL;
6146 if (!dcerpc_binds) {
6147 dcerpc_binds = g_hash_table_new(dcerpc_bind_hash, dcerpc_bind_equal);
6150 /* structures and data for CALL */
6151 if (dcerpc_cn_calls) {
6152 g_hash_table_destroy(dcerpc_cn_calls);
6154 dcerpc_cn_calls = g_hash_table_new(dcerpc_cn_call_hash, dcerpc_cn_call_equal);
6155 if (dcerpc_dg_calls) {
6156 g_hash_table_destroy(dcerpc_dg_calls);
6158 dcerpc_dg_calls = g_hash_table_new(dcerpc_dg_call_hash, dcerpc_dg_call_equal);
6160 /* structure and data for MATCHED */
6161 if (dcerpc_matched) {
6162 g_hash_table_destroy(dcerpc_matched);
6164 dcerpc_matched = g_hash_table_new(dcerpc_matched_hash, dcerpc_matched_equal);
6166 decode_dcerpc_inject_bindings();
6170 proto_register_dcerpc(void)
6172 static hf_register_info hf[] = {
6173 { &hf_dcerpc_request_in,
6174 { "Request in frame", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE,
6175 NULL, 0, "This packet is a response to the packet with this number", HFILL }},
6176 { &hf_dcerpc_response_in,
6177 { "Response in frame", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
6178 NULL, 0, "This packet will be responded in the packet with this number", HFILL }},
6179 { &hf_dcerpc_referent_id,
6180 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
6181 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
6183 { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6184 { &hf_dcerpc_ver_minor,
6185 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6186 { &hf_dcerpc_packet_type,
6187 { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS(pckt_vals), 0x0, NULL, HFILL }},
6188 { &hf_dcerpc_cn_flags,
6189 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6190 { &hf_dcerpc_cn_flags_first_frag,
6191 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_FIRST_FRAG, NULL, HFILL }},
6192 { &hf_dcerpc_cn_flags_last_frag,
6193 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_LAST_FRAG, NULL, HFILL }},
6194 { &hf_dcerpc_cn_flags_cancel_pending,
6195 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_PENDING_CANCEL, NULL, HFILL }},
6196 { &hf_dcerpc_cn_flags_reserved,
6197 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_RESERVED_1, NULL, HFILL }},
6198 { &hf_dcerpc_cn_flags_mpx,
6199 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_CONC_MPX, NULL, HFILL }},
6200 { &hf_dcerpc_cn_flags_dne,
6201 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_DID_NOT_EXECUTE, NULL, HFILL }},
6202 { &hf_dcerpc_cn_flags_maybe,
6203 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_MAYBE, NULL, HFILL }},
6204 { &hf_dcerpc_cn_flags_object,
6205 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_OBJECT_UUID, NULL, HFILL }},
6207 { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6208 { &hf_dcerpc_drep_byteorder,
6209 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS(drep_byteorder_vals), 0x0, NULL, HFILL }},
6210 { &hf_dcerpc_drep_character,
6211 { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS(drep_character_vals), 0x0, NULL, HFILL }},
6212 { &hf_dcerpc_drep_fp,
6213 { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS(drep_fp_vals), 0x0, NULL, HFILL }},
6214 { &hf_dcerpc_cn_frag_len,
6215 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6216 { &hf_dcerpc_cn_auth_len,
6217 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6218 { &hf_dcerpc_cn_call_id,
6219 { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6220 { &hf_dcerpc_cn_max_xmit,
6221 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6222 { &hf_dcerpc_cn_max_recv,
6223 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6224 { &hf_dcerpc_cn_assoc_group,
6225 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6226 { &hf_dcerpc_cn_num_ctx_items,
6227 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6228 { &hf_dcerpc_cn_ctx_item,
6229 { "Ctx Item", "dcerpc.cn_ctx_item", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6230 { &hf_dcerpc_cn_ctx_id,
6231 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6232 { &hf_dcerpc_cn_num_trans_items,
6233 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6234 { &hf_dcerpc_cn_bind_abstract_syntax,
6235 { "Abstract Syntax", "dcerpc.cn_bind_abstract_syntax", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6236 { &hf_dcerpc_cn_bind_if_id,
6237 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6238 { &hf_dcerpc_cn_bind_if_ver,
6239 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6240 { &hf_dcerpc_cn_bind_if_ver_minor,
6241 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6242 { &hf_dcerpc_cn_bind_trans_syntax,
6243 { "Transfer Syntax", "dcerpc.cn_bind_trans", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6244 { &hf_dcerpc_cn_bind_trans_id,
6245 { "ID", "dcerpc.cn_bind_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6246 { &hf_dcerpc_cn_bind_trans_ver,
6247 { "ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6248 { &hf_dcerpc_cn_bind_trans_btfn_01, /* [MS-RPCE] 2.2.2.14 */
6249 { "Security Context Multiplexing Supported", "dcerpc.cn_bind_trans_btfn.01", FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x01, NULL, HFILL }},
6250 { &hf_dcerpc_cn_bind_trans_btfn_02,
6251 { "Keep Connection On Orphan Supported", "dcerpc.cn_bind_trans_btfn.02", FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x02, NULL, HFILL }},
6252 { &hf_dcerpc_cn_alloc_hint,
6253 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6254 { &hf_dcerpc_cn_sec_addr_len,
6255 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6256 { &hf_dcerpc_cn_sec_addr,
6257 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6258 { &hf_dcerpc_cn_num_results,
6259 { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6260 { &hf_dcerpc_cn_ack_result,
6261 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, NULL, HFILL }},
6262 { &hf_dcerpc_cn_ack_reason,
6263 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, NULL, HFILL }},
6264 { &hf_dcerpc_cn_ack_trans_id,
6265 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6266 { &hf_dcerpc_cn_ack_trans_ver,
6267 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6268 { &hf_dcerpc_cn_ack_btfn,
6269 { "Bind Time Feature Negotiation Bitmask", "dcerpc.cn_ack_btfn", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6270 { &hf_dcerpc_cn_reject_reason,
6271 { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, NULL, HFILL }},
6272 { &hf_dcerpc_cn_num_protocols,
6273 { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6274 { &hf_dcerpc_cn_protocol_ver_major,
6275 { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6276 { &hf_dcerpc_cn_protocol_ver_minor,
6277 { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6278 { &hf_dcerpc_cn_cancel_count,
6279 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6280 { &hf_dcerpc_cn_status,
6281 { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, NULL, HFILL }},
6282 { &hf_dcerpc_cn_deseg_req,
6283 { "Desegmentation Required", "dcerpc.cn_deseg_req", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6284 { &hf_dcerpc_auth_type,
6285 { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS(authn_protocol_vals), 0x0, NULL, HFILL }},
6286 { &hf_dcerpc_auth_level,
6287 { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, NULL, HFILL }},
6288 { &hf_dcerpc_auth_pad_len,
6289 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6290 { &hf_dcerpc_auth_rsrvd,
6291 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6292 { &hf_dcerpc_auth_ctx_id,
6293 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6294 { &hf_dcerpc_dg_flags1,
6295 { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6296 { &hf_dcerpc_dg_flags1_rsrvd_01,
6297 { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_RESERVED_01, NULL, HFILL }},
6298 { &hf_dcerpc_dg_flags1_last_frag,
6299 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_LASTFRAG, NULL, HFILL }},
6300 { &hf_dcerpc_dg_flags1_frag,
6301 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_FRAG, NULL, HFILL }},
6302 { &hf_dcerpc_dg_flags1_nofack,
6303 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_NOFACK, NULL, HFILL }},
6304 { &hf_dcerpc_dg_flags1_maybe,
6305 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_MAYBE, NULL, HFILL }},
6306 { &hf_dcerpc_dg_flags1_idempotent,
6307 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_IDEMPOTENT, NULL, HFILL }},
6308 { &hf_dcerpc_dg_flags1_broadcast,
6309 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_BROADCAST, NULL, HFILL }},
6310 { &hf_dcerpc_dg_flags1_rsrvd_80,
6311 { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_RESERVED_80, NULL, HFILL }},
6312 { &hf_dcerpc_dg_flags2,
6313 { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6314 { &hf_dcerpc_dg_flags2_rsrvd_01,
6315 { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_01, NULL, HFILL }},
6316 { &hf_dcerpc_dg_flags2_cancel_pending,
6317 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_CANCEL_PENDING, NULL, HFILL }},
6318 { &hf_dcerpc_dg_flags2_rsrvd_04,
6319 { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_04, NULL, HFILL }},
6320 { &hf_dcerpc_dg_flags2_rsrvd_08,
6321 { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_08, NULL, HFILL }},
6322 { &hf_dcerpc_dg_flags2_rsrvd_10,
6323 { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_10, NULL, HFILL }},
6324 { &hf_dcerpc_dg_flags2_rsrvd_20,
6325 { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_20, NULL, HFILL }},
6326 { &hf_dcerpc_dg_flags2_rsrvd_40,
6327 { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_40, NULL, HFILL }},
6328 { &hf_dcerpc_dg_flags2_rsrvd_80,
6329 { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_80, NULL, HFILL }},
6330 { &hf_dcerpc_dg_serial_lo,
6331 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6332 { &hf_dcerpc_dg_serial_hi,
6333 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6334 { &hf_dcerpc_dg_ahint,
6335 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6336 { &hf_dcerpc_dg_ihint,
6337 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6338 { &hf_dcerpc_dg_frag_len,
6339 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6340 { &hf_dcerpc_dg_frag_num,
6341 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6342 { &hf_dcerpc_dg_auth_proto,
6343 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS(authn_protocol_vals), 0x0, NULL, HFILL }},
6344 { &hf_dcerpc_dg_seqnum,
6345 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6346 { &hf_dcerpc_dg_server_boot,
6347 { "Server boot time", "dcerpc.dg_server_boot", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0, NULL, HFILL }},
6348 { &hf_dcerpc_dg_if_ver,
6349 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6350 { &hf_dcerpc_krb5_av_prot_level,
6351 { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, NULL, HFILL }},
6352 { &hf_dcerpc_krb5_av_key_vers_num,
6353 { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6354 { &hf_dcerpc_krb5_av_key_auth_verifier,
6355 { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6356 { &hf_dcerpc_obj_id,
6357 { "Object", "dcerpc.obj_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6358 { &hf_dcerpc_dg_if_id,
6359 { "Interface", "dcerpc.dg_if_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6360 { &hf_dcerpc_dg_act_id,
6361 { "Activity", "dcerpc.dg_act_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6363 { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6365 { &hf_dcerpc_dg_cancel_vers,
6366 { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6368 { &hf_dcerpc_dg_cancel_id,
6369 { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6371 { &hf_dcerpc_dg_server_accepting_cancels,
6372 { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6374 { &hf_dcerpc_dg_fack_vers,
6375 { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6377 { &hf_dcerpc_dg_fack_window_size,
6378 { "Window Size", "dcerpc.fack_window_size", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6380 { &hf_dcerpc_dg_fack_max_tsdu,
6381 { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6383 { &hf_dcerpc_dg_fack_max_frag_size,
6384 { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6386 { &hf_dcerpc_dg_fack_serial_num,
6387 { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6389 { &hf_dcerpc_dg_fack_selack_len,
6390 { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6392 { &hf_dcerpc_dg_fack_selack,
6393 { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6395 { &hf_dcerpc_dg_status,
6396 { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, NULL, HFILL }},
6398 { &hf_dcerpc_array_max_count,
6399 { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
6401 { &hf_dcerpc_array_offset,
6402 { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
6404 { &hf_dcerpc_array_actual_count,
6405 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
6408 { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6410 { &hf_dcerpc_fragments,
6411 { "Reassembled DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
6412 NULL, 0x0, "DCE/RPC Fragments", HFILL }},
6414 { &hf_dcerpc_fragment,
6415 { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM, BASE_NONE,
6416 NULL, 0x0, NULL, HFILL }},
6418 { &hf_dcerpc_fragment_overlap,
6419 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE,
6420 NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
6422 { &hf_dcerpc_fragment_overlap_conflict,
6423 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE,
6424 NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
6426 { &hf_dcerpc_fragment_multiple_tails,
6427 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE,
6428 NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
6430 { &hf_dcerpc_fragment_too_long_fragment,
6431 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE,
6432 NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
6434 { &hf_dcerpc_fragment_error,
6435 { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE,
6436 NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
6438 { &hf_dcerpc_fragment_count,
6439 { "Fragment count", "dcerpc.fragment.count", FT_UINT32, BASE_DEC,
6440 NULL, 0x0, NULL, HFILL }},
6443 { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE,
6444 NULL, 0, "Time between Request and Response for DCE-RPC calls", HFILL }},
6446 { &hf_dcerpc_reassembled_in,
6447 { "Reassembled PDU in frame", "dcerpc.reassembled_in", FT_FRAMENUM, BASE_NONE,
6448 NULL, 0x0, "The DCE/RPC PDU is completely reassembled in the packet with this number", HFILL }},
6450 { &hf_dcerpc_reassembled_length,
6451 { "Reassembled DCE/RPC length", "dcerpc.reassembled.length", FT_UINT32, BASE_DEC,
6452 NULL, 0x0, "The total length of the reassembled payload", HFILL }},
6454 { &hf_dcerpc_unknown_if_id,
6455 { "Unknown DCERPC interface id", "dcerpc.unknown_if_id", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6457 { &hf_dcerpc_cn_rts_flags,
6458 { "RTS Flags", "dcerpc.cn_rts_flags", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6459 { &hf_dcerpc_cn_rts_flags_none,
6460 {"None", "dcerpc.cn_rts_flags.none", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_NONE, NULL, HFILL }},
6461 { &hf_dcerpc_cn_rts_flags_ping,
6462 { "Ping", "dcerpc.cn_rts.flags.ping", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_PING, NULL, HFILL }},
6463 { &hf_dcerpc_cn_rts_flags_other_cmd,
6464 { "Other Cmd", "dcerpc.cn_rts_flags.other_cmd", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_OTHER_CMD, NULL, HFILL }},
6465 { &hf_dcerpc_cn_rts_flags_recycle_channel,
6466 { "Recycle Channel", "dcerpc.cn_rts_flags.recycle_channel", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_RECYCLE_CHANNEL, NULL, HFILL }},
6467 { &hf_dcerpc_cn_rts_flags_in_channel,
6468 { "In Channel", "dcerpc.cn_rts_flags.in_channel", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_IN_CHANNEL, NULL, HFILL }},
6469 { &hf_dcerpc_cn_rts_flags_out_channel,
6470 { "Out Channel", "dcerpc.cn_rts_flags.out_channel", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_OUT_CHANNEL, NULL, HFILL }},
6471 { &hf_dcerpc_cn_rts_flags_eof,
6472 { "EOF", "dcerpc.cn_rts_flags.eof", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_EOF, NULL, HFILL }},
6473 { &hf_dcerpc_cn_rts_commands_nb,
6474 { "RTS Number of Commands", "dcerpc.cn_rts_commands_nb", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6475 { &hf_dcerpc_cn_rts_command,
6476 { "RTS Command", "dcerpc.cn_rts_command", FT_UINT32, BASE_HEX, VALS(rts_command_vals), 0x0, NULL, HFILL }},
6477 { &hf_dcerpc_cn_rts_command_receivewindowsize,
6478 {"Receive Window Size", "dcerpc.cn_rts_command.receivewindowsize", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6479 { &hf_dcerpc_cn_rts_command_fack_bytesreceived,
6480 {"Bytes Received", "dcerpc.cn_rts_command.fack.bytesreceived", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6481 { &hf_dcerpc_cn_rts_command_fack_availablewindow,
6482 {"Available Window", "dcerpc.cn_rts_command.fack.availablewindow", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6483 { &hf_dcerpc_cn_rts_command_fack_channelcookie,
6484 {"Channel Cookie", "dcerpc.cn_rts_command.fack.channelcookie", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6485 { &hf_dcerpc_cn_rts_command_connectiontimeout,
6486 {"Connection Timeout", "dcerpc.cn_rts_command.connectiontimeout", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6487 { &hf_dcerpc_cn_rts_command_cookie,
6488 {"Cookie", "dcerpc.cn_rts_command.cookie", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6489 { &hf_dcerpc_cn_rts_command_channellifetime,
6490 {"Channel Lifetime", "dcerpc.cn_rts_command.channellifetime", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6491 { &hf_dcerpc_cn_rts_command_clientkeepalive,
6492 {"Client Keepalive", "dcerpc.cn_rts_command.clientkeepalive", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6493 { &hf_dcerpc_cn_rts_command_version,
6494 {"Version", "dcerpc.cn_rts_command.version", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6495 { &hf_dcerpc_cn_rts_command_conformancecount,
6496 {"Conformance Count", "dcerpc.cn_rts_command.padding.conformancecount", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6497 { &hf_dcerpc_cn_rts_command_padding,
6498 { "Padding", "dcerpc.cn_rts_command.padding.padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
6499 { &hf_dcerpc_cn_rts_command_addrtype,
6500 { "Address Type", "dcerpc.cn_rts_command.addrtype", FT_UINT32, BASE_DEC, VALS(rts_addresstype_vals), 0x0, NULL, HFILL }},
6501 { &hf_dcerpc_cn_rts_command_associationgroupid,
6502 {"Association Group ID", "dcerpc.cn_rts_command.associationgroupid", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6503 { &hf_dcerpc_cn_rts_command_forwarddestination,
6504 {"Forward Destination", "dcerpc.cn_rts_command.forwarddestination", FT_UINT32, BASE_DEC, VALS(rts_forward_destination_vals), 0x0, NULL, HFILL }},
6505 { &hf_dcerpc_cn_rts_command_pingtrafficsentnotify,
6506 {"Ping Traffic Sent Notify", "dcerpc.cn_rts_command.pingtrafficsentnotify", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6507 { &hf_dcerpc_sec_vt_command_end,
6508 {"SEC_VT_COMMAND_END", "dcerpc.rpc_sec_vt.command.end", FT_BOOLEAN, 16, NULL, 0x4000, NULL, HFILL }},
6509 { &hf_dcerpc_sec_vt_command_must,
6510 {"SEC_VT_MUST_PROCESS_COMMAND", "dcerpc.rpc_sec_vt.command.must_process", FT_BOOLEAN, 16, NULL, 0x8000, NULL, HFILL }},
6511 { &hf_dcerpc_sec_vt_command_cmd,
6512 {"SEC_VT_COMMAND", "dcerpc.rpc_sec_vt.command.cmd", FT_UINT16, BASE_HEX, VALS(sec_vt_command_cmd_vals), 0x3fff, NULL, HFILL }},
6513 { &hf_dcerpc_sec_vt_command,
6514 {"Command", "dcerpc.rpc_sec_vt.command", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
6515 { &hf_dcerpc_sec_vt_command_length,
6516 {"Length", "dcerpc.rpc_sec_vt.command.length", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL}},
6517 { &hf_dcerpc_sec_vt_bitmask,
6518 {"rpc_sec_vt_bitmask", "dcerpc.rpc_sec_vt.bitmask", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
6519 { &hf_dcerpc_sec_vt_bitmask_sign,
6520 {"CLIENT_SUPPORT_HEADER_SIGNING", "dcerpc.rpc_sec_vt.bitmask.sign", FT_BOOLEAN, 32, NULL, 0x1, NULL, HFILL }},
6521 { &hf_dcerpc_sec_vt_pcontext_uuid,
6522 {"UUID", "dcerpc.rpc_sec_vt.pcontext.interface.uuid", FT_GUID, BASE_NONE, NULL, 0, NULL, HFILL }},
6523 { &hf_dcerpc_sec_vt_pcontext_ver,
6524 {"Version", "dcerpc.rpc_sec_vt.pcontext.interface.ver", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
6526 static gint *ett[] = {
6528 &ett_dcerpc_cn_flags,
6530 &ett_dcerpc_cn_iface,
6531 &ett_dcerpc_cn_trans_syntax,
6532 &ett_dcerpc_cn_trans_btfn,
6533 &ett_dcerpc_cn_rts_flags,
6534 &ett_dcerpc_cn_rts_command,
6535 &ett_dcerpc_cn_rts_pdu,
6537 &ett_dcerpc_dg_flags1,
6538 &ett_dcerpc_dg_flags2,
6539 &ett_dcerpc_pointer_data,
6541 &ett_dcerpc_fragments,
6542 &ett_dcerpc_fragment,
6543 &ett_dcerpc_krb5_auth_verf,
6544 &ett_dcerpc_verification_trailer,
6545 &ett_dcerpc_sec_vt_command,
6546 &ett_dcerpc_sec_vt_bitmask,
6547 &ett_dcerpc_sec_vt_pcontext,
6548 &ett_dcerpc_sec_vt_header,
6551 static ei_register_info ei[] = {
6552 { &ei_dcerpc_fragment, { "dcerpc.fragment", PI_REASSEMBLE, PI_CHAT, "%s fragment", EXPFILL }},
6553 { &ei_dcerpc_fragment_reassembled, { "dcerpc.fragment_reassembled", PI_REASSEMBLE, PI_CHAT, "%s fragment, reassembled", EXPFILL }},
6554 { &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 }},
6555 { &ei_dcerpc_no_request_found, { "dcerpc.no_request_found", PI_SEQUENCE, PI_NOTE, "No request to this DCE/RPC call found", EXPFILL }},
6556 { &ei_dcerpc_cn_status, { "dcerpc.cn_status.expert", PI_RESPONSE_CODE, PI_NOTE, "Fault: %s", EXPFILL }},
6557 { &ei_dcerpc_fragment_multiple, { "dcerpc.fragment_multiple", PI_SEQUENCE, PI_CHAT, "Multiple DCE/RPC fragments/PDU's in one packet", EXPFILL }},
6558 { &ei_dcerpc_context_change, { "dcerpc.context_change", PI_SEQUENCE, PI_CHAT, "Context change: %s", EXPFILL }},
6559 { &ei_dcerpc_bind_not_acknowledged, { "dcerpc.bind_not_acknowledged", PI_SEQUENCE, PI_WARN, "Bind not acknowledged", EXPFILL }},
6562 /* Decode As handling */
6563 static build_valid_func dcerpc_da_build_value[1] = {dcerpc_value};
6564 static decode_as_value_t dcerpc_da_values = {dcerpc_prompt, 1, dcerpc_da_build_value};
6565 static decode_as_t dcerpc_da = {"dcerpc", "DCE-RPC",
6566 /* XXX - DCE/RPC doesn't have a true (sub)dissector table, so
6567 provide a "fake" one to fit the Decode As algorithm */
6569 1, 0, &dcerpc_da_values, NULL, NULL,
6570 dcerpc_populate_list, decode_dcerpc_binding_reset, dcerpc_decode_as_change, dcerpc_decode_as_free};
6572 module_t *dcerpc_module;
6573 expert_module_t* expert_dcerpc;
6575 proto_dcerpc = proto_register_protocol("Distributed Computing Environment / Remote Procedure Call (DCE/RPC)", "DCERPC", "dcerpc");
6576 proto_register_field_array(proto_dcerpc, hf, array_length(hf));
6577 proto_register_subtree_array(ett, array_length(ett));
6578 expert_dcerpc = expert_register_protocol(proto_dcerpc);
6579 expert_register_field_array(expert_dcerpc, ei, array_length(ei));
6581 register_init_routine(dcerpc_init_protocol);
6582 dcerpc_module = prefs_register_protocol(proto_dcerpc, NULL);
6583 prefs_register_bool_preference(dcerpc_module,
6585 "Reassemble DCE/RPC messages spanning multiple TCP segments",
6586 "Whether the DCE/RPC dissector should reassemble messages"
6587 " spanning multiple TCP segments."
6588 " To use this option, you must also enable"
6589 " \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
6590 &dcerpc_cn_desegment);
6591 prefs_register_bool_preference(dcerpc_module,
6592 "reassemble_dcerpc",
6593 "Reassemble DCE/RPC fragments",
6594 "Whether the DCE/RPC dissector should reassemble fragmented DCE/RPC PDUs",
6595 &dcerpc_reassemble);
6596 register_init_routine(dcerpc_reassemble_init);
6597 dcerpc_uuids = g_hash_table_new(dcerpc_uuid_hash, dcerpc_uuid_equal);
6598 dcerpc_tap = register_tap("dcerpc");
6600 register_decode_as(&dcerpc_da);
6604 proto_reg_handoff_dcerpc(void)
6606 heur_dissector_add("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
6607 heur_dissector_add("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
6608 heur_dissector_add("udp", dissect_dcerpc_dg, proto_dcerpc);
6609 heur_dissector_add("smb_transact", dissect_dcerpc_cn_smbpipe, proto_dcerpc);
6610 heur_dissector_add("smb2_heur_subdissectors", dissect_dcerpc_cn_smb2, proto_dcerpc);
6611 heur_dissector_add("http", dissect_dcerpc_cn_bs, proto_dcerpc);
6612 dcerpc_smb_init(proto_dcerpc);
6614 guids_add_uuid(&uuid_data_repr_proto, "32bit NDR");
6615 guids_add_uuid(&uuid_ndr64, "64bit NDR");
6616 guids_add_uuid(&uuid_bind_time_feature_nego_00, "bind time feature negotiation");
6617 guids_add_uuid(&uuid_bind_time_feature_nego_01, "bind time feature negotiation");
6618 guids_add_uuid(&uuid_bind_time_feature_nego_02, "bind time feature negotiation");
6619 guids_add_uuid(&uuid_bind_time_feature_nego_03, "bind time feature negotiation");
6620 guids_add_uuid(&uuid_asyncemsmdb, "async MAPI");
6624 * Editor modelines - http://www.wireshark.org/tools/modelines.html
6629 * indent-tabs-mode: nil
6632 * vi: set shiftwidth=4 tabstop=8 expandtab:
6633 * :indentSize=4:tabSize=8:noTabs=true: