FIXUP: sec_vt_command bitmask
[wireshark-wip.git] / epan / dissectors / packet-dcerpc.c
blob4ebe29addd48c0ee63ccf109e365c6c41fd70c1b
1 /* packet-dcerpc.c
2 * Routines for DCERPC packet disassembly
3 * Copyright 2001, Todd Sabin <tas[AT]webspan.net>
4 * Copyright 2003, Tim Potter <tpot[AT]samba.org>
5 * Copyright 2010, Julien Kerihuel <j.kerihuel[AT]openchange.org>
7 * $Id$
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/
32 #include "config.h"
34 #include <string.h>
36 #include <glib.h>
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>
43 #include <epan/tap.h>
44 #include <epan/wmem/wmem.h>
45 #include <epan/expert.h>
46 #include <epan/strutil.h>
47 #include <epan/addr_resolv.h>
48 #include <epan/show_exception.h>
49 #include <epan/dissectors/packet-dcerpc.h>
50 #include <epan/dissectors/packet-dcerpc-nt.h>
52 static int dcerpc_tap = -1;
54 /* 32bit Network Data Representation, see DCE/RPC Appendix I */
55 static e_uuid_t uuid_data_repr_proto = { 0x8a885d04, 0x1ceb, 0x11c9,
56 { 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60 } };
58 /* 64bit Network Data Representation, introduced in Windows Server 2008 */
59 static e_uuid_t uuid_ndr64 = { 0x71710533, 0xbeba, 0x4937,
60 { 0x83, 0x19, 0xb5, 0xdb, 0xef, 0x9c, 0xcc, 0x36 } };
62 /* Bind Time Feature Negotiation, see [MS-RPCE] 3.3.1.5.3 */
63 static e_uuid_t uuid_bind_time_feature_nego_00 = { 0x6cb71c2c, 0x9812, 0x4540, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
64 static e_uuid_t uuid_bind_time_feature_nego_01 = { 0x6cb71c2c, 0x9812, 0x4540, { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
65 static e_uuid_t uuid_bind_time_feature_nego_02 = { 0x6cb71c2c, 0x9812, 0x4540, { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
66 static e_uuid_t uuid_bind_time_feature_nego_03 = { 0x6cb71c2c, 0x9812, 0x4540, { 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
68 /* see [MS-OXRPC] Appendix A: Full IDL, http://msdn.microsoft.com/en-us/library/ee217991%28v=exchg.80%29.aspx */
69 static e_uuid_t uuid_asyncemsmdb = { 0x5261574a, 0x4572, 0x206e,
70 { 0xb2, 0x68, 0x6b, 0x19, 0x92, 0x13, 0xb4, 0xe4 } };
72 static const value_string pckt_vals[] = {
73 { PDU_REQ, "Request"},
74 { PDU_PING, "Ping"},
75 { PDU_RESP, "Response"},
76 { PDU_FAULT, "Fault"},
77 { PDU_WORKING, "Working"},
78 { PDU_NOCALL, "Nocall"},
79 { PDU_REJECT, "Reject"},
80 { PDU_ACK, "Ack"},
81 { PDU_CL_CANCEL, "Cl_cancel"},
82 { PDU_FACK, "Fack"},
83 { PDU_CANCEL_ACK, "Cancel_ack"},
84 { PDU_BIND, "Bind"},
85 { PDU_BIND_ACK, "Bind_ack"},
86 { PDU_BIND_NAK, "Bind_nak"},
87 { PDU_ALTER, "Alter_context"},
88 { PDU_ALTER_ACK, "Alter_context_resp"},
89 { PDU_AUTH3, "AUTH3"},
90 { PDU_SHUTDOWN, "Shutdown"},
91 { PDU_CO_CANCEL, "Co_cancel"},
92 { PDU_ORPHANED, "Orphaned"},
93 { PDU_RTS, "RPC-over-HTTP RTS"},
94 { 0, NULL }
97 static const value_string drep_byteorder_vals[] = {
98 { 0, "Big-endian" },
99 { 1, "Little-endian" },
100 { 0, NULL }
103 static const value_string drep_character_vals[] = {
104 { 0, "ASCII" },
105 { 1, "EBCDIC" },
106 { 0, NULL }
109 #define DCE_RPC_DREP_FP_IEEE 0
110 #define DCE_RPC_DREP_FP_VAX 1
111 #define DCE_RPC_DREP_FP_CRAY 2
112 #define DCE_RPC_DREP_FP_IBM 3
114 static const value_string drep_fp_vals[] = {
115 { DCE_RPC_DREP_FP_IEEE, "IEEE" },
116 { DCE_RPC_DREP_FP_VAX, "VAX" },
117 { DCE_RPC_DREP_FP_CRAY, "Cray" },
118 { DCE_RPC_DREP_FP_IBM, "IBM" },
119 { 0, NULL }
123 * Authentication services.
125 static const value_string authn_protocol_vals[] = {
126 { DCE_C_RPC_AUTHN_PROTOCOL_NONE, "None" },
127 { DCE_C_RPC_AUTHN_PROTOCOL_KRB5, "Kerberos 5" },
128 { DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO, "SPNEGO" },
129 { DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP, "NTLMSSP" },
130 { DCE_C_RPC_AUTHN_PROTOCOL_GSS_SCHANNEL, "SCHANNEL SSP" },
131 { DCE_C_RPC_AUTHN_PROTOCOL_GSS_KERBEROS, "Kerberos SSP" },
132 { DCE_C_RPC_AUTHN_PROTOCOL_DPA,
133 "Distributed Password Authentication SSP"},
134 { DCE_C_RPC_AUTHN_PROTOCOL_MSN, "MSN SSP"},
135 { DCE_C_RPC_AUTHN_PROTOCOL_DIGEST, "Digest SSP"},
136 { DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN, "NETLOGON Secure Channel" },
137 { DCE_C_RPC_AUTHN_PROTOCOL_MQ, "MSMQ SSP"},
138 { 0, NULL }
142 * Protection levels.
144 static const value_string authn_level_vals[] = {
145 { DCE_C_AUTHN_LEVEL_NONE, "None" },
146 { DCE_C_AUTHN_LEVEL_CONNECT, "Connect" },
147 { DCE_C_AUTHN_LEVEL_CALL, "Call" },
148 { DCE_C_AUTHN_LEVEL_PKT, "Packet" },
149 { DCE_C_AUTHN_LEVEL_PKT_INTEGRITY, "Packet integrity" },
150 { DCE_C_AUTHN_LEVEL_PKT_PRIVACY, "Packet privacy" },
151 { 0, NULL }
155 * Flag bits in first flag field in connectionless PDU header.
157 #define PFCL1_RESERVED_01 0x01 /* Reserved for use by implementations */
158 #define PFCL1_LASTFRAG 0x02 /* If set, the PDU is the last
159 * fragment of a multi-PDU
160 * transmission */
161 #define PFCL1_FRAG 0x04 /* If set, the PDU is a fragment of
162 a multi-PDU transmission */
163 #define PFCL1_NOFACK 0x08 /* If set, the receiver is not
164 * requested to send a `fack' PDU
165 * for the fragment */
166 #define PFCL1_MAYBE 0x10 /* If set, the PDU is for a `maybe'
167 * request */
168 #define PFCL1_IDEMPOTENT 0x20 /* If set, the PDU is for an idempotent
169 * request */
170 #define PFCL1_BROADCAST 0x40 /* If set, the PDU is for a broadcast
171 * request */
172 #define PFCL1_RESERVED_80 0x80 /* Reserved for use by implementations */
175 * Flag bits in second flag field in connectionless PDU header.
177 #define PFCL2_RESERVED_01 0x01 /* Reserved for use by implementations */
178 #define PFCL2_CANCEL_PENDING 0x02 /* Cancel pending at the call end */
179 #define PFCL2_RESERVED_04 0x04 /* Reserved for future use */
180 #define PFCL2_RESERVED_08 0x08 /* Reserved for future use */
181 #define PFCL2_RESERVED_10 0x10 /* Reserved for future use */
182 #define PFCL2_RESERVED_20 0x20 /* Reserved for future use */
183 #define PFCL2_RESERVED_40 0x40 /* Reserved for future use */
184 #define PFCL2_RESERVED_80 0x80 /* Reserved for future use */
187 * Flag bits in connection-oriented PDU header.
189 #define PFC_FIRST_FRAG 0x01 /* First fragment */
190 #define PFC_LAST_FRAG 0x02 /* Last fragment */
191 #define PFC_PENDING_CANCEL 0x04 /* Cancel was pending at sender */
192 #define PFC_RESERVED_1 0x08
193 #define PFC_CONC_MPX 0x10 /* supports concurrent multiplexing
194 * of a single connection. */
195 #define PFC_DID_NOT_EXECUTE 0x20 /* only meaningful on `fault' packet;
196 * if true, guaranteed call did not
197 * execute. */
198 #define PFC_MAYBE 0x40 /* `maybe' call semantics requested */
199 #define PFC_OBJECT_UUID 0x80 /* if true, a non-nil object UUID
200 * was specified in the handle, and
201 * is present in the optional object
202 * field. If false, the object field
203 * is omitted. */
206 * Tests whether a connection-oriented PDU is fragmented; returns TRUE if
207 * it's not fragmented (i.e., this is both the first *and* last fragment),
208 * and FALSE otherwise.
210 #define PFC_NOT_FRAGMENTED(hdr) \
211 ((hdr->flags&(PFC_FIRST_FRAG|PFC_LAST_FRAG)) == (PFC_FIRST_FRAG|PFC_LAST_FRAG))
214 * Presentation context negotiation result.
216 static const value_string p_cont_result_vals[] = {
217 { 0, "Acceptance" },
218 { 1, "User rejection" },
219 { 2, "Provider rejection" },
220 { 3, "Negotiate ACK" }, /* [MS-RPCE] 2.2.2.4 */
221 { 0, NULL }
225 * Presentation context negotiation rejection reasons.
227 static const value_string p_provider_reason_vals[] = {
228 { 0, "Reason not specified" },
229 { 1, "Abstract syntax not supported" },
230 { 2, "Proposed transfer syntaxes not supported" },
231 { 3, "Local limit exceeded" },
232 { 0, NULL }
236 * Reject reasons.
238 #define REASON_NOT_SPECIFIED 0
239 #define TEMPORARY_CONGESTION 1
240 #define LOCAL_LIMIT_EXCEEDED 2
241 #define CALLED_PADDR_UNKNOWN 3 /* not used */
242 #define PROTOCOL_VERSION_NOT_SUPPORTED 4
243 #define DEFAULT_CONTEXT_NOT_SUPPORTED 5 /* not used */
244 #define USER_DATA_NOT_READABLE 6 /* not used */
245 #define NO_PSAP_AVAILABLE 7 /* not used */
246 #define AUTH_TYPE_NOT_RECOGNIZED 8 /* [MS-RPCE] 2.2.2.5 */
247 #define INVALID_CHECKSUM 9 /* [MS-RPCE] 2.2.2.5 */
249 static const value_string reject_reason_vals[] = {
250 { REASON_NOT_SPECIFIED, "Reason not specified" },
251 { TEMPORARY_CONGESTION, "Temporary congestion" },
252 { LOCAL_LIMIT_EXCEEDED, "Local limit exceeded" },
253 { CALLED_PADDR_UNKNOWN, "Called paddr unknown" },
254 { PROTOCOL_VERSION_NOT_SUPPORTED, "Protocol version not supported" },
255 { DEFAULT_CONTEXT_NOT_SUPPORTED, "Default context not supported" },
256 { USER_DATA_NOT_READABLE, "User data not readable" },
257 { NO_PSAP_AVAILABLE, "No PSAP available" },
258 { AUTH_TYPE_NOT_RECOGNIZED, "Authentication type not recognized" },
259 { INVALID_CHECKSUM, "Invalid checksum" },
260 { 0, NULL }
264 * Reject status codes.
266 static const value_string reject_status_vals[] = {
267 { 0, "Stub-defined exception" },
268 { 0x00000001, "nca_s_fault_other" },
269 { 0x00000005, "nca_s_fault_access_denied" },
270 { 0x000006f7, "nca_s_fault_ndr" },
271 { 0x000006d8, "nca_s_fault_cant_perform" },
272 { 0x1c000001, "nca_s_fault_int_div_by_zero" },
273 { 0x1c000002, "nca_s_fault_addr_error" },
274 { 0x1c000003, "nca_s_fault_fp_div_zero" },
275 { 0x1c000004, "nca_s_fault_fp_underflow" },
276 { 0x1c000005, "nca_s_fault_fp_overflow" },
277 { 0x1c000006, "nca_s_fault_invalid_tag" },
278 { 0x1c000007, "nca_s_fault_invalid_bound" },
279 { 0x1c000008, "nca_rpc_version_mismatch" },
280 { 0x1c000009, "nca_unspec_reject" },
281 { 0x1c00000a, "nca_s_bad_actid" },
282 { 0x1c00000b, "nca_who_are_you_failed" },
283 { 0x1c00000c, "nca_manager_not_entered" },
284 { 0x1c00000d, "nca_s_fault_cancel" },
285 { 0x1c00000e, "nca_s_fault_ill_inst" },
286 { 0x1c00000f, "nca_s_fault_fp_error" },
287 { 0x1c000010, "nca_s_fault_int_overflow" },
288 { 0x1c000014, "nca_s_fault_pipe_empty" },
289 { 0x1c000015, "nca_s_fault_pipe_closed" },
290 { 0x1c000016, "nca_s_fault_pipe_order" },
291 { 0x1c000017, "nca_s_fault_pipe_discipline" },
292 { 0x1c000018, "nca_s_fault_pipe_comm_error" },
293 { 0x1c000019, "nca_s_fault_pipe_memory" },
294 { 0x1c00001a, "nca_s_fault_context_mismatch" },
295 { 0x1c00001b, "nca_s_fault_remote_no_memory" },
296 { 0x1c00001c, "nca_invalid_pres_context_id" },
297 { 0x1c00001d, "nca_unsupported_authn_level" },
298 { 0x1c00001f, "nca_invalid_checksum" },
299 { 0x1c000020, "nca_invalid_crc" },
300 { 0x1c000021, "ncs_s_fault_user_defined" },
301 { 0x1c000022, "nca_s_fault_tx_open_failed" },
302 { 0x1c000023, "nca_s_fault_codeset_conv_error" },
303 { 0x1c000024, "nca_s_fault_object_not_found" },
304 { 0x1c000025, "nca_s_fault_no_client_stub" },
305 { 0x1c010002, "nca_op_rng_error" },
306 { 0x1c010003, "nca_unk_if"},
307 { 0x1c010006, "nca_wrong_boot_time" },
308 { 0x1c010009, "nca_s_you_crashed" },
309 { 0x1c01000b, "nca_proto_error" },
310 { 0x1c010013, "nca_out_args_too_big" },
311 { 0x1c010014, "nca_server_too_busy" },
312 { 0x1c010017, "nca_unsupported_type" },
313 /* MS Windows specific values
314 * see: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/system_error_codes__1700-3999_.asp
315 * and: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/seccrypto/security/common_hresult_values.asp
316 * and: http://www.megos.ch/support/doserrors.txt
318 * XXX - we might need a way to dynamically add entries here, as higher layer protocols use these values too,
319 * at least MS protocols (like DCOM) do it that way ... */
320 { 0x80004001, "E_NOTIMPL" },
321 { 0x80004003, "E_POINTER" },
322 { 0x80004004, "E_ABORT" },
323 { 0x8000FFFF, "E_UNEXPECTED" },
324 { 0x80010105, "RPC_E_SERVERFAULT" },
325 { 0x80010108, "RPC_E_DISCONNECTED" },
326 { 0x80010113, "RPC_E_INVALID_IPID" },
327 { 0x8001011F, "RPC_E_TIMEOUT" },
328 { 0x80020003, "DISP_E_MEMBERNOTFOUND" },
329 { 0x80020006, "DISP_E_UNKNOWNNAME" },
330 { 0x8002000E, "DISP_E_BADPARAMCOUNT" },
331 { 0x8004CB00, "CBA_E_MALFORMED" },
332 { 0x8004CB01, "CBA_E_UNKNOWNOBJECT" },
333 { 0x8004CB05, "CBA_E_INVALIDID" },
334 { 0x8004CB09, "CBA_E_INVALIDCOOKIE" },
335 { 0x8004CB0B, "CBA_E_QOSTYPEUNSUPPORTED" },
336 { 0x8004CB0C, "CBA_E_QOSVALUEUNSUPPORTED" },
337 { 0x8004CB0F, "CBA_E_NOTAPPLICABLE" },
338 { 0x8004CB12, "CBA_E_LIMITVIOLATION" },
339 { 0x8004CB13, "CBA_E_QOSTYPENOTAPPLICABLE" },
340 { 0x8004CB18, "CBA_E_OUTOFPARTNERACCOS" },
341 { 0x8004CB1C, "CBA_E_FLAGUNSUPPORTED" },
342 { 0x8004CB23, "CBA_E_FRAMECOUNTUNSUPPORTED" },
343 { 0x8004CB25, "CBA_E_MODECHANGE" },
344 { 0x8007000E, "E_OUTOFMEMORY" },
345 { 0x80070057, "E_INVALIDARG" },
346 { 0x800706d1, "RPC_S_PROCNUM_OUT_OF_RANGE" },
347 { 0x80070776, "OR_INVALID_OXID" },
348 { 0, NULL }
353 * RTS Flags
355 #define RTS_FLAG_NONE 0x0000
356 #define RTS_FLAG_PING 0x0001
357 #define RTS_FLAG_OTHER_CMD 0x0002
358 #define RTS_FLAG_RECYCLE_CHANNEL 0x0004
359 #define RTS_FLAG_IN_CHANNEL 0x0008
360 #define RTS_FLAG_OUT_CHANNEL 0x0010
361 #define RTS_FLAG_EOF 0x0020
362 #define RTS_FLAG_ECHO 0x0040
365 * RTS Commands
368 #define RTS_CMD_RECEIVEWINDOWSIZE 0x0
369 #define RTS_CMD_FLOWCONTROLACK 0x1
370 #define RTS_CMD_CONNECTIONTIMEOUT 0x2
371 #define RTS_CMD_COOKIE 0x3
372 #define RTS_CMD_CHANNELLIFETIME 0x4
373 #define RTS_CMD_CLIENTKEEPALIVE 0x5
374 #define RTS_CMD_VERSION 0x6
375 #define RTS_CMD_EMPTY 0x7
376 #define RTS_CMD_PADDING 0x8
377 #define RTS_CMD_NEGATIVEANCE 0x9
378 #define RTS_CMD_ANCE 0xA
379 #define RTS_CMD_CLIENTADDRESS 0xB
380 #define RTS_CMD_ASSOCIATIONGROUPID 0xC
381 #define RTS_CMD_DESTINATION 0xD
382 #define RTS_CMD_PINGTRAFFICSENTNOTIFY 0xE
384 static const value_string rts_command_vals[] = {
385 { RTS_CMD_RECEIVEWINDOWSIZE, "ReceiveWindowSize" },
386 { RTS_CMD_FLOWCONTROLACK, "FlowControlAck" },
387 { RTS_CMD_CONNECTIONTIMEOUT, "ConnectionTimeOut" },
388 { RTS_CMD_COOKIE, "Cookie" },
389 { RTS_CMD_CHANNELLIFETIME, "ChannelLifetime" },
390 { RTS_CMD_CLIENTKEEPALIVE, "ClientKeepalive" },
391 { RTS_CMD_VERSION, "Version" },
392 { RTS_CMD_EMPTY, "Empty" },
393 { RTS_CMD_PADDING, "Padding" },
394 { RTS_CMD_NEGATIVEANCE, "NegativeANCE" },
395 { RTS_CMD_ANCE, "ANCE" },
396 { RTS_CMD_CLIENTADDRESS, "ClientAddress" },
397 { RTS_CMD_ASSOCIATIONGROUPID, "AssociationGroupId" },
398 { RTS_CMD_DESTINATION, "Destination" },
399 { RTS_CMD_PINGTRAFFICSENTNOTIFY, "PingTrafficSentNotify" },
400 { 0x0, NULL }
404 * RTS client address type
406 #define RTS_IPV4 0
407 #define RTS_IPV6 1
409 static const value_string rts_addresstype_vals[] = {
410 { RTS_IPV4, "IPV4" },
411 { RTS_IPV6, "IPV6" },
412 { 0x0, NULL }
416 * RTS Forward destination
419 static const value_string rts_forward_destination_vals[] = {
420 { 0x0, "FDClient" },
421 { 0x1, "FDInProxy" },
422 { 0x2, "FDServer" },
423 { 0x3, "FDOutProxy" },
424 { 0x0, NULL }
427 /* we need to keep track of what transport were used, ie what handle we came
428 * in through so we know what kind of pinfo->dce_smb_fid was passed to us.
430 /* Value of -1 is reserved for "not DCE packet" in packet_info.dcetransporttype. */
431 #define DCE_TRANSPORT_UNKNOWN 0
432 #define DCE_CN_TRANSPORT_SMBPIPE 1
435 static int proto_dcerpc = -1;
437 /* field defines */
438 static int hf_dcerpc_request_in = -1;
439 static int hf_dcerpc_time = -1;
440 static int hf_dcerpc_response_in = -1;
441 static int hf_dcerpc_ver = -1;
442 static int hf_dcerpc_ver_minor = -1;
443 static int hf_dcerpc_packet_type = -1;
444 static int hf_dcerpc_cn_flags = -1;
445 static int hf_dcerpc_cn_flags_first_frag = -1;
446 static int hf_dcerpc_cn_flags_last_frag = -1;
447 static int hf_dcerpc_cn_flags_cancel_pending = -1;
448 static int hf_dcerpc_cn_flags_reserved = -1;
449 static int hf_dcerpc_cn_flags_mpx = -1;
450 static int hf_dcerpc_cn_flags_dne = -1;
451 static int hf_dcerpc_cn_flags_maybe = -1;
452 static int hf_dcerpc_cn_flags_object = -1;
453 static int hf_dcerpc_drep = -1;
454 int hf_dcerpc_drep_byteorder = -1;
455 static int hf_dcerpc_drep_character = -1;
456 static int hf_dcerpc_drep_fp = -1;
457 static int hf_dcerpc_cn_frag_len = -1;
458 static int hf_dcerpc_cn_auth_len = -1;
459 static int hf_dcerpc_cn_call_id = -1;
460 static int hf_dcerpc_cn_max_xmit = -1;
461 static int hf_dcerpc_cn_max_recv = -1;
462 static int hf_dcerpc_cn_assoc_group = -1;
463 static int hf_dcerpc_cn_num_ctx_items = -1;
464 static int hf_dcerpc_cn_ctx_item = -1;
465 static int hf_dcerpc_cn_ctx_id = -1;
466 static int hf_dcerpc_cn_num_trans_items = -1;
467 static int hf_dcerpc_cn_bind_abstract_syntax = -1;
468 static int hf_dcerpc_cn_bind_if_id = -1;
469 static int hf_dcerpc_cn_bind_if_ver = -1;
470 static int hf_dcerpc_cn_bind_if_ver_minor = -1;
471 static int hf_dcerpc_cn_bind_trans_syntax = -1;
472 static int hf_dcerpc_cn_bind_trans_id = -1;
473 static int hf_dcerpc_cn_bind_trans_ver = -1;
474 static int hf_dcerpc_cn_bind_trans_btfn_01 = -1;
475 static int hf_dcerpc_cn_bind_trans_btfn_02 = -1;
476 static int hf_dcerpc_cn_alloc_hint = -1;
477 static int hf_dcerpc_cn_sec_addr_len = -1;
478 static int hf_dcerpc_cn_sec_addr = -1;
479 static int hf_dcerpc_cn_num_results = -1;
480 static int hf_dcerpc_cn_ack_result = -1;
481 static int hf_dcerpc_cn_ack_reason = -1;
482 static int hf_dcerpc_cn_ack_trans_id = -1;
483 static int hf_dcerpc_cn_ack_trans_ver = -1;
484 static int hf_dcerpc_cn_ack_btfn = -1;
485 static int hf_dcerpc_cn_reject_reason = -1;
486 static int hf_dcerpc_cn_num_protocols = -1;
487 static int hf_dcerpc_cn_protocol_ver_major = -1;
488 static int hf_dcerpc_cn_protocol_ver_minor = -1;
489 static int hf_dcerpc_cn_cancel_count = -1;
490 static int hf_dcerpc_cn_status = -1;
491 static int hf_dcerpc_cn_deseg_req = -1;
492 static int hf_dcerpc_cn_rts_flags = -1;
493 static int hf_dcerpc_cn_rts_flags_none = -1;
494 static int hf_dcerpc_cn_rts_flags_ping = -1;
495 static int hf_dcerpc_cn_rts_flags_other_cmd = -1;
496 static int hf_dcerpc_cn_rts_flags_recycle_channel = -1;
497 static int hf_dcerpc_cn_rts_flags_in_channel = -1;
498 static int hf_dcerpc_cn_rts_flags_out_channel = -1;
499 static int hf_dcerpc_cn_rts_flags_eof = -1;
500 static int hf_dcerpc_cn_rts_commands_nb = -1;
501 static int hf_dcerpc_cn_rts_command = -1;
502 static int hf_dcerpc_cn_rts_command_receivewindowsize = -1;
503 static int hf_dcerpc_cn_rts_command_fack_bytesreceived = -1;
504 static int hf_dcerpc_cn_rts_command_fack_availablewindow = -1;
505 static int hf_dcerpc_cn_rts_command_fack_channelcookie = -1;
506 static int hf_dcerpc_cn_rts_command_connectiontimeout = -1;
507 static int hf_dcerpc_cn_rts_command_cookie = -1;
508 static int hf_dcerpc_cn_rts_command_channellifetime = -1;
509 static int hf_dcerpc_cn_rts_command_clientkeepalive = -1;
510 static int hf_dcerpc_cn_rts_command_version = -1;
511 static int hf_dcerpc_cn_rts_command_conformancecount = -1;
512 static int hf_dcerpc_cn_rts_command_padding = -1;
513 static int hf_dcerpc_cn_rts_command_addrtype = -1;
514 static int hf_dcerpc_cn_rts_command_associationgroupid = -1;
515 static int hf_dcerpc_cn_rts_command_forwarddestination = -1;
516 static int hf_dcerpc_cn_rts_command_pingtrafficsentnotify = -1;
517 static int hf_dcerpc_auth_type = -1;
518 static int hf_dcerpc_auth_level = -1;
519 static int hf_dcerpc_auth_pad_len = -1;
520 static int hf_dcerpc_auth_rsrvd = -1;
521 static int hf_dcerpc_auth_ctx_id = -1;
522 static int hf_dcerpc_dg_flags1 = -1;
523 static int hf_dcerpc_dg_flags1_rsrvd_01 = -1;
524 static int hf_dcerpc_dg_flags1_last_frag = -1;
525 static int hf_dcerpc_dg_flags1_frag = -1;
526 static int hf_dcerpc_dg_flags1_nofack = -1;
527 static int hf_dcerpc_dg_flags1_maybe = -1;
528 static int hf_dcerpc_dg_flags1_idempotent = -1;
529 static int hf_dcerpc_dg_flags1_broadcast = -1;
530 static int hf_dcerpc_dg_flags1_rsrvd_80 = -1;
531 static int hf_dcerpc_dg_flags2 = -1;
532 static int hf_dcerpc_dg_flags2_rsrvd_01 = -1;
533 static int hf_dcerpc_dg_flags2_cancel_pending = -1;
534 static int hf_dcerpc_dg_flags2_rsrvd_04 = -1;
535 static int hf_dcerpc_dg_flags2_rsrvd_08 = -1;
536 static int hf_dcerpc_dg_flags2_rsrvd_10 = -1;
537 static int hf_dcerpc_dg_flags2_rsrvd_20 = -1;
538 static int hf_dcerpc_dg_flags2_rsrvd_40 = -1;
539 static int hf_dcerpc_dg_flags2_rsrvd_80 = -1;
540 static int hf_dcerpc_dg_serial_hi = -1;
541 static int hf_dcerpc_obj_id = -1;
542 static int hf_dcerpc_dg_if_id = -1;
543 static int hf_dcerpc_dg_act_id = -1;
544 static int hf_dcerpc_dg_serial_lo = -1;
545 static int hf_dcerpc_dg_ahint = -1;
546 static int hf_dcerpc_dg_ihint = -1;
547 static int hf_dcerpc_dg_frag_len = -1;
548 static int hf_dcerpc_dg_frag_num = -1;
549 static int hf_dcerpc_dg_auth_proto = -1;
550 static int hf_dcerpc_opnum = -1;
551 static int hf_dcerpc_dg_seqnum = -1;
552 static int hf_dcerpc_dg_server_boot = -1;
553 static int hf_dcerpc_dg_if_ver = -1;
554 static int hf_dcerpc_krb5_av_prot_level = -1;
555 static int hf_dcerpc_krb5_av_key_vers_num = -1;
556 static int hf_dcerpc_krb5_av_key_auth_verifier = -1;
557 static int hf_dcerpc_dg_cancel_vers = -1;
558 static int hf_dcerpc_dg_cancel_id = -1;
559 static int hf_dcerpc_dg_server_accepting_cancels = -1;
560 static int hf_dcerpc_dg_fack_vers = -1;
561 static int hf_dcerpc_dg_fack_window_size = -1;
562 static int hf_dcerpc_dg_fack_max_tsdu = -1;
563 static int hf_dcerpc_dg_fack_max_frag_size = -1;
564 static int hf_dcerpc_dg_fack_serial_num = -1;
565 static int hf_dcerpc_dg_fack_selack_len = -1;
566 static int hf_dcerpc_dg_fack_selack = -1;
567 static int hf_dcerpc_dg_status = -1;
568 static int hf_dcerpc_array_max_count = -1;
569 static int hf_dcerpc_array_offset = -1;
570 static int hf_dcerpc_array_actual_count = -1;
571 static int hf_dcerpc_array_buffer = -1;
572 static int hf_dcerpc_op = -1;
573 static int hf_dcerpc_referent_id = -1;
574 static int hf_dcerpc_fragments = -1;
575 static int hf_dcerpc_fragment = -1;
576 static int hf_dcerpc_fragment_overlap = -1;
577 static int hf_dcerpc_fragment_overlap_conflict = -1;
578 static int hf_dcerpc_fragment_multiple_tails = -1;
579 static int hf_dcerpc_fragment_too_long_fragment = -1;
580 static int hf_dcerpc_fragment_error = -1;
581 static int hf_dcerpc_fragment_count = -1;
582 static int hf_dcerpc_reassembled_in = -1;
583 static int hf_dcerpc_reassembled_length = -1;
584 static int hf_dcerpc_unknown_if_id = -1;
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;
593 static const int* sec_vt_command_fields[] = {
594 &hf_dcerpc_sec_vt_command_cmd,
595 &hf_dcerpc_sec_vt_command_end,
596 &hf_dcerpc_sec_vt_command_must,
597 NULL
600 static const int* sec_vt_bitmask_fields[] = {
601 &hf_dcerpc_sec_vt_bitmask_sign,
602 NULL
605 static const value_string sec_vt_command_cmd_vals[] = {
606 {1, "BITMASK_1"},
607 {2, "PCONTEXT"},
608 {3, "HEADER2"},
609 {0, NULL}
613 static gint ett_dcerpc = -1;
614 static gint ett_dcerpc_cn_flags = -1;
615 static gint ett_dcerpc_cn_ctx = -1;
616 static gint ett_dcerpc_cn_iface = -1;
617 static gint ett_dcerpc_cn_trans_syntax = -1;
618 static gint ett_dcerpc_cn_trans_btfn = -1;
619 static gint ett_dcerpc_cn_rts_flags = -1;
620 static gint ett_dcerpc_cn_rts_command = -1;
621 static gint ett_dcerpc_cn_rts_pdu = -1;
622 static gint ett_dcerpc_drep = -1;
623 static gint ett_dcerpc_dg_flags1 = -1;
624 static gint ett_dcerpc_dg_flags2 = -1;
625 static gint ett_dcerpc_pointer_data = -1;
626 static gint ett_dcerpc_string = -1;
627 static gint ett_dcerpc_fragments = -1;
628 static gint ett_dcerpc_fragment = -1;
629 static gint ett_dcerpc_krb5_auth_verf = -1;
630 static gint ett_dcerpc_verification_trailer = -1;
631 static gint ett_dcerpc_sec_vt_command = -1;
632 static gint ett_dcerpc_sec_vt_bitmask = -1;
634 static expert_field ei_dcerpc_fragment_multiple = EI_INIT;
635 static expert_field ei_dcerpc_cn_status = EI_INIT;
636 static expert_field ei_dcerpc_fragment_reassembled = EI_INIT;
637 static expert_field ei_dcerpc_fragment = EI_INIT;
638 static expert_field ei_dcerpc_no_request_found = EI_INIT;
639 static expert_field ei_dcerpc_context_change = EI_INIT;
640 static expert_field ei_dcerpc_cn_ctx_id_no_bind = EI_INIT;
641 static expert_field ei_dcerpc_bind_not_acknowledged = EI_INIT;
643 static const fragment_items dcerpc_frag_items = {
644 &ett_dcerpc_fragments,
645 &ett_dcerpc_fragment,
647 &hf_dcerpc_fragments,
648 &hf_dcerpc_fragment,
649 &hf_dcerpc_fragment_overlap,
650 &hf_dcerpc_fragment_overlap_conflict,
651 &hf_dcerpc_fragment_multiple_tails,
652 &hf_dcerpc_fragment_too_long_fragment,
653 &hf_dcerpc_fragment_error,
654 &hf_dcerpc_fragment_count,
655 NULL,
656 &hf_dcerpc_reassembled_length,
657 /* Reassembled data field */
658 NULL,
659 "fragments"
662 /* list of hooks to be called when init_protocols is done */
663 GHookList dcerpc_hooks_init_protos;
665 static dcerpc_info *
666 get_next_di(void)
668 static dcerpc_info di[20];
669 static int di_counter = 0;
671 di_counter++;
672 if (di_counter >= 20) {
673 di_counter = 0;
676 memset(&di[di_counter], 0, sizeof(dcerpc_info));
678 return &di[di_counter];
681 /* try to desegment big DCE/RPC packets over TCP? */
682 static gboolean dcerpc_cn_desegment = TRUE;
684 /* reassemble DCE/RPC fragments */
685 /* reassembly of cl dcerpc fragments will not work for the case where ONE frame
686 might contain multiple dcerpc fragments for different PDUs.
687 this case would be so unusual/weird so if you got captures like that:
688 too bad
690 reassembly of co dcerpc fragments will not work for the case where TCP/SMB frames
691 are coming in out of sequence, but that will hurt in a lot of other places as well.
693 static gboolean dcerpc_reassemble = TRUE;
694 static reassembly_table dcerpc_co_reassembly_table;
695 static reassembly_table dcerpc_cl_reassembly_table;
697 typedef struct _dcerpc_fragment_key {
698 address src;
699 address dst;
700 guint32 id;
701 e_uuid_t act_id;
702 } dcerpc_fragment_key;
704 static guint
705 dcerpc_fragment_hash(gconstpointer k)
707 const dcerpc_fragment_key* key = (const dcerpc_fragment_key*) k;
708 guint hash_val;
710 hash_val = 0;
712 hash_val += key->id;
713 hash_val += key->act_id.Data1;
714 hash_val += key->act_id.Data2 << 16;
715 hash_val += key->act_id.Data3;
717 return hash_val;
720 static gint
721 dcerpc_fragment_equal(gconstpointer k1, gconstpointer k2)
723 const dcerpc_fragment_key* key1 = (const dcerpc_fragment_key*) k1;
724 const dcerpc_fragment_key* key2 = (const dcerpc_fragment_key*) k2;
726 /*key.id is the first item to compare since item is most
727 likely to differ between sessions, thus shortcircuiting
728 the comparison of addresses.
730 return (((key1->id == key2->id)
731 && (ADDRESSES_EQUAL(&key1->src, &key2->src))
732 && (ADDRESSES_EQUAL(&key1->dst, &key2->dst))
733 && (memcmp (&key1->act_id, &key2->act_id, sizeof (e_uuid_t)) == 0))
734 ? TRUE : FALSE);
737 /* allocate a persistent dcerpc fragment key to insert in the hash */
738 static void *
739 dcerpc_fragment_temporary_key(const packet_info *pinfo, const guint32 id,
740 const void *data)
742 dcerpc_fragment_key *key = g_slice_new(dcerpc_fragment_key);
743 e_dce_dg_common_hdr_t *hdr = (e_dce_dg_common_hdr_t *)data;
745 key->src = pinfo->src;
746 key->dst = pinfo->dst;
747 key->id = id;
748 key->act_id = hdr->act_id;
750 return key;
753 /* allocate a persistent dcerpc fragment key to insert in the hash */
754 static void *
755 dcerpc_fragment_persistent_key(const packet_info *pinfo, const guint32 id,
756 const void *data)
758 dcerpc_fragment_key *key = g_slice_new(dcerpc_fragment_key);
759 e_dce_dg_common_hdr_t *hdr = (e_dce_dg_common_hdr_t *)data;
761 COPY_ADDRESS(&key->src, &pinfo->src);
762 COPY_ADDRESS(&key->dst, &pinfo->dst);
763 key->id = id;
764 key->act_id = hdr->act_id;
766 return key;
769 static void
770 dcerpc_fragment_free_temporary_key(gpointer ptr)
772 dcerpc_fragment_key *key = (dcerpc_fragment_key *)ptr;
774 if(key)
775 g_slice_free(dcerpc_fragment_key, key);
778 static void
779 dcerpc_fragment_free_persistent_key(gpointer ptr)
781 dcerpc_fragment_key *key = (dcerpc_fragment_key *)ptr;
783 if(key){
785 * Free up the copies of the addresses from the old key.
787 g_free((gpointer)key->src.data);
788 g_free((gpointer)key->dst.data);
790 g_slice_free(dcerpc_fragment_key, key);
794 static const reassembly_table_functions dcerpc_cl_reassembly_table_functions = {
795 dcerpc_fragment_hash,
796 dcerpc_fragment_equal,
797 dcerpc_fragment_temporary_key,
798 dcerpc_fragment_persistent_key,
799 dcerpc_fragment_free_temporary_key,
800 dcerpc_fragment_free_persistent_key
803 static void
804 dcerpc_reassemble_init(void)
807 * XXX - addresses_ports_reassembly_table_functions?
808 * Or can a single connection-oriented DCE RPC session persist
809 * over multiple transport layer connections?
811 reassembly_table_init(&dcerpc_co_reassembly_table,
812 &addresses_reassembly_table_functions);
813 reassembly_table_init(&dcerpc_cl_reassembly_table,
814 &dcerpc_cl_reassembly_table_functions);
818 * Authentication subdissectors. Used to dissect authentication blobs in
819 * DCERPC binds, requests and responses.
822 typedef struct _dcerpc_auth_subdissector {
823 guint8 auth_level;
824 guint8 auth_type;
825 dcerpc_auth_subdissector_fns auth_fns;
826 } dcerpc_auth_subdissector;
828 static GSList *dcerpc_auth_subdissector_list;
830 static dcerpc_auth_subdissector_fns *get_auth_subdissector_fns(
831 guint8 auth_level, guint8 auth_type)
833 gpointer data;
834 int i;
836 for (i = 0; (data = g_slist_nth_data(dcerpc_auth_subdissector_list, i)); i++) {
837 dcerpc_auth_subdissector *asd = (dcerpc_auth_subdissector *)data;
839 if ((asd->auth_level == auth_level) &&
840 (asd->auth_type == auth_type))
841 return &asd->auth_fns;
844 return NULL;
847 void register_dcerpc_auth_subdissector(guint8 auth_level, guint8 auth_type,
848 dcerpc_auth_subdissector_fns *fns)
850 dcerpc_auth_subdissector *d;
852 if (get_auth_subdissector_fns(auth_level, auth_type))
853 return;
855 d = (dcerpc_auth_subdissector *)g_malloc(sizeof(dcerpc_auth_subdissector));
857 d->auth_level = auth_level;
858 d->auth_type = auth_type;
859 memcpy(&d->auth_fns, fns, sizeof(dcerpc_auth_subdissector_fns));
861 dcerpc_auth_subdissector_list = g_slist_append(dcerpc_auth_subdissector_list, d);
864 /* Hand off verifier data to a registered dissector */
866 static void dissect_auth_verf(tvbuff_t *auth_tvb, packet_info *pinfo,
867 proto_tree *tree,
868 dcerpc_auth_subdissector_fns *auth_fns,
869 e_dce_cn_common_hdr_t *hdr,
870 dcerpc_auth_info *auth_info)
872 dcerpc_dissect_fnct_t *volatile fn = NULL;
873 /* XXX - "stub" a fake DCERPC INFO STRUCTURE
874 If a dcerpc_info is really needed, update
875 the call stacks to include it
877 FAKE_DCERPC_INFO_STRUCTURE
879 switch (hdr->ptype) {
880 case PDU_BIND:
881 case PDU_ALTER:
882 fn = auth_fns->bind_fn;
883 break;
884 case PDU_BIND_ACK:
885 case PDU_ALTER_ACK:
886 fn = auth_fns->bind_ack_fn;
887 break;
888 case PDU_AUTH3:
889 fn = auth_fns->auth3_fn;
890 break;
891 case PDU_REQ:
892 fn = auth_fns->req_verf_fn;
893 break;
894 case PDU_RESP:
895 fn = auth_fns->resp_verf_fn;
896 break;
898 /* Don't know how to handle authentication data in this
899 pdu type. */
901 default:
902 g_warning("attempt to dissect %s pdu authentication data",
903 val_to_str(hdr->ptype, pckt_vals, "Unknown (%u)"));
904 break;
907 if (fn)
908 fn(auth_tvb, 0, pinfo, tree, &di, hdr->drep);
909 else {
910 tvb_ensure_bytes_exist(auth_tvb, 0, hdr->auth_len);
911 proto_tree_add_text(tree, auth_tvb, 0, hdr->auth_len,
912 "%s Verifier",
913 val_to_str(auth_info->auth_type,
914 authn_protocol_vals,
915 "Unknown (%u)"));
919 /* Hand off payload data to a registered dissector */
921 static tvbuff_t *decode_encrypted_data(tvbuff_t *data_tvb,
922 tvbuff_t *auth_tvb,
923 packet_info *pinfo,
924 dcerpc_auth_subdissector_fns *auth_fns,
925 gboolean is_request,
926 dcerpc_auth_info *auth_info)
928 dcerpc_decode_data_fnct_t *fn;
930 if (is_request)
931 fn = auth_fns->req_data_fn;
932 else
933 fn = auth_fns->resp_data_fn;
935 if (fn)
936 return fn(data_tvb, auth_tvb, 0, pinfo, auth_info);
938 return NULL;
942 * Subdissectors
945 /* the registered subdissectors */
946 GHashTable *dcerpc_uuids = NULL;
948 static gint
949 dcerpc_uuid_equal(gconstpointer k1, gconstpointer k2)
951 const dcerpc_uuid_key *key1 = (const dcerpc_uuid_key *)k1;
952 const dcerpc_uuid_key *key2 = (const dcerpc_uuid_key *)k2;
953 return ((memcmp(&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
954 && (key1->ver == key2->ver));
957 static guint
958 dcerpc_uuid_hash(gconstpointer k)
960 const dcerpc_uuid_key *key = (const dcerpc_uuid_key *)k;
961 /* This isn't perfect, but the Data1 part of these is almost always
962 unique. */
963 return key->uuid.Data1;
966 void
967 dcerpc_init_uuid(int proto, int ett, e_uuid_t *uuid, guint16 ver,
968 dcerpc_sub_dissector *procs, int opnum_hf)
970 dcerpc_uuid_key *key = (dcerpc_uuid_key *)g_malloc(sizeof (*key));
971 dcerpc_uuid_value *value = (dcerpc_uuid_value *)g_malloc(sizeof (*value));
972 header_field_info *hf_info;
973 module_t *samr_module;
974 const char *filter_name = proto_get_protocol_filter_name(proto);
976 key->uuid = *uuid;
977 key->ver = ver;
979 value->proto = find_protocol_by_id(proto);
980 value->proto_id = proto;
981 value->ett = ett;
982 value->name = proto_get_protocol_short_name(value->proto);
983 value->procs = procs;
984 value->opnum_hf = opnum_hf;
986 g_hash_table_insert(dcerpc_uuids, key, value);
988 hf_info = proto_registrar_get_nth(opnum_hf);
989 hf_info->strings = value_string_from_subdissectors(procs);
991 /* add this GUID to the global name resolving */
992 guids_add_uuid(uuid, proto_get_protocol_short_name(value->proto));
994 /* Register the samr.nt_password preference as obsolete */
995 /* This should be in packet-dcerpc-samr.c */
996 if (strcmp(filter_name, "samr") == 0) {
997 samr_module = prefs_register_protocol(proto, NULL);
998 prefs_register_obsolete_preference(samr_module, "nt_password");
1002 /* Function to find the name of a registered protocol
1003 * or NULL if the protocol/version is not known to wireshark.
1005 const char *
1006 dcerpc_get_proto_name(e_uuid_t *uuid, guint16 ver)
1008 dcerpc_uuid_key key;
1009 dcerpc_uuid_value *sub_proto;
1011 key.uuid = *uuid;
1012 key.ver = ver;
1013 if (!(sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key))) {
1014 return NULL;
1016 return sub_proto->name;
1019 /* Function to find the opnum hf-field of a registered protocol
1020 * or -1 if the protocol/version is not known to wireshark.
1023 dcerpc_get_proto_hf_opnum(e_uuid_t *uuid, guint16 ver)
1025 dcerpc_uuid_key key;
1026 dcerpc_uuid_value *sub_proto;
1028 key.uuid = *uuid;
1029 key.ver = ver;
1030 if (!(sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key))) {
1031 return -1;
1033 return sub_proto->opnum_hf;
1036 /* Create a value_string consisting of DCERPC opnum and name from a
1037 subdissector array. */
1039 value_string *value_string_from_subdissectors(dcerpc_sub_dissector *sd)
1041 value_string *vs = NULL;
1042 int i;
1043 int num_sd = 0;
1045 again:
1046 for (i = 0; sd[i].name; i++) {
1047 if (vs) {
1048 vs[i].value = sd[i].num;
1049 vs[i].strptr = sd[i].name;
1050 } else
1051 num_sd++;
1054 if (!vs) {
1055 vs = (value_string *)wmem_alloc(wmem_epan_scope(), (num_sd + 1) * sizeof(value_string));
1056 goto again;
1059 vs[num_sd].value = 0;
1060 vs[num_sd].strptr = NULL;
1062 return vs;
1065 /* Function to find the subdissector table of a registered protocol
1066 * or NULL if the protocol/version is not known to wireshark.
1068 dcerpc_sub_dissector *
1069 dcerpc_get_proto_sub_dissector(e_uuid_t *uuid, guint16 ver)
1071 dcerpc_uuid_key key;
1072 dcerpc_uuid_value *sub_proto;
1074 key.uuid = *uuid;
1075 key.ver = ver;
1076 if (!(sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key))) {
1077 return NULL;
1079 return sub_proto->procs;
1084 * To keep track of ctx_id mappings.
1086 * Every time we see a bind call we update this table.
1087 * Note that we always specify a SMB FID. For non-SMB transports this
1088 * value is 0.
1090 static GHashTable *dcerpc_binds = NULL;
1092 typedef struct _dcerpc_bind_key {
1093 conversation_t *conv;
1094 guint16 ctx_id;
1095 guint16 smb_fid;
1096 } dcerpc_bind_key;
1098 typedef struct _dcerpc_bind_value {
1099 e_uuid_t uuid;
1100 guint16 ver;
1101 e_uuid_t transport;
1102 } dcerpc_bind_value;
1104 static gint
1105 dcerpc_bind_equal(gconstpointer k1, gconstpointer k2)
1107 const dcerpc_bind_key *key1 = (const dcerpc_bind_key *)k1;
1108 const dcerpc_bind_key *key2 = (const dcerpc_bind_key *)k2;
1109 return ((key1->conv == key2->conv)
1110 && (key1->ctx_id == key2->ctx_id)
1111 && (key1->smb_fid == key2->smb_fid));
1114 static guint
1115 dcerpc_bind_hash(gconstpointer k)
1117 const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
1118 guint hash;
1120 hash = GPOINTER_TO_UINT(key->conv) + key->ctx_id + key->smb_fid;
1121 return hash;
1126 * To keep track of callid mappings. Should really use some generic
1127 * conversation support instead.
1129 static GHashTable *dcerpc_cn_calls = NULL;
1130 static GHashTable *dcerpc_dg_calls = NULL;
1132 typedef struct _dcerpc_cn_call_key {
1133 conversation_t *conv;
1134 guint32 call_id;
1135 guint16 smb_fid;
1136 } dcerpc_cn_call_key;
1138 typedef struct _dcerpc_dg_call_key {
1139 conversation_t *conv;
1140 guint32 seqnum;
1141 e_uuid_t act_id ;
1142 } dcerpc_dg_call_key;
1145 static gint
1146 dcerpc_cn_call_equal(gconstpointer k1, gconstpointer k2)
1148 const dcerpc_cn_call_key *key1 = (const dcerpc_cn_call_key *)k1;
1149 const dcerpc_cn_call_key *key2 = (const dcerpc_cn_call_key *)k2;
1150 return ((key1->conv == key2->conv)
1151 && (key1->call_id == key2->call_id)
1152 && (key1->smb_fid == key2->smb_fid));
1155 static gint
1156 dcerpc_dg_call_equal(gconstpointer k1, gconstpointer k2)
1158 const dcerpc_dg_call_key *key1 = (const dcerpc_dg_call_key *)k1;
1159 const dcerpc_dg_call_key *key2 = (const dcerpc_dg_call_key *)k2;
1160 return ((key1->conv == key2->conv)
1161 && (key1->seqnum == key2->seqnum)
1162 && ((memcmp(&key1->act_id, &key2->act_id, sizeof (e_uuid_t)) == 0)));
1165 static guint
1166 dcerpc_cn_call_hash(gconstpointer k)
1168 const dcerpc_cn_call_key *key = (const dcerpc_cn_call_key *)k;
1169 return GPOINTER_TO_UINT(key->conv) + key->call_id + key->smb_fid;
1172 static guint
1173 dcerpc_dg_call_hash(gconstpointer k)
1175 const dcerpc_dg_call_key *key = (const dcerpc_dg_call_key *)k;
1176 return (GPOINTER_TO_UINT(key->conv) + key->seqnum + key->act_id.Data1
1177 + (key->act_id.Data2 << 16) + key->act_id.Data3
1178 + (key->act_id.Data4[0] << 24) + (key->act_id.Data4[1] << 16)
1179 + (key->act_id.Data4[2] << 8) + (key->act_id.Data4[3] << 0)
1180 + (key->act_id.Data4[4] << 24) + (key->act_id.Data4[5] << 16)
1181 + (key->act_id.Data4[6] << 8) + (key->act_id.Data4[7] << 0));
1184 /* to keep track of matched calls/responses
1185 this one uses the same value struct as calls, but the key is the frame id
1186 and call id; there can be more than one call in a frame.
1188 XXX - why not just use the same keys as are used for calls?
1191 static GHashTable *dcerpc_matched = NULL;
1193 typedef struct _dcerpc_matched_key {
1194 guint32 frame;
1195 guint32 call_id;
1196 } dcerpc_matched_key;
1198 static gint
1199 dcerpc_matched_equal(gconstpointer k1, gconstpointer k2)
1201 const dcerpc_matched_key *key1 = (const dcerpc_matched_key *)k1;
1202 const dcerpc_matched_key *key2 = (const dcerpc_matched_key *)k2;
1203 return ((key1->frame == key2->frame)
1204 && (key1->call_id == key2->call_id));
1207 static guint
1208 dcerpc_matched_hash(gconstpointer k)
1210 const dcerpc_matched_key *key = (const dcerpc_matched_key *)k;
1211 return key->frame;
1217 * Utility functions. Modeled after packet-rpc.c
1221 dissect_dcerpc_uint8(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1222 proto_tree *tree, guint8 *drep,
1223 int hfindex, guint8 *pdata)
1225 guint8 data;
1227 data = tvb_get_guint8(tvb, offset);
1228 if (tree) {
1229 proto_tree_add_item(tree, hfindex, tvb, offset, 1, DREP_ENC_INTEGER(drep));
1231 if (pdata)
1232 *pdata = data;
1233 return offset + 1;
1237 dissect_dcerpc_uint16(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1238 proto_tree *tree, guint8 *drep,
1239 int hfindex, guint16 *pdata)
1241 guint16 data;
1243 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1244 ? tvb_get_letohs(tvb, offset)
1245 : tvb_get_ntohs(tvb, offset));
1247 if (tree) {
1248 proto_tree_add_item(tree, hfindex, tvb, offset, 2, DREP_ENC_INTEGER(drep));
1250 if (pdata)
1251 *pdata = data;
1252 return offset + 2;
1256 dissect_dcerpc_uint32(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1257 proto_tree *tree, guint8 *drep,
1258 int hfindex, guint32 *pdata)
1260 guint32 data;
1262 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1263 ? tvb_get_letohl(tvb, offset)
1264 : tvb_get_ntohl(tvb, offset));
1266 if (tree) {
1267 proto_tree_add_item(tree, hfindex, tvb, offset, 4, DREP_ENC_INTEGER(drep));
1269 if (pdata)
1270 *pdata = data;
1271 return offset+4;
1274 /* handles 32 bit unix time_t */
1276 dissect_dcerpc_time_t(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1277 proto_tree *tree, guint8 *drep,
1278 int hfindex, guint32 *pdata)
1280 guint32 data;
1281 nstime_t tv;
1283 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1284 ? tvb_get_letohl(tvb, offset)
1285 : tvb_get_ntohl(tvb, offset));
1287 tv.secs = data;
1288 tv.nsecs = 0;
1289 if (tree) {
1290 if (data == 0xffffffff) {
1291 /* special case, no time specified */
1292 proto_tree_add_time_format_value(tree, hfindex, tvb, offset, 4, &tv, "No time specified");
1293 } else {
1294 proto_tree_add_time(tree, hfindex, tvb, offset, 4, &tv);
1297 if (pdata)
1298 *pdata = data;
1300 return offset+4;
1304 dissect_dcerpc_uint64(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1305 proto_tree *tree, guint8 *drep,
1306 int hfindex, guint64 *pdata)
1308 guint64 data;
1310 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1311 ? tvb_get_letoh64(tvb, offset)
1312 : tvb_get_ntoh64(tvb, offset));
1314 if (tree) {
1315 header_field_info *hfinfo;
1317 /* This might be a field that is either 32bit, in NDR or
1318 64 bits in NDR64. So we must be careful and call the right
1319 helper here
1321 hfinfo = proto_registrar_get_nth(hfindex);
1323 switch (hfinfo->type) {
1324 case FT_UINT64:
1325 proto_tree_add_uint64(tree, hfindex, tvb, offset, 8, data);
1326 break;
1327 case FT_INT64:
1328 proto_tree_add_int64(tree, hfindex, tvb, offset, 8, data);
1329 break;
1330 default:
1331 DISSECTOR_ASSERT(data <= G_MAXUINT32);
1332 proto_tree_add_uint(tree, hfindex, tvb, offset, 8, (guint32)data);
1335 if (pdata)
1336 *pdata = data;
1337 return offset+8;
1342 dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1343 proto_tree *tree, guint8 *drep,
1344 int hfindex, gfloat *pdata)
1346 gfloat data;
1349 switch (drep[1]) {
1350 case(DCE_RPC_DREP_FP_IEEE):
1351 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1352 ? tvb_get_letohieee_float(tvb, offset)
1353 : tvb_get_ntohieee_float(tvb, offset));
1354 if (tree) {
1355 proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
1357 break;
1358 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
1359 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1360 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
1361 default:
1362 /* ToBeDone: non IEEE floating formats */
1363 /* Set data to a negative infinity value */
1364 data = -G_MAXFLOAT;
1365 if (tree) {
1366 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep[1]);
1369 if (pdata)
1370 *pdata = data;
1371 return offset + 4;
1376 dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1377 proto_tree *tree, guint8 *drep,
1378 int hfindex, gdouble *pdata)
1380 gdouble data;
1383 switch (drep[1]) {
1384 case(DCE_RPC_DREP_FP_IEEE):
1385 data = ((drep[0] & DREP_LITTLE_ENDIAN)
1386 ? tvb_get_letohieee_double(tvb, offset)
1387 : tvb_get_ntohieee_double(tvb, offset));
1388 if (tree) {
1389 proto_tree_add_double(tree, hfindex, tvb, offset, 8, data);
1391 break;
1392 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
1393 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1394 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
1395 default:
1396 /* ToBeDone: non IEEE double formats */
1397 /* Set data to a negative infinity value */
1398 data = -G_MAXDOUBLE;
1399 if (tree) {
1400 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep[1]);
1403 if (pdata)
1404 *pdata = data;
1405 return offset + 8;
1410 dissect_dcerpc_uuid_t(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1411 proto_tree *tree, guint8 *drep,
1412 int hfindex, e_uuid_t *pdata)
1414 e_uuid_t uuid;
1417 if (drep[0] & DREP_LITTLE_ENDIAN) {
1418 tvb_get_letohguid(tvb, offset, (e_guid_t *) &uuid);
1419 } else {
1420 tvb_get_ntohguid(tvb, offset, (e_guid_t *) &uuid);
1422 if (tree) {
1423 proto_tree_add_guid(tree, hfindex, tvb, offset, 16, (e_guid_t *) &uuid);
1425 if (pdata) {
1426 *pdata = uuid;
1428 return offset + 16;
1433 * a couple simpler things
1435 guint16
1436 dcerpc_tvb_get_ntohs(tvbuff_t *tvb, gint offset, guint8 *drep)
1438 if (drep[0] & DREP_LITTLE_ENDIAN) {
1439 return tvb_get_letohs(tvb, offset);
1440 } else {
1441 return tvb_get_ntohs(tvb, offset);
1445 guint32
1446 dcerpc_tvb_get_ntohl(tvbuff_t *tvb, gint offset, guint8 *drep)
1448 if (drep[0] & DREP_LITTLE_ENDIAN) {
1449 return tvb_get_letohl(tvb, offset);
1450 } else {
1451 return tvb_get_ntohl(tvb, offset);
1455 void
1456 dcerpc_tvb_get_uuid(tvbuff_t *tvb, gint offset, guint8 *drep, e_uuid_t *uuid)
1458 if (drep[0] & DREP_LITTLE_ENDIAN) {
1459 tvb_get_letohguid(tvb, offset, (e_guid_t *) uuid);
1460 } else {
1461 tvb_get_ntohguid(tvb, offset, (e_guid_t *) uuid);
1466 /* NDR arrays */
1467 /* function to dissect a unidimensional conformant array */
1469 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1470 proto_tree *tree, dcerpc_info *di, guint8 *drep,
1471 dcerpc_dissect_fnct_t *fnct)
1473 guint32 i;
1474 int old_offset;
1475 int conformance_size = 4;
1477 if (di->call_data->flags & DCERPC_IS_NDR64) {
1478 conformance_size = 8;
1481 if (di->conformant_run) {
1482 guint64 val;
1484 /* conformant run, just dissect the max_count header */
1485 old_offset = offset;
1486 di->conformant_run = 0;
1487 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1488 hf_dcerpc_array_max_count, &val);
1489 di->array_max_count = (gint32)val;
1490 di->array_max_count_offset = offset-conformance_size;
1491 di->conformant_run = 1;
1492 di->conformant_eaten = offset-old_offset;
1493 } else {
1494 /* we don't remember where in the bytestream this field was */
1495 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, conformance_size, di->array_max_count);
1497 /* real run, dissect the elements */
1498 for(i=0; i<di->array_max_count; i++) {
1499 offset = (*fnct)(tvb, offset, pinfo, tree, di, drep);
1503 return offset;
1506 /* function to dissect a unidimensional conformant and varying array
1507 * depending on the dissection function passed as a parameter,
1508 * content of the array will be dissected as a block or byte by byte
1510 static int
1511 dissect_ndr_ucvarray_core(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1512 proto_tree *tree, dcerpc_info *di, guint8 *drep,
1513 dcerpc_dissect_fnct_t *fnct_bytes,
1514 dcerpc_dissect_fnct_blk_t *fnct_block)
1516 guint32 i;
1517 int old_offset;
1518 int conformance_size = 4;
1520 if (di->call_data->flags & DCERPC_IS_NDR64) {
1521 conformance_size = 8;
1524 if (di->conformant_run) {
1525 guint64 val;
1527 /* conformant run, just dissect the max_count header */
1528 old_offset = offset;
1529 di->conformant_run = 0;
1530 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1531 hf_dcerpc_array_max_count, &val);
1532 DISSECTOR_ASSERT(val <= G_MAXUINT32);
1533 di->array_max_count = (guint32)val;
1534 di->array_max_count_offset = offset-conformance_size;
1535 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1536 hf_dcerpc_array_offset, &val);
1537 DISSECTOR_ASSERT(val <= G_MAXUINT32);
1538 di->array_offset = (guint32)val;
1539 di->array_offset_offset = offset-conformance_size;
1540 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1541 hf_dcerpc_array_actual_count, &val);
1542 DISSECTOR_ASSERT(val <= G_MAXUINT32);
1543 di->array_actual_count = (guint32)val;
1544 di->array_actual_count_offset = offset-conformance_size;
1545 di->conformant_run = 1;
1546 di->conformant_eaten = offset-old_offset;
1547 } else {
1548 /* we don't remember where in the bytestream these fields were */
1549 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, conformance_size, di->array_max_count);
1550 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, conformance_size, di->array_offset);
1551 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, conformance_size, di->array_actual_count);
1553 /* real run, dissect the elements */
1554 if (fnct_block) {
1555 offset = (*fnct_block)(tvb, offset, di->array_actual_count, pinfo, tree, drep);
1556 } else {
1557 for(i=0 ;i<di->array_actual_count; i++) {
1558 old_offset = offset;
1559 offset = (*fnct_bytes)(tvb, offset, pinfo, tree, di, drep);
1560 if (offset <= old_offset)
1561 THROW(ReportedBoundsError);
1566 return offset;
1570 dissect_ndr_ucvarray_block(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1571 proto_tree *tree, dcerpc_info *di, guint8 *drep,
1572 dcerpc_dissect_fnct_blk_t *fnct)
1574 return dissect_ndr_ucvarray_core(tvb, offset, pinfo, tree, di, drep, NULL, fnct);
1578 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1579 proto_tree *tree, dcerpc_info *di, guint8 *drep,
1580 dcerpc_dissect_fnct_t *fnct)
1582 return dissect_ndr_ucvarray_core(tvb, offset, pinfo, tree, di, drep, fnct, NULL);
1584 /* function to dissect a unidimensional varying array */
1586 dissect_ndr_uvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1587 proto_tree *tree, dcerpc_info *di, guint8 *drep,
1588 dcerpc_dissect_fnct_t *fnct)
1590 guint32 i;
1591 int old_offset;
1592 int conformance_size = 4;
1594 if (di->call_data->flags & DCERPC_IS_NDR64) {
1595 conformance_size = 8;
1598 if (di->conformant_run) {
1599 guint64 val;
1601 /* conformant run, just dissect the max_count header */
1602 old_offset = offset;
1603 di->conformant_run = 0;
1604 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1605 hf_dcerpc_array_offset, &val);
1606 DISSECTOR_ASSERT(val <= G_MAXUINT32);
1607 di->array_offset = (guint32)val;
1608 di->array_offset_offset = offset-conformance_size;
1609 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1610 hf_dcerpc_array_actual_count, &val);
1611 DISSECTOR_ASSERT(val <= G_MAXUINT32);
1612 di->array_actual_count = (guint32)val;
1613 di->array_actual_count_offset = offset-conformance_size;
1614 di->conformant_run = 1;
1615 di->conformant_eaten = offset-old_offset;
1616 } else {
1617 /* we don't remember where in the bytestream these fields were */
1618 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, conformance_size, di->array_offset);
1619 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, conformance_size, di->array_actual_count);
1621 /* real run, dissect the elements */
1622 for(i=0; i<di->array_actual_count; i++) {
1623 offset = (*fnct)(tvb, offset, pinfo, tree, di, drep);
1627 return offset;
1630 /* Dissect an string of bytes. This corresponds to
1631 IDL of the form '[string] byte *foo'.
1633 It can also be used for a conformant varying array of bytes if
1634 the contents of the array should be shown as a big blob, rather
1635 than showing each byte as an individual element.
1637 XXX - which of those is really the IDL type for, for example,
1638 the encrypted data in some MAPI packets? (Microsoft hasn't
1639 released that IDL.)
1641 XXX - does this need to do all the conformant array stuff that
1642 "dissect_ndr_ucvarray()" does? These are presumably for strings
1643 that are conformant and varying - they're stored like conformant
1644 varying arrays of bytes. */
1646 dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo,
1647 proto_tree *tree, dcerpc_info *di, guint8 *drep)
1649 guint64 len;
1651 if (di->conformant_run) {
1652 /* just a run to handle conformant arrays, no scalars to dissect */
1653 return offset;
1656 /* NDR array header */
1658 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1659 hf_dcerpc_array_max_count, NULL);
1661 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1662 hf_dcerpc_array_offset, NULL);
1664 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
1665 hf_dcerpc_array_actual_count, &len);
1667 DISSECTOR_ASSERT(len <= G_MAXUINT32);
1668 if (tree && len) {
1669 tvb_ensure_bytes_exist(tvb, offset, (guint32)len);
1670 proto_tree_add_item(tree, hf_dcerpc_array_buffer,
1671 tvb, offset, (guint32)len, ENC_NA);
1674 offset += (guint32)len;
1676 return offset;
1679 /* For dissecting arrays that are to be interpreted as strings. */
1681 /* Dissect an NDR conformant varying string of elements.
1682 The length of each element is given by the 'size_is' parameter;
1683 the elements are assumed to be characters or wide characters.
1685 XXX - does this need to do all the conformant array stuff that
1686 "dissect_ndr_ucvarray()" does? */
1688 dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1689 proto_tree *tree, dcerpc_info *di, guint8 *drep, int size_is,
1690 int hfindex, gboolean add_subtree, char **data)
1692 proto_item *string_item;
1693 proto_tree *string_tree;
1694 guint64 len;
1695 guint32 buffer_len;
1696 char *s;
1697 header_field_info *hfinfo;
1699 if (di->conformant_run) {
1700 /* just a run to handle conformant arrays, no scalars to dissect */
1701 return offset;
1704 if (add_subtree) {
1705 string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1706 proto_registrar_get_name(hfindex));
1707 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1708 } else {
1709 string_item = NULL;
1710 string_tree = tree;
1713 /* NDR array header */
1715 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
1716 hf_dcerpc_array_max_count, NULL);
1718 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
1719 hf_dcerpc_array_offset, NULL);
1721 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
1722 hf_dcerpc_array_actual_count, &len);
1724 DISSECTOR_ASSERT(len <= G_MAXUINT32);
1725 buffer_len = size_is * (guint32)len;
1727 /* Adjust offset */
1728 if (!di->no_align && (offset % size_is))
1729 offset += size_is - (offset % size_is);
1731 if (size_is == sizeof(guint16)) {
1732 /* XXX - use drep to determine the byte order? */
1733 /* XXX - once we have an ENC_ value for UTF-16, just use
1734 proto_tree_add_item() with the appropriate ENC_ value? */
1735 /* XXX - should this ever be used with something that's *not*
1736 an FT_STRING? */
1737 s = tvb_get_unicode_string(wmem_packet_scope(), tvb, offset, buffer_len, ENC_LITTLE_ENDIAN);
1738 if (tree && buffer_len) {
1739 hfinfo = proto_registrar_get_nth(hfindex);
1740 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1741 if (hfinfo->type == FT_STRING) {
1742 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1743 buffer_len, s);
1744 } else {
1745 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1746 buffer_len, DREP_ENC_INTEGER(drep));
1750 } else {
1752 * "tvb_get_string()" throws an exception if the entire string
1753 * isn't in the tvbuff. If the length is bogus, this should
1754 * keep us from trying to allocate an immensely large buffer.
1755 * (It won't help if the length is *valid* but immensely large,
1756 * but that's another matter; in any case, that would happen only
1757 * if we had an immensely large tvbuff....)
1759 * XXX - if this is an octet string, does the byte order
1760 * matter? Will this ever be anything *other* than an
1761 * octet string? What if size_is is neither 1 nor 2?
1763 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1764 s = tvb_get_string(wmem_packet_scope(), tvb, offset, buffer_len);
1765 if (tree && buffer_len)
1766 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1767 buffer_len, DREP_ENC_INTEGER(drep));
1770 if (string_item != NULL)
1771 proto_item_append_text(string_item, ": %s", s);
1773 if (data)
1774 *data = s;
1776 offset += buffer_len;
1778 proto_item_set_end(string_item, tvb, offset);
1780 return offset;
1784 dissect_ndr_cstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1785 proto_tree *tree, dcerpc_info *di, guint8 *drep, int size_is,
1786 int hfindex, gboolean add_subtree, char **data)
1788 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep, size_is, hfindex, add_subtree, data);
1791 /* Dissect an conformant varying string of chars.
1792 This corresponds to IDL of the form '[string] char *foo'.
1794 XXX - at least according to the DCE RPC 1.1 spec, a string has
1795 a null terminator, which isn't necessary as a terminator for
1796 the transfer language (as there's a length), but is presumably
1797 there for the benefit of null-terminated-string languages
1798 such as C. Is this ever used for purely counted strings?
1799 (Not that it matters if it is.) */
1801 dissect_ndr_char_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1802 proto_tree *tree, dcerpc_info *di, guint8 *drep)
1804 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep,
1805 sizeof(guint8), di->hf_index,
1806 FALSE, NULL);
1809 /* Dissect a conformant varying string of wchars (wide characters).
1810 This corresponds to IDL of the form '[string] wchar *foo'
1812 XXX - at least according to the DCE RPC 1.1 spec, a string has
1813 a null terminator, which isn't necessary as a terminator for
1814 the transfer language (as there's a length), but is presumably
1815 there for the benefit of null-terminated-string languages
1816 such as C. Is this ever used for purely counted strings?
1817 (Not that it matters if it is.) */
1819 dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1820 proto_tree *tree, dcerpc_info *di, guint8 *drep)
1822 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep,
1823 sizeof(guint16), di->hf_index,
1824 FALSE, NULL);
1827 /* This function is aimed for PIDL usage and dissects a UNIQUE pointer to
1828 * unicode string.
1831 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)
1833 char *s = NULL;
1834 gint levels = CB_STR_ITEM_LEVELS(param);
1836 offset = dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep,
1837 chsize, hfindex,
1838 FALSE, &s);
1840 if (!di->conformant_run) {
1841 /* Append string to COL_INFO */
1842 if (param & PIDL_SET_COL_INFO) {
1843 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", s);
1845 /* Save string to dcv->private_data */
1846 if ((param & PIDL_STR_SAVE)
1847 && (!pinfo->fd->flags.visited)) {
1848 dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1849 dcv->private_data = wmem_strdup(wmem_file_scope(), s);
1851 /* Append string to upper-level proto_items */
1852 if ((levels > 0) && tree && s && s[0]) {
1853 proto_item_append_text(tree, ": %s", s);
1854 tree = tree->parent;
1855 levels--;
1856 if (levels > 0) {
1857 proto_item_append_text(tree, ": %s", s);
1858 tree = tree->parent;
1859 levels--;
1860 while (levels > 0) {
1861 proto_item_append_text(tree, " %s", s);
1862 tree = tree->parent;
1863 levels--;
1870 return offset;
1873 /* Dissect an NDR varying string of elements.
1874 The length of each element is given by the 'size_is' parameter;
1875 the elements are assumed to be characters or wide characters.
1878 dissect_ndr_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1879 proto_tree *tree, dcerpc_info *di, guint8 *drep, int size_is,
1880 int hfindex, gboolean add_subtree, char **data)
1882 proto_item *string_item;
1883 proto_tree *string_tree;
1884 guint64 len;
1885 guint32 buffer_len;
1886 char *s;
1887 header_field_info *hfinfo;
1889 if (di->conformant_run) {
1890 /* just a run to handle conformant arrays, no scalars to dissect */
1891 return offset;
1894 if (add_subtree) {
1895 string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1896 proto_registrar_get_name(hfindex));
1897 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1898 } else {
1899 string_item = NULL;
1900 string_tree = tree;
1903 /* NDR array header */
1904 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
1905 hf_dcerpc_array_offset, NULL);
1907 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
1908 hf_dcerpc_array_actual_count, &len);
1910 DISSECTOR_ASSERT(len <= G_MAXUINT32);
1911 buffer_len = size_is * (guint32)len;
1913 /* Adjust offset */
1914 if (!di->no_align && (offset % size_is))
1915 offset += size_is - (offset % size_is);
1917 if (size_is == sizeof(guint16)) {
1918 /* XXX - use drep to determine the byte order? */
1919 /* XXX - once we have an ENC_ value for UTF-16, just use
1920 proto_tree_add_item() with the appropriate ENC_ value? */
1921 /* XXX - should this ever be used with something that's *not*
1922 an FT_STRING? */
1923 s = tvb_get_unicode_string(wmem_packet_scope(), tvb, offset, buffer_len, ENC_LITTLE_ENDIAN);
1924 if (tree && buffer_len) {
1925 hfinfo = proto_registrar_get_nth(hfindex);
1926 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1927 if (hfinfo->type == FT_STRING) {
1928 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1929 buffer_len, s);
1930 } else {
1931 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1932 buffer_len, DREP_ENC_INTEGER(drep));
1936 } else {
1938 * "tvb_get_string()" throws an exception if the entire string
1939 * isn't in the tvbuff. If the length is bogus, this should
1940 * keep us from trying to allocate an immensely large buffer.
1941 * (It won't help if the length is *valid* but immensely large,
1942 * but that's another matter; in any case, that would happen only
1943 * if we had an immensely large tvbuff....)
1945 * XXX - if this is an octet string, does the byte order
1946 * matter? Will this ever be anything *other* than an
1947 * octet string? What if size_is is neither 1 nor 2?
1949 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1950 s = tvb_get_string(wmem_packet_scope(), tvb, offset, buffer_len);
1951 if (tree && buffer_len)
1952 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1953 buffer_len, DREP_ENC_INTEGER(drep));
1956 if (string_item != NULL)
1957 proto_item_append_text(string_item, ": %s", s);
1959 if (data)
1960 *data = s;
1962 offset += buffer_len;
1964 proto_item_set_end(string_item, tvb, offset);
1966 return offset;
1969 /* Dissect an varying string of chars.
1970 This corresponds to IDL of the form '[string] char *foo'.
1972 XXX - at least according to the DCE RPC 1.1 spec, a string has
1973 a null terminator, which isn't necessary as a terminator for
1974 the transfer language (as there's a length), but is presumably
1975 there for the benefit of null-terminated-string languages
1976 such as C. Is this ever used for purely counted strings?
1977 (Not that it matters if it is.) */
1979 dissect_ndr_char_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1980 proto_tree *tree, dcerpc_info *di, guint8 *drep)
1982 return dissect_ndr_vstring(tvb, offset, pinfo, tree, di, drep,
1983 sizeof(guint8), di->hf_index,
1984 FALSE, NULL);
1987 /* Dissect a varying string of wchars (wide characters).
1988 This corresponds to IDL of the form '[string] wchar *foo'
1990 XXX - at least according to the DCE RPC 1.1 spec, a string has
1991 a null terminator, which isn't necessary as a terminator for
1992 the transfer language (as there's a length), but is presumably
1993 there for the benefit of null-terminated-string languages
1994 such as C. Is this ever used for purely counted strings?
1995 (Not that it matters if it is.) */
1997 dissect_ndr_wchar_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1998 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2000 return dissect_ndr_vstring(tvb, offset, pinfo, tree, di, drep,
2001 sizeof(guint16), di->hf_index,
2002 FALSE, NULL);
2006 /* ndr pointer handling */
2007 /* list of pointers encountered so far */
2008 static GSList *ndr_pointer_list = NULL;
2010 /* position where in the list to insert newly encountered pointers */
2011 static int ndr_pointer_list_pos = 0;
2013 /* Boolean controlling whether pointers are top-level or embedded */
2014 static gboolean pointers_are_top_level = TRUE;
2016 /* as a kludge, we represent all embedded reference pointers as id == -1
2017 hoping that his will not collide with any non-ref pointers */
2018 typedef struct ndr_pointer_data {
2019 guint32 id;
2020 proto_item *item; /* proto_item for pointer */
2021 proto_tree *tree; /* subtree of above item */
2022 dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
2023 int hf_index;
2024 dcerpc_callback_fnct_t *callback;
2025 void *callback_args;
2026 } ndr_pointer_data_t;
2028 void
2029 init_ndr_pointer_list(dcerpc_info *di)
2031 di->conformant_run = 0;
2033 while (ndr_pointer_list) {
2034 ndr_pointer_data_t *npd = (ndr_pointer_data_t *)g_slist_nth_data(ndr_pointer_list, 0);
2035 ndr_pointer_list = g_slist_remove(ndr_pointer_list, npd);
2036 g_free(npd);
2039 ndr_pointer_list = NULL;
2040 ndr_pointer_list_pos = 0;
2041 pointers_are_top_level = TRUE;
2045 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, dcerpc_info *di, guint8 *drep)
2047 int found_new_pointer;
2048 int old_offset;
2049 int next_pointer;
2051 next_pointer = 0;
2054 int i, len;
2056 found_new_pointer = 0;
2057 len = g_slist_length(ndr_pointer_list);
2058 for(i=next_pointer; i<len; i++) {
2059 ndr_pointer_data_t *tnpd = (ndr_pointer_data_t *)g_slist_nth_data(ndr_pointer_list, i);
2060 if (tnpd->fnct) {
2061 dcerpc_dissect_fnct_t *fnct;
2063 next_pointer = i+1;
2064 found_new_pointer = 1;
2065 fnct = tnpd->fnct;
2066 tnpd->fnct = NULL;
2067 ndr_pointer_list_pos = i+1;
2068 di->hf_index = tnpd->hf_index;
2069 /* first a run to handle any conformant
2070 array headers */
2071 di->conformant_run = 1;
2072 di->conformant_eaten = 0;
2073 old_offset = offset;
2074 offset = (*(fnct))(tvb, offset, pinfo, NULL, di, drep);
2076 DISSECTOR_ASSERT((offset-old_offset) == di->conformant_eaten);
2077 /* This is to check for any bugs in the dissectors.
2079 * Basically, the NDR representation will store all
2080 * arrays in two blocks, one block with the dimension
2081 * description, like size, number of elements and such,
2082 * and another block that contains the actual data stored
2083 * in the array.
2084 * If the array is embedded directly inside another,
2085 * encapsulating aggregate type, like a union or struct,
2086 * then these two blocks will be stored at different places
2087 * in the bytestream, with other data between the blocks.
2089 * For this reason, all pointers to types (both aggregate
2090 * and scalar, for simplicity no distinction is made)
2091 * will have its dissector called twice.
2092 * The dissector will first be called with conformant_run == 1
2093 * in which mode the dissector MUST NOT consume any data from
2094 * the tvbuff (i.e. may not dissect anything) except the
2095 * initial control block for arrays.
2096 * The second time the dissector is called, with
2097 * conformant_run == 0, all other data for the type will be
2098 * dissected.
2100 * All dissect_ndr_<type> dissectors are already prepared
2101 * for this and knows when it should eat data from the tvb
2102 * and when not to, so implementors of dissectors will
2103 * normally not need to worry about this or even know about
2104 * it. However, if a dissector for an aggregate type calls
2105 * a subdissector from outside packet-dcerpc.c, such as
2106 * the dissector in packet-smb.c for NT Security Descriptors
2107 * as an example, then it is VERY important to encapsulate
2108 * this call to an external subdissector with the appropriate
2109 * test for conformant_run, i.e. it will need something like
2111 * dcerpc_info *di (received as function parameter)
2113 * if (di->conformant_run) {
2114 * return offset;
2117 * to make sure it makes the right thing.
2118 * This assert will signal when someone has forgotten to
2119 * make the dissector aware of this requirement.
2122 /* now we dissect the actual pointer */
2123 di->conformant_run = 0;
2124 old_offset = offset;
2125 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, di, drep);
2126 if (tnpd->callback)
2127 tnpd->callback(pinfo, tnpd->tree, tnpd->item, di, tvb, old_offset, offset, tnpd->callback_args);
2128 proto_item_set_len(tnpd->item, offset - old_offset);
2129 break;
2132 } while (found_new_pointer);
2134 return offset;
2138 static void
2139 add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
2140 dcerpc_info *di, dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index,
2141 dcerpc_callback_fnct_t *callback, void *callback_args)
2143 ndr_pointer_data_t *npd;
2145 /* check if this pointer is valid */
2146 if (id != 0xffffffff) {
2147 dcerpc_call_value *value;
2149 value = di->call_data;
2151 if (di->ptype == PDU_REQ) {
2152 if (!(pinfo->fd->flags.visited)) {
2153 if (id > value->max_ptr) {
2154 value->max_ptr = id;
2157 } else {
2158 /* if we haven't seen the request bail out since we cant
2159 know whether this is the first non-NULL instance
2160 or not */
2161 if (value->req_frame == 0) {
2162 /* XXX THROW EXCEPTION */
2165 /* We saw this one in the request frame, nothing to
2166 dissect later */
2167 if (id <= value->max_ptr) {
2168 return;
2173 npd = (ndr_pointer_data_t *)g_malloc(sizeof(ndr_pointer_data_t));
2174 npd->id = id;
2175 npd->tree = tree;
2176 npd->item = item;
2177 npd->fnct = fnct;
2178 npd->hf_index = hf_index;
2179 npd->callback = callback;
2180 npd->callback_args = callback_args;
2181 ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
2182 ndr_pointer_list_pos);
2183 ndr_pointer_list_pos++;
2187 static int
2188 find_pointer_index(guint32 id)
2190 ndr_pointer_data_t *npd;
2191 int i,len;
2193 len = g_slist_length(ndr_pointer_list);
2194 for(i=0; i<len; i++) {
2195 npd = (ndr_pointer_data_t *)g_slist_nth_data(ndr_pointer_list, i);
2196 if (npd) {
2197 if (npd->id == id) {
2198 return i;
2203 return -1;
2206 /* This function dissects an NDR pointer and stores the callback for later
2207 * deferred dissection.
2209 * fnct is the callback function for when we have reached this object in
2210 * the bytestream.
2212 * type is what type of pointer.
2214 * this is text is what text we should put in any created tree node.
2216 * hf_index is what hf value we want to pass to the callback function when
2217 * it is called, the callback can later pick this one up from di->hf_index.
2219 * callback is executed after the pointer has been dereferenced.
2221 * callback_args is passed as an argument to the callback function
2223 * See packet-dcerpc-samr.c for examples
2226 dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2227 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2228 int type, const char *text, int hf_index,
2229 dcerpc_callback_fnct_t *callback, void *callback_args)
2231 proto_tree *tr = NULL;
2232 gint start_offset = offset;
2233 int pointer_size = 4;
2235 if (di->conformant_run) {
2236 /* this call was only for dissecting the header for any
2237 embedded conformant array. we will not parse any
2238 pointers in this mode.
2240 return offset;
2242 if (di->call_data->flags & DCERPC_IS_NDR64) {
2243 pointer_size = 8;
2247 /*TOP LEVEL REFERENCE POINTER*/
2248 if ( pointers_are_top_level
2249 && (type == NDR_POINTER_REF) ) {
2250 proto_item *item;
2252 /* we must find out a nice way to do the length here */
2253 item = proto_tree_add_text(tree, tvb, offset, 0,
2254 "%s", text);
2255 tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2257 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
2258 hf_index, callback, callback_args);
2259 goto after_ref_id;
2262 /*TOP LEVEL FULL POINTER*/
2263 if ( pointers_are_top_level
2264 && (type == NDR_POINTER_PTR) ) {
2265 int idx;
2266 guint64 id;
2267 proto_item *item;
2269 /* get the referent id */
2270 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
2272 tvb_ensure_bytes_exist(tvb, offset-pointer_size, pointer_size);
2273 /* we got a NULL pointer */
2274 if (id == 0) {
2275 proto_tree_add_text(tree, tvb, offset-pointer_size,
2276 pointer_size,
2277 "(NULL pointer) %s",text);
2278 goto after_ref_id;
2281 /* see if we have seen this pointer before */
2282 DISSECTOR_ASSERT(id <= G_MAXUINT32);
2283 idx = find_pointer_index((guint32)id);
2285 /* we have seen this pointer before */
2286 if (idx >= 0) {
2287 proto_tree_add_text(tree, tvb, offset-pointer_size,
2288 pointer_size,
2289 "(duplicate PTR) %s",text);
2290 goto after_ref_id;
2293 /* new pointer */
2294 item = proto_tree_add_text(tree, tvb, offset-pointer_size,
2295 pointer_size,
2296 "%s", text);
2297 tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2298 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb,
2299 offset-pointer_size, pointer_size, (guint32)id);
2300 add_pointer_to_list(pinfo, tr, item, di, fnct, (guint32)id, hf_index,
2301 callback, callback_args);
2302 goto after_ref_id;
2304 /*TOP LEVEL UNIQUE POINTER*/
2305 if ( pointers_are_top_level
2306 && (type == NDR_POINTER_UNIQUE) ) {
2307 guint64 id;
2308 proto_item *item;
2310 /* get the referent id */
2311 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
2313 tvb_ensure_bytes_exist(tvb, offset-pointer_size, pointer_size);
2314 /* we got a NULL pointer */
2315 if (id == 0) {
2316 proto_tree_add_text(tree, tvb, offset-pointer_size,
2317 pointer_size,
2318 "(NULL pointer) %s",text);
2319 goto after_ref_id;
2322 /* new pointer */
2323 DISSECTOR_ASSERT(id <= G_MAXUINT32);
2324 item = proto_tree_add_text(tree, tvb, offset-pointer_size,
2325 pointer_size,
2326 "%s", text);
2327 tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2328 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb,
2329 offset-pointer_size, pointer_size, (guint32)id);
2330 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
2331 hf_index, callback, callback_args);
2332 goto after_ref_id;
2335 /*EMBEDDED REFERENCE POINTER*/
2336 if ( (!pointers_are_top_level)
2337 && (type == NDR_POINTER_REF) ) {
2338 guint64 id;
2339 proto_item *item;
2341 /* get the referent id */
2342 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
2344 tvb_ensure_bytes_exist(tvb, offset-pointer_size, pointer_size);
2345 /* new pointer */
2346 item = proto_tree_add_text(tree, tvb, offset-pointer_size,
2347 pointer_size,
2348 "%s",text);
2349 tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2350 DISSECTOR_ASSERT(id <= G_MAXUINT32);
2351 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb,
2352 offset-pointer_size, pointer_size, (guint32)id);
2353 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
2354 hf_index, callback, callback_args);
2355 goto after_ref_id;
2358 /*EMBEDDED UNIQUE POINTER*/
2359 if ( (!pointers_are_top_level)
2360 && (type == NDR_POINTER_UNIQUE) ) {
2361 guint64 id;
2362 proto_item *item;
2364 /* get the referent id */
2365 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
2367 tvb_ensure_bytes_exist(tvb, offset-pointer_size, pointer_size);
2368 /* we got a NULL pointer */
2369 if (id == 0) {
2370 proto_tree_add_text(tree, tvb, offset-pointer_size,
2371 pointer_size,
2372 "(NULL pointer) %s", text);
2373 goto after_ref_id;
2376 /* new pointer */
2377 item = proto_tree_add_text(tree, tvb, offset-pointer_size,
2378 pointer_size,
2379 "%s",text);
2380 tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2381 DISSECTOR_ASSERT(id <= G_MAXUINT32);
2382 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb,
2383 offset-pointer_size, pointer_size, (guint32)id);
2384 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
2385 hf_index, callback, callback_args);
2386 goto after_ref_id;
2389 /*EMBEDDED FULL POINTER*/
2390 if ( (!pointers_are_top_level)
2391 && (type == NDR_POINTER_PTR) ) {
2392 int idx;
2393 guint64 id;
2394 proto_item *item;
2396 /* get the referent id */
2397 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
2399 tvb_ensure_bytes_exist(tvb, offset-pointer_size, pointer_size);
2400 /* we got a NULL pointer */
2401 if (id == 0) {
2402 proto_tree_add_text(tree, tvb, offset-pointer_size,
2403 pointer_size,
2404 "(NULL pointer) %s",text);
2405 goto after_ref_id;
2408 /* see if we have seen this pointer before */
2409 DISSECTOR_ASSERT(id <= G_MAXUINT32);
2410 idx = find_pointer_index((guint32)id);
2412 /* we have seen this pointer before */
2413 if (idx >= 0) {
2414 proto_tree_add_text(tree, tvb, offset-pointer_size,
2415 pointer_size,
2416 "(duplicate PTR) %s",text);
2417 goto after_ref_id;
2420 /* new pointer */
2421 item = proto_tree_add_text(tree, tvb, offset-pointer_size,
2422 pointer_size,
2423 "%s", text);
2424 tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2425 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb,
2426 offset-pointer_size, pointer_size, (guint32)id);
2427 add_pointer_to_list(pinfo, tr, item, di, fnct, (guint32)id, hf_index,
2428 callback, callback_args);
2429 goto after_ref_id;
2433 after_ref_id:
2434 /* After each top level pointer we have dissected we have to
2435 dissect all deferrals before we move on to the next top level
2436 argument */
2437 if (pointers_are_top_level == TRUE) {
2438 pointers_are_top_level = FALSE;
2439 offset = dissect_deferred_pointers(pinfo, tvb, offset, di, drep);
2440 pointers_are_top_level = TRUE;
2443 /* Set the length for the new subtree */
2444 if (tr) {
2445 proto_item_set_len(tr, offset-start_offset);
2447 return offset;
2451 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2452 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2453 int type, const char *text, int hf_index)
2455 return dissect_ndr_pointer_cb(
2456 tvb, offset, pinfo, tree, di, drep, fnct, type, text, hf_index,
2457 NULL, NULL);
2460 dissect_ndr_toplevel_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2461 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2462 int type, const char *text, int hf_index)
2464 int ret;
2466 pointers_are_top_level = TRUE;
2467 ret = dissect_ndr_pointer_cb(
2468 tvb, offset, pinfo, tree, di, drep, fnct, type, text, hf_index,
2469 NULL, NULL);
2470 return ret;
2473 dissect_ndr_embedded_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2474 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2475 int type, const char *text, int hf_index)
2477 int ret;
2479 pointers_are_top_level = FALSE;
2480 ret = dissect_ndr_pointer_cb(
2481 tvb, offset, pinfo, tree, di, drep, fnct, type, text, hf_index,
2482 NULL, NULL);
2483 return ret;
2486 static void
2487 show_stub_data(tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
2488 dcerpc_auth_info *auth_info, gboolean is_encrypted)
2490 int length, plain_length, auth_pad_len;
2491 guint auth_pad_offset;
2494 * We don't show stub data unless we have some in the tvbuff;
2495 * however, in the protocol tree, we show, as the number of
2496 * bytes, the reported number of bytes, not the number of bytes
2497 * that happen to be in the tvbuff.
2499 if (tvb_length_remaining(tvb, offset) > 0) {
2500 auth_pad_len = auth_info?auth_info->auth_pad_len:0;
2501 length = tvb_reported_length_remaining(tvb, offset);
2503 /* if auth_pad_len is larger than length then we ignore auth_pad_len totally */
2504 plain_length = length - auth_pad_len;
2505 if (plain_length < 1) {
2506 plain_length = length;
2507 auth_pad_len = 0;
2509 auth_pad_offset = offset + plain_length;
2511 if ((auth_info != NULL) &&
2512 (auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)) {
2513 if (is_encrypted) {
2514 tvb_ensure_bytes_exist(tvb, offset, length);
2515 proto_tree_add_text(dcerpc_tree, tvb, offset, length,
2516 "Encrypted stub data (%d byte%s)",
2517 length, plurality(length, "", "s"));
2518 /* is the padding is still inside the encrypted blob, don't display it explicit */
2519 auth_pad_len = 0;
2520 } else {
2521 tvb_ensure_bytes_exist(tvb, offset, plain_length);
2522 proto_tree_add_text(dcerpc_tree, tvb, offset, plain_length,
2523 "Decrypted stub data (%d byte%s)",
2524 plain_length, plurality(plain_length, "", "s"));
2526 } else {
2527 tvb_ensure_bytes_exist(tvb, offset, plain_length);
2528 proto_tree_add_text(dcerpc_tree, tvb, offset, plain_length,
2529 "Stub data (%d byte%s)", plain_length,
2530 plurality(plain_length, "", "s"));
2532 /* If there is auth padding at the end of the stub, display it */
2533 if (auth_pad_len != 0) {
2534 tvb_ensure_bytes_exist(tvb, auth_pad_offset, auth_pad_len);
2535 proto_tree_add_text(dcerpc_tree, tvb, auth_pad_offset,
2536 auth_pad_len,
2537 "Auth Padding (%u byte%s)",
2538 auth_pad_len,
2539 plurality(auth_pad_len, "", "s"));
2544 static int
2545 dissect_verification_trailer(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *parent_tree)
2547 static const guint8 TRAILER_SIGNATUR[] = {0x8a, 0xe3, 0x13, 0x71, 0x02, 0xf4, 0x36, 0x71};
2548 static const guint16 SEC_VT_COMMAND_END = 0x4000;
2550 proto_item *item;
2551 proto_tree *tree;
2553 const guint8 *start, *pos;
2554 guint16 cmd, len;
2555 int remaining = tvb_length_remaining(tvb, offset);
2556 if (remaining <= 0) {
2557 return offset;
2559 start = tvb_get_ptr(tvb, offset, remaining);
2560 pos = epan_memmem(start, remaining, TRAILER_SIGNATUR, sizeof(TRAILER_SIGNATUR));
2561 if (!pos) {
2562 return offset;
2565 item = proto_tree_add_text(parent_tree, tvb, offset, -1, "Verification Trailer");
2566 tree = proto_item_add_subtree(item, ett_dcerpc_verification_trailer);
2568 if (pos > start) {
2569 int len = pos - start;
2570 proto_tree_add_text(tree, tvb, offset, len,
2571 "Padding (%d byte%s)", len, plurality(len, "", "s"));
2572 offset += len;
2573 remaining -= len;
2575 //XXX DISSECTOR_ASSERT(offset % 4);
2578 proto_tree_add_text(tree, tvb, offset, sizeof(TRAILER_SIGNATUR),
2579 "rpc_sec_verification_trailer");
2580 offset += sizeof(TRAILER_SIGNATUR);
2581 remaining -= sizeof(TRAILER_SIGNATUR);
2583 while (remaining >= 4) {
2584 cmd = tvb_get_letohs(tvb, offset);
2585 len = tvb_get_letohs(tvb, offset+2);
2586 proto_tree_add_bitmask(tree, tvb, offset,
2587 hf_dcerpc_sec_vt_command,
2588 ett_dcerpc_sec_vt_command,
2589 sec_vt_command_fields,
2590 ENC_LITTLE_ENDIAN);
2591 offset += 2;
2592 proto_tree_add_item(tree, hf_dcerpc_sec_vt_command_length, tvb,
2593 offset, 2, ENC_LITTLE_ENDIAN);
2594 offset += 2;
2596 switch (cmd & 0x3fff) {
2597 case 1:
2598 proto_tree_add_bitmask(tree, tvb, offset,
2599 hf_dcerpc_sec_vt_bitmask,
2600 ett_dcerpc_sec_vt_bitmask,
2601 sec_vt_bitmask_fields,
2602 ENC_LITTLE_ENDIAN);
2603 offset += len;
2604 break;
2605 default:
2606 proto_tree_add_text(tree, tvb, offset, len, "blob");
2607 offset += len;
2609 remaining -= (4 + len);
2610 if (cmd & SEC_VT_COMMAND_END) {
2611 break;
2615 proto_item_set_end(item, tvb, offset);
2616 return offset;
2619 static int
2620 dcerpc_try_handoff(packet_info *pinfo, proto_tree *tree,
2621 proto_tree *dcerpc_tree,
2622 tvbuff_t *volatile tvb, tvbuff_t *decrypted_tvb,
2623 guint8 *drep, dcerpc_info *info,
2624 dcerpc_auth_info *auth_info)
2626 volatile gint offset = 0;
2627 dcerpc_uuid_key key;
2628 dcerpc_uuid_value *sub_proto;
2629 proto_tree *volatile sub_tree = NULL;
2630 dcerpc_sub_dissector *proc;
2631 const gchar *name = NULL;
2632 const char *volatile saved_proto;
2633 guint length = 0, reported_length = 0;
2634 tvbuff_t *volatile stub_tvb;
2635 volatile guint auth_pad_len;
2636 volatile int auth_pad_offset;
2637 proto_item *sub_item = NULL;
2638 proto_item *pi, *hidden_item;
2640 dcerpc_dissect_fnct_t *volatile sub_dissect;
2642 key.uuid = info->call_data->uuid;
2643 key.ver = info->call_data->ver;
2645 if ((sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key)) == NULL
2646 || !proto_is_protocol_enabled(sub_proto->proto)) {
2648 * We don't have a dissector for this UUID, or the protocol
2649 * for that UUID is disabled.
2652 hidden_item = proto_tree_add_boolean(dcerpc_tree, hf_dcerpc_unknown_if_id,
2653 tvb, offset, 0, TRUE);
2654 PROTO_ITEM_SET_HIDDEN(hidden_item);
2655 col_append_fstr(pinfo->cinfo, COL_INFO, " %s V%u",
2656 guids_resolve_uuid_to_str(&info->call_data->uuid), info->call_data->ver);
2658 if (decrypted_tvb != NULL) {
2659 show_stub_data(decrypted_tvb, 0, dcerpc_tree, auth_info,
2660 FALSE);
2661 } else
2662 show_stub_data(tvb, 0, dcerpc_tree, auth_info, TRUE);
2663 return -1;
2666 for (proc = sub_proto->procs; proc->name; proc++) {
2667 if (proc->num == info->call_data->opnum) {
2668 name = proc->name;
2669 break;
2673 col_set_str(pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
2675 if (!name)
2676 col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown operation %u %s",
2677 info->call_data->opnum,
2678 (info->ptype == PDU_REQ) ? "request" : "response");
2679 else
2680 col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
2681 name, (info->ptype == PDU_REQ) ? "request" : "response");
2683 sub_dissect = (info->ptype == PDU_REQ) ?
2684 proc->dissect_rqst : proc->dissect_resp;
2686 if (tree) {
2687 sub_item = proto_tree_add_item(tree, sub_proto->proto_id,
2688 (decrypted_tvb != NULL)?decrypted_tvb:tvb,
2689 0, -1, ENC_NA);
2691 if (sub_item) {
2692 sub_tree = proto_item_add_subtree(sub_item, sub_proto->ett);
2693 if (!name)
2694 proto_item_append_text(sub_item, ", unknown operation %u",
2695 info->call_data->opnum);
2696 else
2697 proto_item_append_text(sub_item, ", %s", name);
2701 * Put the operation number into the tree along with
2702 * the operation's name.
2704 if (sub_proto->opnum_hf != -1)
2705 proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
2706 tvb, 0, 0, info->call_data->opnum,
2707 "Operation: %s (%u)",
2708 name ? name : "Unknown operation",
2709 info->call_data->opnum);
2710 else
2711 proto_tree_add_uint_format_value(sub_tree, hf_dcerpc_op, tvb,
2712 0, 0, info->call_data->opnum,
2713 "%s (%u)",
2714 name ? name : "Unknown operation",
2715 info->call_data->opnum);
2717 if ((info->ptype == PDU_REQ) && (info->call_data->rep_frame != 0)) {
2718 pi = proto_tree_add_uint(sub_tree, hf_dcerpc_response_in,
2719 tvb, 0, 0, info->call_data->rep_frame);
2720 PROTO_ITEM_SET_GENERATED(pi);
2722 if ((info->ptype == PDU_RESP) && (info->call_data->req_frame != 0)) {
2723 pi = proto_tree_add_uint(sub_tree, hf_dcerpc_request_in,
2724 tvb, 0, 0, info->call_data->req_frame);
2725 PROTO_ITEM_SET_GENERATED(pi);
2727 } /* tree */
2729 if (decrypted_tvb != NULL) {
2730 /* Either there was no encryption or we successfully decrypted
2731 the encrypted payload. */
2732 if (sub_dissect) {
2733 /* We have a subdissector - call it. */
2734 saved_proto = pinfo->current_proto;
2735 pinfo->current_proto = sub_proto->name;
2737 init_ndr_pointer_list(info);
2739 length = tvb_length(decrypted_tvb);
2740 reported_length = tvb_reported_length(decrypted_tvb);
2743 * Remove the authentication padding from the stub data.
2745 if ((auth_info != NULL) && (auth_info->auth_pad_len != 0)) {
2746 if (reported_length >= auth_info->auth_pad_len) {
2748 * OK, the padding length isn't so big that it
2749 * exceeds the stub length. Trim the reported
2750 * length of the tvbuff.
2752 reported_length -= auth_info->auth_pad_len;
2755 * If that exceeds the actual amount of data in
2756 * the tvbuff (which means we have at least one
2757 * byte of authentication padding in the tvbuff),
2758 * trim the actual amount.
2760 if (length > reported_length)
2761 length = reported_length;
2763 stub_tvb = tvb_new_subset(decrypted_tvb, 0, length, reported_length);
2764 auth_pad_len = auth_info->auth_pad_len;
2765 auth_pad_offset = reported_length;
2766 } else {
2768 * The padding length exceeds the stub length.
2769 * Don't bother dissecting the stub, trim the padding
2770 * length to what's in the stub data, and show the
2771 * entire stub as authentication padding.
2773 stub_tvb = NULL;
2774 auth_pad_len = reported_length;
2775 auth_pad_offset = 0;
2776 length = 0;
2778 } else {
2780 * No authentication padding.
2782 stub_tvb = decrypted_tvb;
2783 auth_pad_len = 0;
2784 auth_pad_offset = 0;
2787 if (sub_item) {
2788 proto_item_set_len(sub_item, length);
2791 if (stub_tvb != NULL) {
2793 * Catch all exceptions other than BoundsError, so that even
2794 * if the stub data is bad, we still show the authentication
2795 * padding, if any.
2797 * If we get BoundsError, it means the frame was cut short
2798 * by a snapshot length, so there's nothing more to
2799 * dissect; just re-throw that exception.
2801 TRY {
2802 int remaining;
2804 offset = sub_dissect(stub_tvb, 0, pinfo, sub_tree,
2805 info, drep);
2807 offset = dissect_verification_trailer(stub_tvb, offset,
2808 pinfo, dcerpc_tree);
2810 /* If we have a subdissector and it didn't dissect all
2811 data in the tvb, make a note of it. */
2812 remaining = tvb_reported_length_remaining(stub_tvb, offset);
2813 if (remaining > 0) {
2814 proto_tree_add_text(sub_tree, stub_tvb, offset,
2815 remaining,
2816 "[Long frame (%d byte%s)]",
2817 remaining,
2818 plurality(remaining, "", "s"));
2819 col_append_fstr(pinfo->cinfo, COL_INFO,
2820 "[Long frame (%d byte%s)]",
2821 remaining,
2822 plurality(remaining, "", "s"));
2825 } CATCH_NONFATAL_ERRORS {
2827 * Somebody threw an exception that means that there
2828 * was a problem dissecting the payload; that means
2829 * that a dissector was found, so we don't need to
2830 * dissect the payload as data or update the protocol
2831 * or info columns.
2833 * Just show the exception and then drive on to show
2834 * the authentication padding.
2836 show_exception(stub_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
2837 } ENDTRY;
2840 /* If there is auth padding at the end of the stub, display it */
2841 if (auth_pad_len != 0) {
2842 tvb_ensure_bytes_exist(tvb, auth_pad_offset, auth_pad_len);
2843 proto_tree_add_text(dcerpc_tree, decrypted_tvb, auth_pad_offset,
2844 auth_pad_len,
2845 "Auth Padding (%u byte%s)",
2846 auth_pad_len,
2847 plurality(auth_pad_len, "", "s"));
2850 pinfo->current_proto = saved_proto;
2851 } else {
2852 /* No subdissector - show it as stub data. */
2853 if (decrypted_tvb) {
2854 show_stub_data(decrypted_tvb, 0, sub_tree, auth_info, FALSE);
2855 } else {
2856 show_stub_data(tvb, 0, sub_tree, auth_info, TRUE);
2859 } else
2860 show_stub_data(tvb, 0, sub_tree, auth_info, TRUE);
2862 tap_queue_packet(dcerpc_tap, pinfo, info);
2863 return 0;
2866 static int
2867 dissect_dcerpc_verifier(tvbuff_t *tvb, packet_info *pinfo,
2868 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
2869 dcerpc_auth_info *auth_info)
2871 int auth_offset;
2873 auth_info->auth_data = NULL;
2875 if (auth_info->auth_size != 0) {
2876 dcerpc_auth_subdissector_fns *auth_fns;
2877 tvbuff_t *auth_tvb;
2879 auth_offset = hdr->frag_len - hdr->auth_len;
2881 auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
2882 hdr->auth_len);
2884 auth_info->auth_data = auth_tvb;
2886 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
2887 auth_info->auth_type))) {
2889 * Catch all bounds-error exceptions, so that even if the
2890 * verifier is bad or we don't have all of it, we still
2891 * show the stub data.
2893 TRY {
2894 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
2895 hdr, auth_info);
2896 } CATCH_BOUNDS_ERRORS {
2897 show_exception(auth_tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
2898 } ENDTRY;
2899 } else {
2900 tvb_ensure_bytes_exist(tvb, 0, hdr->auth_len);
2901 proto_tree_add_text(dcerpc_tree, auth_tvb, 0, hdr->auth_len,
2902 "Auth Verifier");
2906 return hdr->auth_len;
2909 static void
2910 dissect_dcerpc_cn_auth(tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
2911 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
2912 gboolean are_credentials, dcerpc_auth_info *auth_info)
2914 volatile int offset;
2917 * Initially set auth_level and auth_type to zero to indicate that we
2918 * haven't yet seen any authentication level information.
2920 auth_info->auth_level = 0;
2921 auth_info->auth_type = 0;
2922 auth_info->auth_size = 0;
2923 auth_info->auth_pad_len = 0;
2926 * The authentication information is at the *end* of the PDU; in
2927 * request and response PDUs, the request and response stub data
2928 * come before it.
2930 * Is there any authentication data (i.e., is the authentication length
2931 * non-zero), and is the authentication length valid (i.e., is it, plus
2932 * 8 bytes for the type/level/pad length/reserved/context id, less than
2933 * or equal to the fragment length minus the starting offset of the
2934 * stub data?)
2937 if (hdr->auth_len
2938 && ((hdr->auth_len + 8) <= (hdr->frag_len - stub_offset))) {
2941 * Yes, there is authentication data, and the length is valid.
2942 * Do we have all the bytes of stub data?
2943 * (If not, we'd throw an exception dissecting *that*, so don't
2944 * bother trying to dissect the authentication information and
2945 * throwing another exception there.)
2947 offset = hdr->frag_len - (hdr->auth_len + 8);
2948 if (offset == 0 || tvb_offset_exists(tvb, offset - 1)) {
2950 * Either there's no stub data, or the last byte of the stub
2951 * data is present in the captured data, so we shouldn't
2952 * get a BoundsError dissecting the stub data.
2954 * Try dissecting the authentication data.
2955 * Catch all exceptions, so that even if the auth info is bad
2956 * or we don't have all of it, we still show the stuff we
2957 * dissect after this, such as stub data.
2959 TRY {
2960 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2961 hf_dcerpc_auth_type,
2962 &auth_info->auth_type);
2963 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2964 hf_dcerpc_auth_level,
2965 &auth_info->auth_level);
2967 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2968 hf_dcerpc_auth_pad_len,
2969 &auth_info->auth_pad_len);
2970 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2971 hf_dcerpc_auth_rsrvd, NULL);
2972 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2973 hf_dcerpc_auth_ctx_id, NULL);
2976 * Dissect the authentication data.
2978 if (are_credentials) {
2979 tvbuff_t *auth_tvb;
2980 dcerpc_auth_subdissector_fns *auth_fns;
2982 auth_tvb = tvb_new_subset(tvb, offset,
2983 MIN(hdr->auth_len,tvb_length_remaining(tvb, offset)),
2984 hdr->auth_len);
2986 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
2987 auth_info->auth_type)))
2988 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
2989 hdr, auth_info);
2990 else
2991 proto_tree_add_text(dcerpc_tree, tvb, offset, hdr->auth_len,
2992 "Auth Credentials");
2995 /* Compute the size of the auth block. Note that this should not
2996 include auth padding, since when NTLMSSP encryption is used, the
2997 padding is actually inside the encrypted stub */
2998 auth_info->auth_size = hdr->auth_len + 8;
2999 } CATCH_BOUNDS_ERRORS {
3000 show_exception(tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
3001 } ENDTRY;
3007 /* We need to hash in the SMB fid number to generate a unique hash table
3008 * key as DCERPC over SMB allows several pipes over the same TCP/IP
3009 * socket.
3010 * We pass this function the transport type here to make sure we only look
3011 * at this function if it came across an SMB pipe.
3012 * Other transports might need to mix in their own extra multiplexing data
3013 * as well in the future.
3016 guint16 dcerpc_get_transport_salt(packet_info *pinfo)
3018 switch (pinfo->dcetransporttype) {
3019 case DCE_CN_TRANSPORT_SMBPIPE:
3020 /* DCERPC over smb */
3021 return pinfo->dcetransportsalt;
3024 /* Some other transport... */
3025 return 0;
3029 * Connection oriented packet types
3032 static void
3033 dissect_dcerpc_cn_bind(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3034 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
3036 conversation_t *conv = find_or_create_conversation(pinfo);
3037 guint8 num_ctx_items = 0;
3038 guint i;
3039 guint16 ctx_id;
3040 guint8 num_trans_items;
3041 guint j;
3042 e_uuid_t if_id;
3043 e_uuid_t trans_id;
3044 guint32 trans_ver;
3045 guint16 if_ver, if_ver_minor;
3046 dcerpc_auth_info auth_info;
3047 char *uuid_str;
3048 const char *uuid_name = NULL;
3049 proto_item *iface_item = NULL;
3051 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3052 hf_dcerpc_cn_max_xmit, NULL);
3054 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3055 hf_dcerpc_cn_max_recv, NULL);
3057 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3058 hf_dcerpc_cn_assoc_group, NULL);
3060 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3061 hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
3063 /* padding */
3064 offset += 3;
3066 col_append_fstr(pinfo->cinfo, COL_INFO, ", %u context items:", num_ctx_items);
3068 for (i = 0; i < num_ctx_items; i++) {
3069 proto_item *ctx_item = NULL;
3070 proto_tree *ctx_tree = NULL, *iface_tree = NULL;
3071 gint ctx_offset = offset;
3073 dissect_dcerpc_uint16(tvb, offset, pinfo, NULL, hdr->drep,
3074 hf_dcerpc_cn_ctx_id, &ctx_id);
3076 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3077 /* (if we have multiple contexts, this might cause "decode as"
3078 * to behave unpredictably) */
3079 pinfo->dcectxid = ctx_id;
3081 if (dcerpc_tree) {
3082 ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_item,
3083 tvb, offset, 0,
3084 ENC_NA);
3085 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
3088 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree, hdr->drep,
3089 hf_dcerpc_cn_ctx_id, &ctx_id);
3090 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, ctx_tree, hdr->drep,
3091 hf_dcerpc_cn_num_trans_items, &num_trans_items);
3093 if (dcerpc_tree) {
3094 proto_item_append_text(ctx_item, "[%u]: Context ID:%u", i+1, ctx_id);
3097 /* padding */
3098 offset += 1;
3100 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &if_id);
3101 if (ctx_tree) {
3103 iface_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_abstract_syntax, tvb, offset, 0, ENC_NA);
3104 iface_tree = proto_item_add_subtree(iface_item, ett_dcerpc_cn_iface);
3106 uuid_str = guid_to_str((e_guid_t*)&if_id);
3107 uuid_name = guids_get_uuid_name(&if_id);
3108 if (uuid_name) {
3109 proto_tree_add_guid_format(iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
3110 offset, 16, (e_guid_t *) &if_id, "Interface: %s UUID: %s", uuid_name, uuid_str);
3111 proto_item_append_text(iface_item, ": %s", uuid_name);
3112 proto_item_append_text(ctx_item, ", %s", uuid_name);
3113 } else {
3114 proto_tree_add_guid_format(iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
3115 offset, 16, (e_guid_t *) &if_id, "Interface UUID: %s", uuid_str);
3116 proto_item_append_text(iface_item, ": %s", uuid_str);
3117 proto_item_append_text(ctx_item, ", %s", uuid_str);
3120 offset += 16;
3122 if (hdr->drep[0] & DREP_LITTLE_ENDIAN) {
3123 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
3124 hf_dcerpc_cn_bind_if_ver, &if_ver);
3125 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
3126 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
3127 } else {
3128 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
3129 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
3130 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
3131 hf_dcerpc_cn_bind_if_ver, &if_ver);
3134 if (ctx_tree) {
3135 proto_item_append_text(iface_item, " V%u.%u", if_ver, if_ver_minor);
3136 proto_item_set_len(iface_item, 20);
3139 memset(&trans_id, 0, sizeof(trans_id));
3140 for (j = 0; j < num_trans_items; j++) {
3141 proto_tree *trans_tree = NULL;
3142 proto_item *trans_item = NULL;
3143 proto_item *uuid_item = NULL;
3145 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &trans_id);
3146 if (ctx_tree) {
3148 trans_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_trans_syntax, tvb, offset, 0, ENC_NA);
3149 trans_tree = proto_item_add_subtree(trans_item, ett_dcerpc_cn_trans_syntax);
3151 uuid_str = guid_to_str((e_guid_t *) &trans_id);
3152 uuid_name = guids_get_uuid_name(&trans_id);
3154 if (uuid_name) {
3155 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);
3156 proto_item_append_text(trans_item, "[%u]: %s", j+1, uuid_name);
3157 proto_item_append_text(ctx_item, ", %s", uuid_name);
3158 } else {
3159 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);
3160 proto_item_append_text(trans_item, "[%u]: %s", j+1, uuid_str);
3161 proto_item_append_text(ctx_item, ", %s", uuid_str);
3164 /* check for [MS-RPCE] 3.3.1.5.3 Bind Time Feature Negotiation */
3165 if (trans_id.Data1 == 0x6cb71c2c && trans_id.Data2 == 0x9812 && trans_id.Data3 == 0x4540) {
3166 proto_tree *uuid_tree = proto_item_add_subtree(uuid_item, ett_dcerpc_cn_trans_btfn);
3167 proto_tree_add_boolean(uuid_tree, hf_dcerpc_cn_bind_trans_btfn_01, tvb, offset+8, 1, trans_id.Data4[0]);
3168 proto_tree_add_boolean(uuid_tree, hf_dcerpc_cn_bind_trans_btfn_02, tvb, offset+8, 1, trans_id.Data4[0]);
3171 offset += 16;
3173 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, trans_tree, hdr->drep,
3174 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
3175 if (ctx_tree) {
3176 proto_item_set_len(trans_item, 20);
3177 proto_item_append_text(trans_item, " V%u", trans_ver);
3181 /* if this is the first time we've seen this packet, we need to
3182 update the dcerpc_binds table so that any later calls can
3183 match to the interface.
3184 XXX We assume that BINDs will NEVER be fragmented.
3186 if (!(pinfo->fd->flags.visited)) {
3187 dcerpc_bind_key *key;
3188 dcerpc_bind_value *value;
3190 key = (dcerpc_bind_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_key));
3191 key->conv = conv;
3192 key->ctx_id = ctx_id;
3193 key->smb_fid = dcerpc_get_transport_salt(pinfo);
3195 value = (dcerpc_bind_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_value));
3196 value->uuid = if_id;
3197 value->ver = if_ver;
3198 value->transport = trans_id;
3200 /* add this entry to the bind table */
3201 g_hash_table_insert(dcerpc_binds, key, value);
3204 if (i > 0)
3205 col_append_fstr(pinfo->cinfo, COL_INFO, ",");
3206 col_append_fstr(pinfo->cinfo, COL_INFO, " %s V%u.%u (%s)",
3207 guids_resolve_uuid_to_str(&if_id), if_ver, if_ver_minor,
3208 guids_resolve_uuid_to_str(&trans_id));
3210 if (ctx_tree) {
3211 proto_item_set_len(ctx_item, offset - ctx_offset);
3216 * XXX - we should save the authentication type *if* we have
3217 * an authentication header, and associate it with an authentication
3218 * context, so subsequent PDUs can use that context.
3220 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
3223 static void
3224 dissect_dcerpc_cn_bind_ack(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3225 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
3227 guint16 max_xmit, max_recv;
3228 guint16 sec_addr_len;
3229 guint8 num_results;
3230 guint i;
3231 guint16 result = 0;
3232 guint16 reason = 0;
3233 e_uuid_t trans_id;
3234 guint32 trans_ver;
3235 dcerpc_auth_info auth_info;
3236 const char *uuid_name = NULL;
3237 const char *result_str = NULL;
3239 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3240 hf_dcerpc_cn_max_xmit, &max_xmit);
3242 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3243 hf_dcerpc_cn_max_recv, &max_recv);
3245 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3246 hf_dcerpc_cn_assoc_group, NULL);
3248 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3249 hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
3250 if (sec_addr_len != 0) {
3251 tvb_ensure_bytes_exist(tvb, offset, sec_addr_len);
3252 proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
3253 sec_addr_len, ENC_ASCII|ENC_NA);
3254 offset += sec_addr_len;
3257 if (offset % 4) {
3258 offset += 4 - offset % 4;
3261 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3262 hf_dcerpc_cn_num_results, &num_results);
3264 /* padding */
3265 offset += 3;
3267 col_append_fstr(pinfo->cinfo, COL_INFO, ", max_xmit: %u max_recv: %u, %u results:",
3268 max_xmit, max_recv, num_results);
3270 for (i = 0; i < num_results; i++) {
3271 proto_tree *ctx_tree = NULL;
3272 proto_item *ctx_item = NULL;
3274 if (dcerpc_tree) {
3275 ctx_item = proto_tree_add_text(dcerpc_tree, tvb, offset, 24, "Ctx Item[%u]:", i+1);
3276 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
3279 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree,
3280 hdr->drep, hf_dcerpc_cn_ack_result,
3281 &result);
3283 /* [MS-RPCE] 3.3.1.5.3 check if this Ctx Item is the response to a Bind Time Feature Negotiation request */
3284 if (result == 3) {
3285 const int old_offset = offset;
3286 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree, hdr->drep, hf_dcerpc_cn_ack_btfn, &reason);
3287 proto_tree_add_boolean(ctx_tree, hf_dcerpc_cn_bind_trans_btfn_01, tvb, old_offset, 1, reason);
3288 proto_tree_add_boolean(ctx_tree, hf_dcerpc_cn_bind_trans_btfn_02, tvb, old_offset, 1, reason);
3289 } else if (result != 0) {
3290 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree,
3291 hdr->drep, hf_dcerpc_cn_ack_reason,
3292 &reason);
3293 } else {
3295 * The reason for rejection isn't meaningful, and often isn't
3296 * set, when the syntax was accepted.
3298 offset += 2;
3301 result_str = val_to_str(result, p_cont_result_vals, "Unknown result (%u)");
3303 if (ctx_tree) {
3304 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &trans_id);
3305 uuid_name = guids_get_uuid_name(&trans_id);
3306 if (! uuid_name) {
3307 uuid_name = guid_to_str((e_guid_t *) &trans_id);
3309 proto_tree_add_guid_format(ctx_tree, hf_dcerpc_cn_ack_trans_id, tvb,
3310 offset, 16, (e_guid_t *) &trans_id, "Transfer Syntax: %s",
3311 uuid_name);
3312 proto_item_append_text(ctx_item, " %s, %s", result_str, uuid_name);
3314 offset += 16;
3316 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, ctx_tree, hdr->drep,
3317 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
3319 if (i > 0)
3320 col_append_fstr(pinfo->cinfo, COL_INFO, ",");
3321 col_append_fstr(pinfo->cinfo, COL_INFO, " %s", result_str);
3325 * XXX - do we need to do anything with the authentication level
3326 * we get back from this?
3328 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
3331 static void
3332 dissect_dcerpc_cn_bind_nak(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3333 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
3335 guint16 reason;
3336 guint8 num_protocols;
3337 guint i;
3339 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
3340 hdr->drep, hf_dcerpc_cn_reject_reason,
3341 &reason);
3343 col_append_fstr(pinfo->cinfo, COL_INFO, " reason: %s",
3344 val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
3346 if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
3347 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3348 hf_dcerpc_cn_num_protocols,
3349 &num_protocols);
3351 for (i = 0; i < num_protocols; i++) {
3352 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
3353 hdr->drep, hf_dcerpc_cn_protocol_ver_major,
3354 NULL);
3355 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
3356 hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
3357 NULL);
3362 /* Return a string describing a DCE/RPC fragment as first, middle, or end
3363 fragment. */
3365 #define PFC_FRAG_MASK 0x03
3367 static const char *
3368 fragment_type(guint8 flags)
3370 static const char* t[4] = {
3371 "Mid",
3372 "1st",
3373 "Last",
3374 "Single"
3376 return t[flags & PFC_FRAG_MASK];
3379 /* Dissect stub data (payload) of a DCERPC packet. */
3381 static void
3382 dissect_dcerpc_cn_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
3383 proto_tree *dcerpc_tree, proto_tree *tree,
3384 e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
3385 dcerpc_auth_info *auth_info, guint32 alloc_hint _U_,
3386 guint32 frame)
3388 gint length, reported_length;
3389 gboolean save_fragmented;
3390 fragment_head *fd_head = NULL;
3392 tvbuff_t *auth_tvb, *payload_tvb, *decrypted_tvb;
3393 proto_item *pi;
3394 proto_item *parent_pi;
3395 proto_item *dcerpc_tree_item;
3397 save_fragmented = pinfo->fragmented;
3399 length = tvb_length_remaining(tvb, offset);
3400 reported_length = tvb_reported_length_remaining(tvb, offset);
3401 if (reported_length < 0 ||
3402 (guint32)reported_length < auth_info->auth_size) {
3403 /* We don't even have enough bytes for the authentication
3404 stuff. */
3405 return;
3407 reported_length -= auth_info->auth_size;
3408 if (length > reported_length)
3409 length = reported_length;
3410 payload_tvb = tvb_new_subset(tvb, offset, length, reported_length);
3412 auth_tvb = NULL;
3413 /*don't bother if we don't have the entire tvb */
3414 /*XXX we should really make sure we calculate auth_info->auth_data
3415 and use that one instead of this auth_tvb hack
3417 if (tvb_length(tvb) == tvb_reported_length(tvb)) {
3418 if (tvb_length_remaining(tvb, offset+length) > 8) {
3419 auth_tvb = tvb_new_subset_remaining(tvb, offset+length+8);
3423 /* Decrypt the PDU if it is encrypted */
3425 if (auth_info->auth_type &&
3426 (auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)) {
3428 * We know the authentication type, and the authentication
3429 * level is "Packet privacy", meaning the payload is
3430 * encrypted; attempt to decrypt it.
3432 dcerpc_auth_subdissector_fns *auth_fns;
3434 /* Start out assuming we won't succeed in decrypting. */
3435 decrypted_tvb = NULL;
3436 /* Schannel needs information into the footer (verifier) in order to setup decryption keys
3437 * so we call it in order to have a chance to decipher the data
3439 if (DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN == auth_info->auth_type) {
3440 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, auth_info);
3443 if ((auth_fns = get_auth_subdissector_fns(
3444 auth_info->auth_level, auth_info->auth_type))) {
3445 tvbuff_t *result;
3447 result = decode_encrypted_data(
3448 payload_tvb, auth_tvb, pinfo, auth_fns,
3449 hdr->ptype == PDU_REQ, auth_info);
3451 if (result) {
3452 if (dcerpc_tree)
3453 proto_tree_add_text(
3454 dcerpc_tree, payload_tvb, 0, -1,
3455 "Encrypted stub data (%d byte%s)",
3456 tvb_reported_length(payload_tvb),
3458 plurality(tvb_length(payload_tvb), "", "s"));
3460 add_new_data_source(
3461 pinfo, result, "Decrypted stub data");
3463 /* We succeeded. */
3464 decrypted_tvb = result;
3467 } else
3468 decrypted_tvb = payload_tvb;
3470 /* if this packet is not fragmented, just dissect it and exit */
3471 if (PFC_NOT_FRAGMENTED(hdr)) {
3472 pinfo->fragmented = FALSE;
3474 dcerpc_try_handoff(
3475 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
3476 hdr->drep, di, auth_info);
3478 pinfo->fragmented = save_fragmented;
3479 return;
3482 /* The packet is fragmented. */
3483 pinfo->fragmented = TRUE;
3485 /* debug output of essential fragment data. */
3486 /* leave it here for future debugging sessions */
3487 /*printf("DCE num:%u offset:%u frag_len:%u tvb_len:%u\n",
3488 pinfo->fd->num, offset, hdr->frag_len, tvb_length(decrypted_tvb));*/
3490 /* if we are not doing reassembly and this is the first fragment
3491 then just dissect it and exit
3492 XXX - if we're not doing reassembly, can we decrypt an
3493 encrypted stub?
3495 if ( (!dcerpc_reassemble) && (hdr->flags & PFC_FIRST_FRAG) ) {
3497 dcerpc_try_handoff(
3498 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
3499 hdr->drep, di, auth_info);
3501 expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment, "%s fragment", fragment_type(hdr->flags));
3503 pinfo->fragmented = save_fragmented;
3504 return;
3507 /* if we have already seen this packet, see if it was reassembled
3508 and if so dissect the full pdu.
3509 then exit
3511 if (pinfo->fd->flags.visited) {
3512 fd_head = fragment_get_reassembled(&dcerpc_co_reassembly_table, frame);
3513 goto end_cn_stub;
3516 /* if we are not doing reassembly and it was neither a complete PDU
3517 nor the first fragment then there is nothing more we can do
3518 so we just have to exit
3520 if ( !dcerpc_reassemble || (tvb_length(tvb) != tvb_reported_length(tvb)) )
3521 goto end_cn_stub;
3523 /* if we didn't get 'frame' we don't know where the PDU started and thus
3524 it is pointless to continue
3526 if (!frame)
3527 goto end_cn_stub;
3529 /* from now on we must attempt to reassemble the PDU
3532 /* if we get here we know it is the first time we see the packet
3533 and we also know it is only a fragment and not a full PDU,
3534 thus we must reassemble it.
3537 /* Do we have any non-encrypted data to reassemble? */
3538 if (decrypted_tvb == NULL) {
3539 /* No. We can't even try to reassemble. */
3540 goto end_cn_stub;
3543 /* defragmentation is a bit tricky, as there's no offset of the fragment
3544 * in the protocol data.
3546 * just use fragment_add_seq_next() and hope that TCP/SMB segments coming
3547 * in with the correct sequence.
3549 fd_head = fragment_add_seq_next(&dcerpc_co_reassembly_table,
3550 decrypted_tvb, 0, pinfo, frame, NULL,
3551 tvb_length(decrypted_tvb),
3552 hdr->flags&PFC_LAST_FRAG ? FALSE : TRUE /* more_frags */);
3554 end_cn_stub:
3556 /* if reassembly is complete and this is the last fragment
3557 * (multiple fragments in one PDU are possible!)
3558 * dissect the full PDU
3560 if (fd_head && (fd_head->flags & FD_DEFRAGMENTED) ) {
3562 if ((pinfo->fd->num == fd_head->reassembled_in) && (hdr->flags & PFC_LAST_FRAG) ) {
3563 tvbuff_t *next_tvb;
3564 proto_item *frag_tree_item;
3566 next_tvb = tvb_new_chain((decrypted_tvb)?decrypted_tvb:payload_tvb,
3567 fd_head->tvb_data);
3569 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3570 show_fragment_tree(fd_head, &dcerpc_frag_items,
3571 tree, pinfo, next_tvb, &frag_tree_item);
3572 /* the toplevel fragment subtree is now behind all desegmented data,
3573 * move it right behind the DCE/RPC tree */
3574 dcerpc_tree_item = proto_tree_get_parent(dcerpc_tree);
3575 if (frag_tree_item && dcerpc_tree_item) {
3576 proto_tree_move_item(tree, dcerpc_tree_item, frag_tree_item);
3579 pinfo->fragmented = FALSE;
3581 expert_add_info_format(pinfo, frag_tree_item, &ei_dcerpc_fragment_reassembled, "%s fragment, reassembled", fragment_type(hdr->flags));
3583 dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb,
3584 next_tvb, hdr->drep, di, auth_info);
3586 } else {
3587 if (decrypted_tvb) {
3588 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
3589 decrypted_tvb, 0, 0, fd_head->reassembled_in);
3590 } else {
3591 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
3592 payload_tvb, 0, 0, fd_head->reassembled_in);
3594 PROTO_ITEM_SET_GENERATED(pi);
3595 parent_pi = proto_tree_get_parent(dcerpc_tree);
3596 if (parent_pi != NULL) {
3597 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
3599 col_append_fstr(pinfo->cinfo, COL_INFO,
3600 " [DCE/RPC %s fragment, reas: #%u]", fragment_type(hdr->flags), fd_head->reassembled_in);
3601 expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment_reassembled, "%s fragment, reassembled in #%u", fragment_type(hdr->flags), fd_head->reassembled_in);
3603 } else {
3604 /* Reassembly not complete - some fragments
3605 are missing. Just show the stub data. */
3606 expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment, "%s fragment", fragment_type(hdr->flags));
3608 if (decrypted_tvb) {
3609 show_stub_data(decrypted_tvb, 0, tree, auth_info, FALSE);
3610 } else {
3611 show_stub_data(payload_tvb, 0, tree, auth_info, TRUE);
3615 pinfo->fragmented = save_fragmented;
3619 * Registers a conversation/UUID binding association, so that
3620 * we can invoke the proper sub-dissector for a given DCERPC
3621 * conversation.
3623 * @param binding all values needed to create and bind a new conversation
3625 * @return Pointer to newly-added UUID/conversation binding.
3627 struct _dcerpc_bind_value *
3628 dcerpc_add_conv_to_bind_table(decode_dcerpc_bind_values_t *binding)
3630 dcerpc_bind_value *bind_value;
3631 dcerpc_bind_key *key;
3632 conversation_t *conv;
3634 conv = find_conversation(
3636 &binding->addr_a,
3637 &binding->addr_b,
3638 binding->ptype,
3639 binding->port_a,
3640 binding->port_b,
3643 if (!conv) {
3644 conv = conversation_new(
3646 &binding->addr_a,
3647 &binding->addr_b,
3648 binding->ptype,
3649 binding->port_a,
3650 binding->port_b,
3654 bind_value = (dcerpc_bind_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_value));
3655 bind_value->uuid = binding->uuid;
3656 bind_value->ver = binding->ver;
3657 /* For now, assume all DCE/RPC we pick from "decode as" is using
3658 standard ndr and not ndr64.
3659 We should make this selectable from the dialog in the future
3661 bind_value->transport = uuid_data_repr_proto;
3663 key = (dcerpc_bind_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_key));
3664 key->conv = conv;
3665 key->ctx_id = binding->ctx_id;
3666 key->smb_fid = binding->smb_fid;
3668 /* add this entry to the bind table */
3669 g_hash_table_insert(dcerpc_binds, key, bind_value);
3671 return bind_value;
3675 static void
3676 dissect_dcerpc_cn_rqst(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3677 proto_tree *dcerpc_tree, proto_tree *tree,
3678 e_dce_cn_common_hdr_t *hdr)
3680 conversation_t *conv;
3681 guint16 ctx_id;
3682 guint16 opnum;
3683 e_uuid_t obj_id = DCERPC_UUID_NULL;
3684 dcerpc_auth_info auth_info;
3685 guint32 alloc_hint;
3686 proto_item *pi;
3687 proto_item *parent_pi;
3689 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3690 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3692 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3693 hf_dcerpc_cn_ctx_id, &ctx_id);
3694 parent_pi = proto_tree_get_parent(dcerpc_tree);
3695 if (parent_pi != NULL) {
3696 proto_item_append_text(parent_pi, ", Ctx: %u", ctx_id);
3699 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3700 hf_dcerpc_opnum, &opnum);
3702 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3703 pinfo->dcectxid = ctx_id;
3705 col_append_fstr(pinfo->cinfo, COL_INFO, ", opnum: %u, Ctx: %u",
3706 opnum, ctx_id);
3708 if (hdr->flags & PFC_OBJECT_UUID) {
3709 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &obj_id);
3710 if (dcerpc_tree) {
3711 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
3712 offset, 16, (e_guid_t *) &obj_id, "Object UUID: %s",
3713 guid_to_str((e_guid_t *) &obj_id));
3715 offset += 16;
3719 * XXX - what if this was set when the connection was set up,
3720 * and we just have a security context?
3722 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3724 conv = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3725 pinfo->srcport, pinfo->destport, 0);
3726 if (!conv)
3727 show_stub_data(tvb, offset, dcerpc_tree, &auth_info, TRUE);
3728 else {
3729 dcerpc_matched_key matched_key, *new_matched_key;
3730 dcerpc_call_value *value;
3732 /* !!! we can NOT check flags.visited here since this will interact
3733 badly with when SMB handles (i.e. calls the subdissector)
3734 and desegmented pdu's .
3735 Instead we check if this pdu is already in the matched table or not
3737 matched_key.frame = pinfo->fd->num;
3738 matched_key.call_id = hdr->call_id;
3739 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
3740 if (!value) {
3741 dcerpc_bind_key bind_key;
3742 dcerpc_bind_value *bind_value;
3744 bind_key.conv = conv;
3745 bind_key.ctx_id = ctx_id;
3746 bind_key.smb_fid = dcerpc_get_transport_salt(pinfo);
3748 if ((bind_value = (dcerpc_bind_value *)g_hash_table_lookup(dcerpc_binds, &bind_key)) ) {
3749 if (!(hdr->flags&PFC_FIRST_FRAG)) {
3750 dcerpc_cn_call_key call_key;
3751 dcerpc_call_value *call_value;
3753 call_key.conv = conv;
3754 call_key.call_id = hdr->call_id;
3755 call_key.smb_fid = dcerpc_get_transport_salt(pinfo);
3756 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_cn_calls, &call_key))) {
3757 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
3758 *new_matched_key = matched_key;
3759 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
3760 value = call_value;
3762 } else {
3763 dcerpc_cn_call_key *call_key;
3764 dcerpc_call_value *call_value;
3766 /* We found the binding and it is the first fragment
3767 (or a complete PDU) of a dcerpc pdu so just add
3768 the call to both the call table and the
3769 matched table
3771 call_key = (dcerpc_cn_call_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_cn_call_key));
3772 call_key->conv = conv;
3773 call_key->call_id = hdr->call_id;
3774 call_key->smb_fid = dcerpc_get_transport_salt(pinfo);
3776 /* if there is already a matching call in the table
3777 remove it so it is replaced with the new one */
3778 if (g_hash_table_lookup(dcerpc_cn_calls, call_key)) {
3779 g_hash_table_remove(dcerpc_cn_calls, call_key);
3782 call_value = (dcerpc_call_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_call_value));
3783 call_value->uuid = bind_value->uuid;
3784 call_value->ver = bind_value->ver;
3785 call_value->object_uuid = obj_id;
3786 call_value->opnum = opnum;
3787 call_value->req_frame = pinfo->fd->num;
3788 call_value->req_time = pinfo->fd->abs_ts;
3789 call_value->rep_frame = 0;
3790 call_value->max_ptr = 0;
3791 call_value->se_data = NULL;
3792 call_value->private_data = NULL;
3793 call_value->pol = NULL;
3794 call_value->flags = 0;
3795 if (!memcmp(&bind_value->transport, &uuid_ndr64, sizeof(uuid_ndr64))) {
3796 call_value->flags |= DCERPC_IS_NDR64;
3799 g_hash_table_insert(dcerpc_cn_calls, call_key, call_value);
3801 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
3802 *new_matched_key = matched_key;
3803 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
3804 value = call_value;
3809 if (value) {
3810 dcerpc_info *di;
3812 di = get_next_di();
3813 /* handoff this call */
3814 di->conv = conv;
3815 di->call_id = hdr->call_id;
3816 di->smb_fid = dcerpc_get_transport_salt(pinfo);
3817 di->ptype = PDU_REQ;
3818 di->call_data = value;
3819 di->hf_index = -1;
3821 if (value->rep_frame != 0) {
3822 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
3823 tvb, 0, 0, value->rep_frame);
3824 PROTO_ITEM_SET_GENERATED(pi);
3825 if (parent_pi != NULL) {
3826 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
3830 dissect_dcerpc_cn_stub(tvb, offset, pinfo, dcerpc_tree, tree,
3831 hdr, di, &auth_info, alloc_hint,
3832 value->req_frame);
3833 } else {
3834 /* no bind information, simply show stub data */
3835 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);
3836 show_stub_data(tvb, offset, dcerpc_tree, &auth_info, TRUE);
3840 /* Dissect the verifier */
3841 dissect_dcerpc_verifier(tvb, pinfo, dcerpc_tree, hdr, &auth_info);
3845 static void
3846 dissect_dcerpc_cn_resp(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3847 proto_tree *dcerpc_tree, proto_tree *tree,
3848 e_dce_cn_common_hdr_t *hdr)
3850 dcerpc_call_value *value = NULL;
3851 conversation_t *conv;
3852 guint16 ctx_id;
3853 dcerpc_auth_info auth_info;
3854 guint32 alloc_hint;
3855 proto_item *pi;
3856 proto_item *parent_pi;
3857 e_uuid_t obj_id_null = DCERPC_UUID_NULL;
3859 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3860 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3862 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3863 hf_dcerpc_cn_ctx_id, &ctx_id);
3864 parent_pi = proto_tree_get_parent(dcerpc_tree);
3865 if (parent_pi != NULL) {
3866 proto_item_append_text(parent_pi, ", Ctx: %u", ctx_id);
3869 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3870 pinfo->dcectxid = ctx_id;
3872 col_append_fstr(pinfo->cinfo, COL_INFO, ", Ctx: %u", ctx_id);
3874 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3875 hf_dcerpc_cn_cancel_count, NULL);
3876 /* padding */
3877 offset++;
3880 * XXX - what if this was set when the connection was set up,
3881 * and we just have a security context?
3883 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3885 conv = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3886 pinfo->srcport, pinfo->destport, 0);
3888 if (!conv) {
3889 /* no point in creating one here, really */
3890 show_stub_data(tvb, offset, dcerpc_tree, &auth_info, TRUE);
3891 } else {
3892 dcerpc_matched_key matched_key, *new_matched_key;
3894 /* !!! we can NOT check flags.visited here since this will interact
3895 badly with when SMB handles (i.e. calls the subdissector)
3896 and desegmented pdu's .
3897 Instead we check if this pdu is already in the matched table or not
3899 matched_key.frame = pinfo->fd->num;
3900 matched_key.call_id = hdr->call_id;
3901 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
3902 if (!value) {
3903 dcerpc_cn_call_key call_key;
3904 dcerpc_call_value *call_value;
3906 call_key.conv = conv;
3907 call_key.call_id = hdr->call_id;
3908 call_key.smb_fid = dcerpc_get_transport_salt(pinfo);
3910 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_cn_calls, &call_key))) {
3911 /* extra sanity check, only match them if the reply
3912 came after the request */
3913 if (call_value->req_frame<pinfo->fd->num) {
3914 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
3915 *new_matched_key = matched_key;
3916 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
3917 value = call_value;
3918 if (call_value->rep_frame == 0) {
3919 call_value->rep_frame = pinfo->fd->num;
3925 if (value) {
3926 dcerpc_info *di;
3928 di = get_next_di();
3929 /* handoff this call */
3930 di->conv = conv;
3931 di->call_id = hdr->call_id;
3932 di->smb_fid = dcerpc_get_transport_salt(pinfo);
3933 di->ptype = PDU_RESP;
3934 di->call_data = value;
3936 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
3938 /* (optional) "Object UUID" from request */
3939 if (dcerpc_tree && (memcmp(&value->object_uuid, &obj_id_null, sizeof(obj_id_null)) != 0)) {
3940 pi = proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
3941 offset, 0, (e_guid_t *) &value->object_uuid, "Object UUID: %s",
3942 guid_to_str((e_guid_t *) &value->object_uuid));
3943 PROTO_ITEM_SET_GENERATED(pi);
3946 /* request in */
3947 if (value->req_frame != 0) {
3948 nstime_t delta_ts;
3949 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3950 tvb, 0, 0, value->req_frame);
3951 PROTO_ITEM_SET_GENERATED(pi);
3952 if (parent_pi != NULL) {
3953 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
3955 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
3956 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
3957 PROTO_ITEM_SET_GENERATED(pi);
3958 } else {
3959 proto_tree_add_expert(dcerpc_tree, pinfo, &ei_dcerpc_no_request_found, tvb, 0, 0);
3962 dissect_dcerpc_cn_stub(tvb, offset, pinfo, dcerpc_tree, tree,
3963 hdr, di, &auth_info, alloc_hint,
3964 value->rep_frame);
3965 } else {
3966 /* no bind information, simply show stub data */
3967 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);
3968 show_stub_data(tvb, offset, dcerpc_tree, &auth_info, TRUE);
3972 /* Dissect the verifier */
3973 dissect_dcerpc_verifier(tvb, pinfo, dcerpc_tree, hdr, &auth_info);
3976 static void
3977 dissect_dcerpc_cn_fault(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3978 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
3980 dcerpc_call_value *value = NULL;
3981 conversation_t *conv;
3982 guint16 ctx_id;
3983 guint32 status;
3984 guint32 alloc_hint;
3985 dcerpc_auth_info auth_info;
3986 proto_item *pi = NULL;
3988 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3989 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3991 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3992 hf_dcerpc_cn_ctx_id, &ctx_id);
3994 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3995 hf_dcerpc_cn_cancel_count, NULL);
3996 /* padding */
3997 offset++;
3999 #if 0
4000 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4001 hf_dcerpc_cn_status, &status);
4002 #endif
4003 status = ((hdr->drep[0] & DREP_LITTLE_ENDIAN)
4004 ? tvb_get_letohl(tvb, offset)
4005 : tvb_get_ntohl(tvb, offset));
4007 pi = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_status, tvb, offset, 4, DREP_ENC_INTEGER(hdr->drep));
4008 offset+=4;
4010 expert_add_info_format(pinfo, pi, &ei_dcerpc_cn_status, "Fault: %s", val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
4012 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
4013 pinfo->dcectxid = ctx_id;
4015 col_append_fstr(pinfo->cinfo, COL_INFO,
4016 ", Ctx: %u, status: %s", ctx_id,
4017 val_to_str(status, reject_status_vals,
4018 "Unknown (0x%08x)"));
4020 /* padding */
4021 offset += 4;
4024 * XXX - what if this was set when the connection was set up,
4025 * and we just have a security context?
4027 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
4029 conv = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
4030 pinfo->srcport, pinfo->destport, 0);
4031 if (!conv) {
4032 /* no point in creating one here, really */
4033 } else {
4034 dcerpc_matched_key matched_key, *new_matched_key;
4036 /* !!! we can NOT check flags.visited here since this will interact
4037 badly with when SMB handles (i.e. calls the subdissector)
4038 and desegmented pdu's .
4039 Instead we check if this pdu is already in the matched table or not
4041 matched_key.frame = pinfo->fd->num;
4042 matched_key.call_id = hdr->call_id;
4043 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
4044 if (!value) {
4045 dcerpc_cn_call_key call_key;
4046 dcerpc_call_value *call_value;
4048 call_key.conv = conv;
4049 call_key.call_id = hdr->call_id;
4050 call_key.smb_fid = dcerpc_get_transport_salt(pinfo);
4052 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_cn_calls, &call_key))) {
4053 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
4054 *new_matched_key = matched_key;
4055 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
4057 value = call_value;
4058 if (call_value->rep_frame == 0) {
4059 call_value->rep_frame = pinfo->fd->num;
4065 if (value) {
4066 int length, stub_length;
4067 dcerpc_info *di;
4068 proto_item *parent_pi;
4070 di = get_next_di();
4071 /* handoff this call */
4072 di->conv = conv;
4073 di->call_id = hdr->call_id;
4074 di->smb_fid = dcerpc_get_transport_salt(pinfo);
4075 di->ptype = PDU_FAULT;
4076 di->call_data = value;
4078 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
4079 if (value->req_frame != 0) {
4080 nstime_t delta_ts;
4081 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4082 tvb, 0, 0, value->req_frame);
4083 PROTO_ITEM_SET_GENERATED(pi);
4084 parent_pi = proto_tree_get_parent(dcerpc_tree);
4085 if (parent_pi != NULL) {
4086 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
4088 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
4089 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
4090 PROTO_ITEM_SET_GENERATED(pi);
4091 } else {
4092 proto_tree_add_expert(dcerpc_tree, pinfo, &ei_dcerpc_no_request_found, tvb, 0, 0);
4095 length = tvb_length_remaining(tvb, offset);
4096 /* as we now create a tvb in dissect_dcerpc_cn() containing only the
4097 * stub_data, the following calculation is no longer valid:
4098 * stub_length = hdr->frag_len - offset - auth_info.auth_size;
4099 * simply use the remaining length of the tvb instead.
4100 * XXX - or better use the reported_length?!?
4102 stub_length = length;
4103 if (length > stub_length)
4104 length = stub_length;
4106 /* If we don't have reassembly enabled, or this packet contains
4107 the entire PDU, or if we don't have all the data in this
4108 fragment, just call the handoff directly if this is the
4109 first fragment or the PDU isn't fragmented. */
4110 if ( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
4111 !tvb_bytes_exist(tvb, offset, stub_length) ) {
4112 if (hdr->flags&PFC_FIRST_FRAG) {
4113 /* First fragment, possibly the only fragment */
4115 * XXX - should there be a third routine for each
4116 * function in an RPC subdissector, to handle
4117 * fault responses? The DCE RPC 1.1 spec says
4118 * three's "stub data" here, which I infer means
4119 * that it's protocol-specific and call-specific.
4121 * It should probably get passed the status code
4122 * as well, as that might be protocol-specific.
4124 if (dcerpc_tree) {
4125 if (stub_length > 0) {
4126 tvb_ensure_bytes_exist(tvb, offset, stub_length);
4127 proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
4128 "Fault stub data (%d byte%s)",
4129 stub_length,
4130 plurality(stub_length, "", "s"));
4133 } else {
4134 /* PDU is fragmented and this isn't the first fragment */
4135 if (dcerpc_tree) {
4136 if (stub_length > 0) {
4137 tvb_ensure_bytes_exist(tvb, offset, stub_length);
4138 proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
4139 "Fragment data (%d byte%s)",
4140 stub_length,
4141 plurality(stub_length, "", "s"));
4145 } else {
4146 /* Reassembly is enabled, the PDU is fragmented, and
4147 we have all the data in the fragment; the first two
4148 of those mean we should attempt reassembly, and the
4149 third means we can attempt reassembly. */
4150 if (dcerpc_tree) {
4151 if (length > 0) {
4152 tvb_ensure_bytes_exist(tvb, offset, stub_length);
4153 proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
4154 "Fragment data (%d byte%s)",
4155 stub_length,
4156 plurality(stub_length, "", "s"));
4159 if (hdr->flags&PFC_FIRST_FRAG) { /* FIRST fragment */
4160 if ( (!pinfo->fd->flags.visited) && value->rep_frame ) {
4161 fragment_add_seq_next(&dcerpc_co_reassembly_table,
4162 tvb, offset,
4163 pinfo, value->rep_frame, NULL,
4164 stub_length,
4165 TRUE);
4167 } else if (hdr->flags&PFC_LAST_FRAG) { /* LAST fragment */
4168 if ( value->rep_frame ) {
4169 fragment_head *fd_head;
4171 fd_head = fragment_add_seq_next(&dcerpc_co_reassembly_table,
4172 tvb, offset,
4173 pinfo, value->rep_frame, NULL,
4174 stub_length,
4175 TRUE);
4177 if (fd_head) {
4178 /* We completed reassembly */
4179 tvbuff_t *next_tvb;
4180 proto_item *frag_tree_item;
4182 next_tvb = tvb_new_chain(tvb, fd_head->tvb_data);
4183 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
4184 show_fragment_tree(fd_head, &dcerpc_frag_items,
4185 dcerpc_tree, pinfo, next_tvb, &frag_tree_item);
4188 * XXX - should there be a third routine for each
4189 * function in an RPC subdissector, to handle
4190 * fault responses? The DCE RPC 1.1 spec says
4191 * three's "stub data" here, which I infer means
4192 * that it's protocol-specific and call-specific.
4194 * It should probably get passed the status code
4195 * as well, as that might be protocol-specific.
4197 if (dcerpc_tree) {
4198 if (length > 0) {
4199 tvb_ensure_bytes_exist(tvb, offset, stub_length);
4200 proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
4201 "Fault stub data (%d byte%s)",
4202 stub_length,
4203 plurality(stub_length, "", "s"));
4208 } else { /* MIDDLE fragment(s) */
4209 if ( (!pinfo->fd->flags.visited) && value->rep_frame ) {
4210 fragment_add_seq_next(&dcerpc_co_reassembly_table,
4211 tvb, offset,
4212 pinfo, value->rep_frame, NULL,
4213 stub_length,
4214 TRUE);
4222 static void
4223 dissect_dcerpc_cn_rts(tvbuff_t *tvb, gint offset, packet_info *pinfo,
4224 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
4226 proto_item *tf = NULL;
4227 proto_item *parent_pi = NULL;
4228 proto_tree *cn_rts_pdu_tree = NULL;
4229 guint16 rts_flags;
4230 guint16 commands_nb = 0;
4231 guint32 *cmd;
4232 guint32 i;
4233 const char *info_str = NULL;
4235 /* Dissect specific RTS header */
4236 rts_flags = dcerpc_tvb_get_ntohs(tvb, offset, hdr->drep);
4237 if (dcerpc_tree) {
4238 proto_tree *cn_rts_flags_tree;
4240 tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_rts_flags, tvb, offset, 2, rts_flags);
4241 cn_rts_flags_tree = proto_item_add_subtree(tf, ett_dcerpc_cn_rts_flags);
4242 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_none, tvb, offset, 1, rts_flags);
4243 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_ping, tvb, offset, 1, rts_flags);
4244 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_other_cmd, tvb, offset, 1, rts_flags);
4245 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_recycle_channel, tvb, offset, 1, rts_flags);
4246 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_in_channel, tvb, offset, 1, rts_flags);
4247 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_out_channel, tvb, offset, 1, rts_flags);
4248 proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_eof, tvb, offset, 1, rts_flags);
4250 offset += 2;
4252 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4253 hf_dcerpc_cn_rts_commands_nb, &commands_nb);
4255 /* Create the RTS PDU tree - we do not yet know its name */
4256 tf = proto_tree_add_text(dcerpc_tree, tvb, offset, tvb_length_remaining(tvb, offset), "RTS PDU: %u commands", commands_nb);
4257 cn_rts_pdu_tree = proto_item_add_subtree(tf, ett_dcerpc_cn_rts_pdu);
4259 cmd = (guint32 *)wmem_alloc(wmem_packet_scope(), sizeof (guint32) * (commands_nb + 1));
4261 /* Dissect commands */
4262 for (i = 0; i < commands_nb; ++i) {
4263 proto_tree *cn_rts_command_tree = NULL;
4264 const guint32 command = dcerpc_tvb_get_ntohl(tvb, offset, hdr->drep);
4265 cmd[i] = command;
4266 tf = proto_tree_add_uint(cn_rts_pdu_tree, hf_dcerpc_cn_rts_command, tvb, offset, 4, command);
4267 cn_rts_command_tree = proto_item_add_subtree(tf, ett_dcerpc_cn_rts_command);
4268 offset += 4;
4269 switch (command) {
4270 case RTS_CMD_RECEIVEWINDOWSIZE:
4271 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_receivewindowsize, NULL);
4272 break;
4273 case RTS_CMD_FLOWCONTROLACK:
4274 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_fack_bytesreceived, NULL);
4275 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_fack_availablewindow, NULL);
4276 offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_fack_channelcookie, NULL);
4277 break;
4278 case RTS_CMD_CONNECTIONTIMEOUT:
4279 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_connectiontimeout, NULL);
4280 break;
4281 case RTS_CMD_COOKIE:
4282 offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_cookie, NULL);
4283 break;
4284 case RTS_CMD_CHANNELLIFETIME:
4285 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_channellifetime, NULL);
4286 break;
4287 case RTS_CMD_CLIENTKEEPALIVE:
4288 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_clientkeepalive, NULL);
4289 break;
4290 case RTS_CMD_VERSION:
4291 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_version, NULL);
4292 break;
4293 case RTS_CMD_EMPTY:
4294 break;
4295 case RTS_CMD_PADDING: {
4296 guint8 *padding;
4297 const guint32 conformance_count = dcerpc_tvb_get_ntohl(tvb, offset, hdr->drep);
4298 proto_tree_add_uint(cn_rts_command_tree, hf_dcerpc_cn_rts_command_conformancecount, tvb, offset, 4, conformance_count);
4299 offset += 4;
4300 padding = (guint8 *)tvb_memdup(NULL, tvb, offset, conformance_count);
4301 proto_tree_add_bytes(cn_rts_command_tree, hf_dcerpc_cn_rts_command_padding, tvb, offset, conformance_count, padding);
4302 offset += conformance_count;
4303 } break;
4304 case RTS_CMD_NEGATIVEANCE:
4305 break;
4306 case RTS_CMD_ANCE:
4307 break;
4308 case RTS_CMD_CLIENTADDRESS: {
4309 guint8 *padding;
4310 const guint32 addrtype = dcerpc_tvb_get_ntohl(tvb, offset, hdr->drep);
4311 proto_tree_add_uint(cn_rts_command_tree, hf_dcerpc_cn_rts_command_addrtype, tvb, offset, 4, addrtype);
4312 offset += 4;
4313 switch (addrtype) {
4314 case RTS_IPV4: {
4315 const guint32 addr4 = tvb_get_ipv4(tvb, offset);
4316 proto_tree_add_text(cn_rts_command_tree, tvb, offset, 4, "%s", get_hostname(addr4));
4317 offset += 4;
4318 } break;
4319 case RTS_IPV6: {
4320 struct e_in6_addr addr6;
4321 tvb_get_ipv6(tvb, offset, &addr6);
4322 proto_tree_add_text(cn_rts_command_tree, tvb, offset, 16, "%s", get_hostname6(&addr6));
4323 offset += 16;
4324 } break;
4326 padding = (guint8 *)tvb_memdup(NULL, tvb, offset, 12);
4327 proto_tree_add_bytes(cn_rts_command_tree, hf_dcerpc_cn_rts_command_padding, tvb, offset, 12, padding);
4328 offset += 12;
4329 } break;
4330 case RTS_CMD_ASSOCIATIONGROUPID:
4331 offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_associationgroupid, NULL);
4332 break;
4333 case RTS_CMD_DESTINATION:
4334 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_forwarddestination, NULL);
4335 break;
4336 case RTS_CMD_PINGTRAFFICSENTNOTIFY:
4337 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_pingtrafficsentnotify, NULL);
4338 break;
4339 default:
4340 proto_tree_add_text(cn_rts_command_tree, tvb, offset, 0, "unknown RTS command number");
4341 break;
4345 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RPCH");
4347 /* Define which PDU Body we are dealing with */
4348 info_str = "unknown RTS PDU";
4350 switch (rts_flags) {
4351 case RTS_FLAG_NONE:
4352 switch (commands_nb) {
4353 case 1:
4354 if (cmd[0] == 0x2) {
4355 info_str = "CONN/A3";
4356 } else if (cmd[0] == 0x3) {
4357 info_str = "IN_R1/A5,IN_R1/A6,IN_R2/A2,IN_R2/A5,OUT_R2/A4";
4358 } else if (cmd[0] == 0x7) {
4359 info_str = "IN_R1/B1";
4360 } else if (cmd[0] == 0x0) {
4361 info_str = "IN_R1/B2";
4362 } else if (cmd[0] == 0xD) {
4363 info_str = "IN_R2/A3,IN_R2/A4";
4364 } else if (cmd[0] == 0xA) {
4365 info_str = "OUT_R1/A9,OUT_R1/A10,OUT_R1/A11,OUT_R2/B1,OUT_R2/B2";
4367 break;
4368 case 2:
4369 if ((cmd[0] == 0x0) && (cmd[1] == 0x6)) {
4370 info_str = "CONN/B3";
4371 } else if ((cmd[0] == 0xD) && (cmd[1] == 0xA)) {
4372 info_str = "OUT_R2/A5,OUT_R2/A6";
4374 break;
4375 case 3:
4376 if ((cmd[0] == 0x6) && (cmd[1] == 0x0) && (cmd[2] == 0x2)) {
4377 info_str = "CONN/C1,CONN/C2";
4379 break;
4380 case 4:
4381 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x0)) {
4382 info_str = "CONN/A1";
4383 } else if ((cmd[0] == 0xD) && (cmd[1] == 0x6) && (cmd[2] == 0x0) && (cmd[3] == 0x2)) {
4384 info_str = "IN_R1/A3,IN_R1/A4";
4386 break;
4387 case 6:
4388 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x4) && (cmd[4] == 0x5) && (cmd[5] == 0xC)) {
4389 info_str = "CONN/B1";
4391 break;
4392 default:
4393 break;
4395 break;
4396 case RTS_FLAG_PING:
4397 switch (commands_nb) {
4398 case 0:
4399 info_str = "Ping";
4400 break;
4401 case 1:
4402 if ((cmd[0] == 0x7) || (cmd[0] == 0x8)) {
4403 info_str = "OUT_R2/C1";
4405 break;
4406 default:
4407 break;
4409 break;
4410 case RTS_FLAG_OTHER_CMD:
4411 switch (commands_nb) {
4412 case 1:
4413 if (cmd[0] == 0x5) {
4414 info_str = "Keep-Alive";
4415 } else if (cmd[0] == 0xE) {
4416 info_str = "PingTrafficSentNotify";
4417 } else if (cmd[0] == 0x1) {
4418 info_str = "FlowControlAck";
4420 break;
4421 case 2:
4422 if ((cmd[0] == 0xD) && (cmd[1] == 0x1)) {
4423 info_str = "FlowControlAckWithDestination";
4425 break;
4426 default:
4427 break;
4429 break;
4430 case RTS_FLAG_RECYCLE_CHANNEL:
4431 switch (commands_nb) {
4432 case 1:
4433 if (cmd[0] == 0xD) {
4434 info_str = "OUT_R1/A1,OUT_R1/A2,OUT_R2/A1,OUT_R2/A2";
4436 break;
4437 case 4:
4438 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3)) {
4439 info_str = "IN_R1/A1,IN_R2/A1";
4441 break;
4442 case 5:
4443 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3) && (cmd[4] == 0x0)) {
4444 info_str = "OUT_R1/A3,OUT_R2/A3";
4446 break;
4447 default:
4448 break;
4450 break;
4451 case RTS_FLAG_IN_CHANNEL|RTS_FLAG_RECYCLE_CHANNEL:
4452 switch (commands_nb) {
4453 case 6:
4454 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3) && (cmd[4] == 0x0) && (cmd[5] == 0x2)) {
4455 info_str = "IN_R1/A2";
4457 break;
4458 default:
4459 break;
4461 case RTS_FLAG_IN_CHANNEL:
4462 switch (commands_nb) {
4463 case 7:
4464 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x0) && (cmd[4] == 0x2) && (cmd[5] == 0xC) && (cmd[6] == 0xB)) {
4465 info_str = "CONN/B2";
4467 break;
4468 default:
4469 break;
4471 case RTS_FLAG_OUT_CHANNEL|RTS_FLAG_RECYCLE_CHANNEL:
4472 switch (commands_nb) {
4473 case 7:
4474 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3) && (cmd[4] == 0x4) && (cmd[5] == 0) && (cmd[6] == 0x2)) {
4475 info_str = "OUT_R1/A4";
4477 break;
4478 default:
4479 break;
4481 break;
4482 case RTS_FLAG_OUT_CHANNEL:
4483 switch (commands_nb) {
4484 case 2:
4485 if ((cmd[0] == 0xD) && (cmd[1] == 0x3)) {
4486 info_str = "OUT_R1/A7,OUT_R1/A8,OUT_R2/A8";
4488 break;
4489 case 3:
4490 if ((cmd[0] == 0xD) && (cmd[1] == 0x6) && (cmd[2] == 0x2)) {
4491 info_str = "OUT_R1/A5,OUT_R1/A6";
4492 } else if ((cmd[0] == 0xD) && (cmd[1] == 0x3) && (cmd[2] == 0x6)) {
4493 info_str = "OUT_R2/A7";
4495 break;
4496 case 5:
4497 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x4) && (cmd[4] == 0x0)) {
4498 info_str = "CONN/A2";
4500 break;
4501 default:
4502 break;
4504 case RTS_FLAG_EOF:
4505 switch (commands_nb) {
4506 case 1:
4507 if (cmd[0] == 0xA) {
4508 info_str = "OUT_R2/B3";
4510 break;
4511 default:
4512 break;
4514 break;
4515 case RTS_FLAG_ECHO:
4516 switch (commands_nb) {
4517 case 0:
4518 info_str = "Echo";
4519 break;
4520 default:
4521 break;
4523 break;
4524 default:
4525 break;
4528 col_add_fstr(pinfo->cinfo, COL_INFO, "%s, ", info_str);
4529 col_set_fence(pinfo->cinfo,COL_INFO);
4531 parent_pi = proto_tree_get_parent(dcerpc_tree);
4532 if (parent_pi != NULL) {
4533 proto_item_append_text(parent_pi, ", %s", info_str);
4538 * DCERPC dissector for connection oriented calls.
4539 * We use transport type to later multiplex between what kind of
4540 * pinfo->private_data structure to expect.
4542 static gboolean
4543 dissect_dcerpc_cn(tvbuff_t *tvb, int offset, packet_info *pinfo,
4544 proto_tree *tree, gboolean can_desegment, int *pkt_len)
4546 static const guint8 nulls[4] = { 0 };
4547 int start_offset;
4548 int padding = 0;
4549 int subtvb_len = 0;
4550 proto_item *ti = NULL;
4551 proto_item *tf = NULL;
4552 proto_tree *dcerpc_tree = NULL;
4553 proto_tree *cn_flags_tree = NULL;
4554 proto_tree *drep_tree = NULL;
4555 e_dce_cn_common_hdr_t hdr;
4556 dcerpc_auth_info auth_info;
4557 tvbuff_t *fragment_tvb;
4560 * when done over nbt, dcerpc requests are padded with 4 bytes of null
4561 * data for some reason.
4563 * XXX - if that's always the case, the right way to do this would
4564 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
4565 * the 4 bytes of null padding, and make that the dissector
4566 * used for "netbios".
4568 if (tvb_memeql(tvb, offset, nulls, 4) == 0) {
4571 * Skip the padding.
4573 offset += 4;
4574 padding += 4;
4577 * Check if this looks like a C/O DCERPC call
4579 if (!tvb_bytes_exist(tvb, offset, sizeof (hdr))) {
4580 return FALSE; /* not enough information to check */
4582 start_offset = offset;
4583 hdr.rpc_ver = tvb_get_guint8(tvb, offset++);
4584 if (hdr.rpc_ver != 5)
4585 return FALSE;
4586 hdr.rpc_ver_minor = tvb_get_guint8(tvb, offset++);
4587 if ((hdr.rpc_ver_minor != 0) && (hdr.rpc_ver_minor != 1))
4588 return FALSE;
4589 hdr.ptype = tvb_get_guint8(tvb, offset++);
4590 if (hdr.ptype > PDU_RTS)
4591 return FALSE;
4593 hdr.flags = tvb_get_guint8(tvb, offset++);
4594 tvb_memcpy(tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
4595 offset += (int)sizeof (hdr.drep);
4597 hdr.frag_len = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
4598 offset += 2;
4599 hdr.auth_len = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
4600 offset += 2;
4601 hdr.call_id = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
4602 /*offset += 4;*/
4604 if (pinfo->dcectxid == 0) {
4605 col_append_fstr(pinfo->cinfo, COL_DCE_CALL, "%u", hdr.call_id);
4606 } else {
4607 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
4608 * prepend a delimiter */
4609 col_append_fstr(pinfo->cinfo, COL_DCE_CALL, "#%u", hdr.call_id);
4612 if (can_desegment && pinfo->can_desegment
4613 && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
4614 pinfo->desegment_offset = start_offset;
4615 pinfo->desegment_len = hdr.frag_len - tvb_length_remaining(tvb, start_offset);
4616 *pkt_len = 0; /* desegmentation required */
4617 return TRUE;
4620 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCERPC");
4622 if (pinfo->dcectxid != 0) {
4623 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
4624 * append a delimiter and set a column fence */
4625 col_append_str(pinfo->cinfo, COL_INFO, " # ");
4626 col_set_fence(pinfo->cinfo,COL_INFO);
4628 col_add_fstr(pinfo->cinfo, COL_INFO, "%s: call_id: %u",
4629 pckt_vals[hdr.ptype].strptr, hdr.call_id);
4631 if (pinfo->dcectxid != 0) {
4632 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU */
4633 expert_add_info(pinfo, NULL, &ei_dcerpc_fragment_multiple);
4636 offset = start_offset;
4637 tvb_ensure_bytes_exist(tvb, offset, 16);
4638 if (tree) {
4639 ti = proto_tree_add_item(tree, proto_dcerpc, tvb, offset, hdr.frag_len, ENC_NA);
4640 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
4643 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
4644 offset++;
4646 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset, 1, hdr.rpc_ver_minor);
4647 offset++;
4649 tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
4650 offset++;
4652 #if 0 /* XXX - too much "output noise", removed for now */
4653 if (hdr.ptype == PDU_BIND || hdr.ptype == PDU_ALTER ||
4654 hdr.ptype == PDU_BIND_ACK || hdr.ptype == PDU_ALTER_ACK)
4655 expert_add_info_format(pinfo, tf, &ei_dcerpc_context_change, "Context change: %s", val_to_str(hdr.ptype, pckt_vals, "(0x%x)"));
4656 #endif
4657 if (hdr.ptype == PDU_BIND_NAK)
4658 expert_add_info(pinfo, tf, &ei_dcerpc_bind_not_acknowledged);
4660 if (tree) {
4661 proto_item_append_text(ti, " %s, Fragment: %s",
4662 val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"),
4663 fragment_type(hdr.flags));
4665 tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
4666 cn_flags_tree = proto_item_add_subtree(tf, ett_dcerpc_cn_flags);
4668 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
4669 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
4670 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
4671 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
4672 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
4673 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
4674 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
4675 proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
4676 offset++;
4678 col_append_fstr(pinfo->cinfo, COL_INFO, ", Fragment: %s", fragment_type(hdr.flags));
4680 if (dcerpc_tree) {
4681 tf = proto_tree_add_bytes(dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
4682 drep_tree = proto_item_add_subtree(tf, ett_dcerpc_drep);
4684 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
4685 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
4686 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
4687 offset += (int)sizeof (hdr.drep);
4689 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
4690 offset += 2;
4692 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
4693 offset += 2;
4695 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
4696 offset += 4;
4698 if (ti) {
4699 proto_item_append_text(ti, ", FragLen: %u, Call: %u", hdr.frag_len, hdr.call_id);
4703 * None of the stuff done above should throw an exception, because
4704 * we would have rejected this as "not DCE RPC" if we didn't have all
4705 * of it. (XXX - perhaps we should request reassembly if we have
4706 * enough of the header to consider it DCE RPC but not enough to
4707 * get the fragment length; in that case the stuff still wouldn't
4708 * throw an exception.)
4710 * The rest of the stuff might, so return the PDU length to our caller.
4711 * XXX - should we construct a tvbuff containing only the PDU and
4712 * use that? Or should we have separate "is this a DCE RPC PDU",
4713 * "how long is it", and "dissect it" routines - which might let us
4714 * do most of the work in "tcp_dissect_pdus()"?
4716 if (pkt_len != NULL)
4717 *pkt_len = hdr.frag_len + padding;
4719 /* The remaining bytes in the current tvb might contain multiple
4720 * DCE/RPC fragments, so create a new tvb subset for this fragment.
4721 * Only limit the end of the fragment, but not the offset start,
4722 * as the authentication function dissect_dcerpc_cn_auth() will fail
4723 * (and other functions might fail as well) computing the right start
4724 * offset otherwise.
4726 subtvb_len = MIN(hdr.frag_len, tvb_length(tvb));
4727 fragment_tvb = tvb_new_subset(tvb, start_offset,
4728 subtvb_len /* length */,
4729 hdr.frag_len /* reported_length */);
4732 * Packet type specific stuff is next.
4734 switch (hdr.ptype) {
4735 case PDU_BIND:
4736 case PDU_ALTER:
4737 dissect_dcerpc_cn_bind(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
4738 break;
4740 case PDU_BIND_ACK:
4741 case PDU_ALTER_ACK:
4742 dissect_dcerpc_cn_bind_ack(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
4743 break;
4745 case PDU_AUTH3:
4747 * Nothing after the common header other than credentials.
4749 dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr, TRUE,
4750 &auth_info);
4751 break;
4753 case PDU_REQ:
4754 dissect_dcerpc_cn_rqst(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, tree, &hdr);
4755 break;
4757 case PDU_RESP:
4758 dissect_dcerpc_cn_resp(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, tree, &hdr);
4759 break;
4761 case PDU_FAULT:
4762 dissect_dcerpc_cn_fault(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
4763 break;
4765 case PDU_BIND_NAK:
4766 dissect_dcerpc_cn_bind_nak(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
4767 break;
4769 case PDU_CO_CANCEL:
4770 case PDU_ORPHANED:
4772 * Nothing after the common header other than an authentication
4773 * verifier.
4775 dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr, FALSE,
4776 &auth_info);
4777 break;
4779 case PDU_SHUTDOWN:
4781 * Nothing after the common header, not even an authentication
4782 * verifier.
4784 break;
4785 case PDU_RTS:
4786 dissect_dcerpc_cn_rts(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
4787 break;
4789 default:
4790 /* might as well dissect the auth info */
4791 dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr, FALSE,
4792 &auth_info);
4793 break;
4795 return TRUE;
4799 * DCERPC dissector for connection oriented calls over packet-oriented
4800 * transports
4802 static gboolean
4803 dissect_dcerpc_cn_pk(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
4806 * Only one PDU per transport packet, and only one transport
4807 * packet per PDU.
4809 pinfo->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
4810 if (!dissect_dcerpc_cn(tvb, 0, pinfo, tree, FALSE, NULL)) {
4812 * It wasn't a DCERPC PDU.
4814 return FALSE;
4815 } else {
4817 * It was.
4819 return TRUE;
4824 * DCERPC dissector for connection oriented calls over byte-stream
4825 * transports.
4826 * we need to distinguish here between SMB and non-TCP (more in the future?)
4827 * to be able to know what kind of private_data structure to expect.
4829 static gboolean
4830 dissect_dcerpc_cn_bs_body(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4832 volatile int offset = 0;
4833 int pdu_len = 0;
4834 volatile int dcerpc_pdus = 0;
4835 volatile gboolean ret = FALSE;
4838 * There may be multiple PDUs per transport packet; keep
4839 * processing them.
4841 while (tvb_reported_length_remaining(tvb, offset) != 0) {
4842 TRY {
4843 pdu_len = 0;
4844 if (dissect_dcerpc_cn(tvb, offset, pinfo, tree,
4845 dcerpc_cn_desegment, &pdu_len)) {
4846 dcerpc_pdus++;
4848 } CATCH_NONFATAL_ERRORS {
4850 * Somebody threw an exception that means that there
4851 * was a problem dissecting the payload; that means
4852 * that a dissector was found, so we don't need to
4853 * dissect the payload as data or update the protocol
4854 * or info columns.
4856 * Just show the exception and then continue dissecting
4857 * PDUs.
4859 show_exception(tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
4861 * Presumably it looked enough like a DCE RPC PDU that we
4862 * dissected enough of it to throw an exception.
4864 dcerpc_pdus++;
4865 } ENDTRY;
4867 if (dcerpc_pdus == 0) {
4868 gboolean try_desegment = FALSE;
4869 if (dcerpc_cn_desegment && pinfo->can_desegment &&
4870 !tvb_bytes_exist(tvb, offset, sizeof(e_dce_cn_common_hdr_t))) {
4871 /* look for a previous occurence of the DCE-RPC protocol */
4872 wmem_list_frame_t *cur;
4873 cur = wmem_list_frame_prev(wmem_list_tail(pinfo->layers));
4874 while (cur != NULL) {
4875 if (proto_dcerpc == (gint)GPOINTER_TO_UINT(wmem_list_frame_data(cur))) {
4876 try_desegment = TRUE;
4877 break;
4879 cur = wmem_list_frame_prev(cur);
4883 if (try_desegment) {
4884 /* It didn't look like DCE-RPC but we already had one DCE-RPC
4885 * layer in this packet and what we have is short. Assume that
4886 * it was just too short to tell and ask the TCP layer for more
4887 * data. */
4888 pinfo->desegment_offset = offset;
4889 pinfo->desegment_len = (guint32)(sizeof(e_dce_cn_common_hdr_t) - tvb_length_remaining(tvb, offset));
4890 } else {
4891 /* Really not DCE-RPC */
4892 break;
4897 * Well, we've seen at least one DCERPC PDU.
4899 ret = TRUE;
4901 /* if we had more than one Req/Resp in this PDU change the protocol column */
4902 /* this will formerly contain the last interface name, which may not be the same for all Req/Resp */
4903 if (dcerpc_pdus >= 2)
4904 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "%u*DCERPC", dcerpc_pdus);
4906 if (pdu_len == 0) {
4908 * Desegmentation required - bail now, but give the user a hint that desegmentation might be done later.
4910 proto_tree_add_uint_format(tree, hf_dcerpc_cn_deseg_req, tvb, offset,
4912 tvb_reported_length_remaining(tvb, offset),
4913 "[DCE RPC: %u byte%s left, desegmentation might follow]",
4914 tvb_reported_length_remaining(tvb, offset),
4915 plurality(tvb_reported_length_remaining(tvb, offset), "", "s"));
4916 break;
4920 * Step to the next PDU.
4922 offset += pdu_len;
4924 return ret;
4927 static gboolean
4928 dissect_dcerpc_cn_bs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
4930 pinfo->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
4931 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
4934 static gboolean
4935 dissect_dcerpc_cn_smbpipe(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
4937 pinfo->dcetransporttype = DCE_CN_TRANSPORT_SMBPIPE;
4938 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
4941 static gboolean
4942 dissect_dcerpc_cn_smb2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
4944 pinfo->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
4945 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
4950 static void
4951 dissect_dcerpc_dg_auth(tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
4952 e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
4954 proto_item *ti = NULL;
4955 proto_tree *auth_tree = NULL;
4956 guint8 protection_level;
4959 * Initially set "*auth_level_p" to -1 to indicate that we haven't
4960 * yet seen any authentication level information.
4962 if (auth_level_p != NULL)
4963 *auth_level_p = -1;
4966 * The authentication information is at the *end* of the PDU; in
4967 * request and response PDUs, the request and response stub data
4968 * come before it.
4970 * If the full packet is here, and there's data past the end of the
4971 * packet body, then dissect the auth info.
4973 offset += hdr->frag_len;
4974 if (tvb_length_remaining(tvb, offset) > 0) {
4975 switch (hdr->auth_proto) {
4977 case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
4978 ti = proto_tree_add_text(dcerpc_tree, tvb, offset, -1, "Kerberos authentication verifier");
4979 auth_tree = proto_item_add_subtree(ti, ett_dcerpc_krb5_auth_verf);
4980 protection_level = tvb_get_guint8(tvb, offset);
4981 if (auth_level_p != NULL)
4982 *auth_level_p = protection_level;
4983 proto_tree_add_uint(auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
4984 offset++;
4985 proto_tree_add_item(auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, ENC_BIG_ENDIAN);
4986 offset++;
4987 if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
4988 offset += 6; /* 6 bytes of padding */
4989 else
4990 offset += 2; /* 2 bytes of padding */
4991 proto_tree_add_item(auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, ENC_NA);
4992 /*offset += 16;*/
4993 break;
4995 default:
4996 proto_tree_add_text(dcerpc_tree, tvb, offset, -1, "Authentication verifier");
4997 break;
5002 static void
5003 dissect_dcerpc_dg_cancel_ack(tvbuff_t *tvb, int offset, packet_info *pinfo,
5004 proto_tree *dcerpc_tree,
5005 e_dce_dg_common_hdr_t *hdr)
5007 guint32 version;
5009 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5010 hdr->drep, hf_dcerpc_dg_cancel_vers,
5011 &version);
5013 switch (version) {
5015 case 0:
5016 /* The only version we know about */
5017 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5018 hdr->drep, hf_dcerpc_dg_cancel_id,
5019 NULL);
5020 /*offset = */dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
5021 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
5022 NULL);
5023 break;
5027 static void
5028 dissect_dcerpc_dg_cancel(tvbuff_t *tvb, int offset, packet_info *pinfo,
5029 proto_tree *dcerpc_tree,
5030 e_dce_dg_common_hdr_t *hdr)
5032 guint32 version;
5034 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5035 hdr->drep, hf_dcerpc_dg_cancel_vers,
5036 &version);
5038 switch (version) {
5040 case 0:
5041 /* The only version we know about */
5042 /*offset = */dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5043 hdr->drep, hf_dcerpc_dg_cancel_id,
5044 NULL);
5045 /* XXX - are NDR Booleans 32 bits? */
5047 /* XXX - the RPC reference in chapter: "the cancel PDU" doesn't mention
5048 the accepting_cancels field (it's only in the cancel_ack PDU)! */
5049 /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
5050 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
5051 NULL);*/
5052 break;
5056 static void
5057 dissect_dcerpc_dg_fack(tvbuff_t *tvb, int offset, packet_info *pinfo,
5058 proto_tree *dcerpc_tree,
5059 e_dce_dg_common_hdr_t *hdr)
5061 guint8 version;
5062 guint16 serial_num;
5063 guint16 selack_len;
5064 guint i;
5066 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
5067 hdr->drep, hf_dcerpc_dg_fack_vers,
5068 &version);
5069 /* padding */
5070 offset++;
5072 switch (version) {
5074 case 0: /* The only version documented in the DCE RPC 1.1 spec */
5075 case 1: /* This appears to be the same */
5076 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
5077 hdr->drep, hf_dcerpc_dg_fack_window_size,
5078 NULL);
5079 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5080 hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
5081 NULL);
5082 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5083 hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
5084 NULL);
5085 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
5086 hdr->drep, hf_dcerpc_dg_fack_serial_num,
5087 &serial_num);
5088 col_append_fstr(pinfo->cinfo, COL_INFO, " serial: %u",
5089 serial_num);
5090 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
5091 hdr->drep, hf_dcerpc_dg_fack_selack_len,
5092 &selack_len);
5093 for (i = 0; i < selack_len; i++) {
5094 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5095 hdr->drep, hf_dcerpc_dg_fack_selack,
5096 NULL);
5099 break;
5103 static void
5104 dissect_dcerpc_dg_reject_fault(tvbuff_t *tvb, int offset, packet_info *pinfo,
5105 proto_tree *dcerpc_tree,
5106 e_dce_dg_common_hdr_t *hdr)
5108 guint32 status;
5110 /*offset = */dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5111 hdr->drep, hf_dcerpc_dg_status,
5112 &status);
5114 col_append_fstr (pinfo->cinfo, COL_INFO,
5115 ": status: %s",
5116 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
5119 static void
5120 dissect_dcerpc_dg_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
5121 proto_tree *dcerpc_tree, proto_tree *tree,
5122 e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
5124 int length, reported_length, stub_length;
5125 gboolean save_fragmented;
5126 fragment_head *fd_head;
5127 tvbuff_t *next_tvb;
5128 proto_item *pi;
5129 proto_item *parent_pi;
5131 col_append_fstr(pinfo->cinfo, COL_INFO, " opnum: %u len: %u",
5132 di->call_data->opnum, hdr->frag_len );
5134 length = tvb_length_remaining(tvb, offset);
5135 reported_length = tvb_reported_length_remaining(tvb, offset);
5136 stub_length = hdr->frag_len;
5137 if (length > stub_length)
5138 length = stub_length;
5139 if (reported_length > stub_length)
5140 reported_length = stub_length;
5142 save_fragmented = pinfo->fragmented;
5144 /* If we don't have reassembly enabled, or this packet contains
5145 the entire PDU, or if this is a short frame (or a frame
5146 not reassembled at a lower layer) that doesn't include all
5147 the data in the fragment, just call the handoff directly if
5148 this is the first fragment or the PDU isn't fragmented. */
5149 if ( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
5150 !tvb_bytes_exist(tvb, offset, stub_length) ) {
5151 if (hdr->frag_num == 0) {
5154 /* First fragment, possibly the only fragment */
5157 * XXX - authentication info?
5159 pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
5160 next_tvb = tvb_new_subset(tvb, offset, length,
5161 reported_length);
5162 dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb,
5163 next_tvb, hdr->drep, di, NULL);
5164 } else {
5165 /* PDU is fragmented and this isn't the first fragment */
5166 if (dcerpc_tree) {
5167 if (length > 0) {
5168 tvb_ensure_bytes_exist(tvb, offset, stub_length);
5169 proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
5170 "Fragment data (%d byte%s)",
5171 stub_length,
5172 plurality(stub_length, "", "s"));
5176 } else {
5177 /* Reassembly is enabled, the PDU is fragmented, and
5178 we have all the data in the fragment; the first two
5179 of those mean we should attempt reassembly, and the
5180 third means we can attempt reassembly. */
5181 if (dcerpc_tree) {
5182 if (length > 0) {
5183 tvb_ensure_bytes_exist(tvb, offset, stub_length);
5184 proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
5185 "Fragment data (%d byte%s)", stub_length,
5186 plurality(stub_length, "", "s"));
5190 fd_head = fragment_add_seq(&dcerpc_cl_reassembly_table,
5191 tvb, offset,
5192 pinfo, hdr->seqnum, (void *)hdr,
5193 hdr->frag_num, stub_length,
5194 !(hdr->flags1 & PFCL1_LASTFRAG), 0);
5195 if (fd_head != NULL) {
5196 /* We completed reassembly... */
5197 if (pinfo->fd->num == fd_head->reassembled_in) {
5198 /* ...and this is the reassembled RPC PDU */
5199 next_tvb = tvb_new_chain(tvb, fd_head->tvb_data);
5200 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
5201 show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
5202 tree, pinfo, next_tvb, &pi);
5205 * XXX - authentication info?
5207 pinfo->fragmented = FALSE;
5208 dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb,
5209 next_tvb, hdr->drep, di, NULL);
5210 } else {
5211 /* ...and this isn't the reassembled RPC PDU */
5212 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
5213 tvb, 0, 0, fd_head->reassembled_in);
5214 PROTO_ITEM_SET_GENERATED(pi);
5215 parent_pi = proto_tree_get_parent(dcerpc_tree);
5216 if (parent_pi != NULL) {
5217 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
5219 col_append_fstr(pinfo->cinfo, COL_INFO,
5220 " [DCE/RPC fragment, reas: #%u]", fd_head->reassembled_in);
5224 pinfo->fragmented = save_fragmented;
5227 static void
5228 dissect_dcerpc_dg_rqst(tvbuff_t *tvb, int offset, packet_info *pinfo,
5229 proto_tree *dcerpc_tree, proto_tree *tree,
5230 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
5232 dcerpc_info *di;
5233 dcerpc_call_value *value, v;
5234 dcerpc_matched_key matched_key, *new_matched_key;
5235 proto_item *pi;
5236 proto_item *parent_pi;
5238 di = get_next_di();
5239 if (!(pinfo->fd->flags.visited)) {
5240 dcerpc_call_value *call_value;
5241 dcerpc_dg_call_key *call_key;
5243 call_key = (dcerpc_dg_call_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_dg_call_key));
5244 call_key->conv = conv;
5245 call_key->seqnum = hdr->seqnum;
5246 call_key->act_id = hdr->act_id;
5248 call_value = (dcerpc_call_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_call_value));
5249 call_value->uuid = hdr->if_id;
5250 call_value->ver = hdr->if_ver;
5251 call_value->object_uuid = hdr->obj_id;
5252 call_value->opnum = hdr->opnum;
5253 call_value->req_frame = pinfo->fd->num;
5254 call_value->req_time = pinfo->fd->abs_ts;
5255 call_value->rep_frame = 0;
5256 call_value->max_ptr = 0;
5257 call_value->se_data = NULL;
5258 call_value->private_data = NULL;
5259 call_value->pol = NULL;
5260 /* NDR64 is not available on dg transports ?*/
5261 call_value->flags = 0;
5263 g_hash_table_insert(dcerpc_dg_calls, call_key, call_value);
5265 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof(dcerpc_matched_key));
5266 new_matched_key->frame = pinfo->fd->num;
5267 new_matched_key->call_id = hdr->seqnum;
5268 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
5271 matched_key.frame = pinfo->fd->num;
5272 matched_key.call_id = hdr->seqnum;
5273 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
5274 if (!value) {
5275 v.uuid = hdr->if_id;
5276 v.ver = hdr->if_ver;
5277 v.object_uuid = hdr->obj_id;
5278 v.opnum = hdr->opnum;
5279 v.req_frame = pinfo->fd->num;
5280 v.rep_frame = 0;
5281 v.max_ptr = 0;
5282 v.se_data = NULL;
5283 v.private_data = NULL;
5284 value = &v;
5287 di->conv = conv;
5288 di->call_id = hdr->seqnum;
5289 di->smb_fid = -1;
5290 di->ptype = PDU_REQ;
5291 di->call_data = value;
5293 if (value->rep_frame != 0) {
5294 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
5295 tvb, 0, 0, value->rep_frame);
5296 PROTO_ITEM_SET_GENERATED(pi);
5297 parent_pi = proto_tree_get_parent(dcerpc_tree);
5298 if (parent_pi != NULL) {
5299 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
5302 dissect_dcerpc_dg_stub(tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
5305 static void
5306 dissect_dcerpc_dg_resp(tvbuff_t *tvb, int offset, packet_info *pinfo,
5307 proto_tree *dcerpc_tree, proto_tree *tree,
5308 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
5310 dcerpc_info *di;
5311 dcerpc_call_value *value, v;
5312 dcerpc_matched_key matched_key, *new_matched_key;
5313 proto_item *pi;
5314 proto_item *parent_pi;
5316 di = get_next_di();
5317 if (!(pinfo->fd->flags.visited)) {
5318 dcerpc_call_value *call_value;
5319 dcerpc_dg_call_key call_key;
5321 call_key.conv = conv;
5322 call_key.seqnum = hdr->seqnum;
5323 call_key.act_id = hdr->act_id;
5325 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_dg_calls, &call_key))) {
5326 new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
5327 new_matched_key->frame = pinfo->fd->num;
5328 new_matched_key->call_id = hdr->seqnum;
5329 g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
5330 if (call_value->rep_frame == 0) {
5331 call_value->rep_frame = pinfo->fd->num;
5336 matched_key.frame = pinfo->fd->num;
5337 matched_key.call_id = hdr->seqnum;
5338 value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
5339 if (!value) {
5340 v.uuid = hdr->if_id;
5341 v.ver = hdr->if_ver;
5342 v.object_uuid = hdr->obj_id;
5343 v.opnum = hdr->opnum;
5344 v.req_frame = 0;
5345 v.rep_frame = pinfo->fd->num;
5346 v.se_data = NULL;
5347 v.private_data = NULL;
5348 value = &v;
5351 di->conv = conv;
5352 di->call_id = 0;
5353 di->smb_fid = -1;
5354 di->ptype = PDU_RESP;
5355 di->call_data = value;
5357 if (value->req_frame != 0) {
5358 nstime_t delta_ts;
5359 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
5360 tvb, 0, 0, value->req_frame);
5361 PROTO_ITEM_SET_GENERATED(pi);
5362 parent_pi = proto_tree_get_parent(dcerpc_tree);
5363 if (parent_pi != NULL) {
5364 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
5366 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
5367 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
5368 PROTO_ITEM_SET_GENERATED(pi);
5369 } else {
5370 proto_tree_add_expert(dcerpc_tree, pinfo, &ei_dcerpc_no_request_found, tvb, 0, 0);
5372 dissect_dcerpc_dg_stub(tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
5375 static void
5376 dissect_dcerpc_dg_ping_ack(tvbuff_t *tvb, int offset, packet_info *pinfo,
5377 proto_tree *dcerpc_tree,
5378 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
5380 proto_item *parent_pi;
5381 /* if (!(pinfo->fd->flags.visited)) {*/
5382 dcerpc_call_value *call_value;
5383 dcerpc_dg_call_key call_key;
5385 call_key.conv = conv;
5386 call_key.seqnum = hdr->seqnum;
5387 call_key.act_id = hdr->act_id;
5389 if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_dg_calls, &call_key))) {
5390 proto_item *pi;
5391 nstime_t delta_ts;
5393 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
5394 tvb, 0, 0, call_value->req_frame);
5395 PROTO_ITEM_SET_GENERATED(pi);
5396 parent_pi = proto_tree_get_parent(dcerpc_tree);
5397 if (parent_pi != NULL) {
5398 proto_item_append_text(parent_pi, ", [Req: #%u]", call_value->req_frame);
5401 col_append_fstr(pinfo->cinfo, COL_INFO, " [req: #%u]", call_value->req_frame);
5403 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &call_value->req_time);
5404 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
5405 PROTO_ITEM_SET_GENERATED(pi);
5406 /* }*/
5411 * DCERPC dissector for connectionless calls
5413 static gboolean
5414 dissect_dcerpc_dg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5416 proto_item *ti = NULL;
5417 proto_item *tf = NULL;
5418 proto_tree *dcerpc_tree = NULL;
5419 proto_tree *dg_flags1_tree = NULL;
5420 proto_tree *dg_flags2_tree = NULL;
5421 proto_tree *drep_tree = NULL;
5422 e_dce_dg_common_hdr_t hdr;
5423 int offset = 0;
5424 conversation_t *conv;
5425 int auth_level;
5426 char *uuid_str;
5427 const char *uuid_name = NULL;
5430 * Check if this looks like a CL DCERPC call. All dg packets
5431 * have an 80 byte header on them. Which starts with
5432 * version (4), pkt_type.
5434 if (tvb_length(tvb) < sizeof (hdr)) {
5435 return FALSE;
5438 /* Version must be 4 */
5439 hdr.rpc_ver = tvb_get_guint8(tvb, offset++);
5440 if (hdr.rpc_ver != 4)
5441 return FALSE;
5443 /* Type must be <= 19 or it's not DCE/RPC */
5444 hdr.ptype = tvb_get_guint8(tvb, offset++);
5445 if (hdr.ptype > 19)
5446 return FALSE;
5448 /* flags1 has bit 1 and 8 as reserved so if any of them are set, it is
5449 probably not a DCE/RPC packet
5451 hdr.flags1 = tvb_get_guint8(tvb, offset++);
5452 if (hdr.flags1&0x81)
5453 return FALSE;
5455 /* flags2 has all bits except bit 2 as reserved so if any of them are set
5456 it is probably not DCE/RPC.
5458 hdr.flags2 = tvb_get_guint8(tvb, offset++);
5459 if (hdr.flags2&0xfd)
5460 return FALSE;
5463 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCERPC");
5464 col_add_str(pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
5466 tvb_memcpy(tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
5467 offset += (int)sizeof (hdr.drep);
5468 hdr.serial_hi = tvb_get_guint8(tvb, offset++);
5469 dcerpc_tvb_get_uuid(tvb, offset, hdr.drep, &hdr.obj_id);
5470 offset += 16;
5471 dcerpc_tvb_get_uuid(tvb, offset, hdr.drep, &hdr.if_id);
5472 offset += 16;
5473 dcerpc_tvb_get_uuid(tvb, offset, hdr.drep, &hdr.act_id);
5474 offset += 16;
5475 hdr.server_boot = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
5476 offset += 4;
5477 hdr.if_ver = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
5478 offset += 4;
5479 hdr.seqnum = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
5480 offset += 4;
5481 hdr.opnum = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5482 offset += 2;
5483 hdr.ihint = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5484 offset += 2;
5485 hdr.ahint = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5486 offset += 2;
5487 hdr.frag_len = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5488 offset += 2;
5489 hdr.frag_num = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5490 offset += 2;
5491 hdr.auth_proto = tvb_get_guint8(tvb, offset++);
5492 hdr.serial_lo = tvb_get_guint8(tvb, offset++);
5494 if (tree) {
5495 ti = proto_tree_add_item(tree, proto_dcerpc, tvb, 0, -1, ENC_NA);
5496 if (ti) {
5497 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
5498 proto_item_append_text(ti, " %s, Seq: %u, Serial: %u, Frag: %u, FragLen: %u",
5499 val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"),
5500 hdr.seqnum, hdr.serial_hi*256+hdr.serial_lo,
5501 hdr.frag_num, hdr.frag_len);
5504 offset = 0;
5506 if (tree)
5507 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
5508 offset++;
5510 if (tree)
5511 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
5512 offset++;
5514 if (tree) {
5515 tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
5516 dg_flags1_tree = proto_item_add_subtree(tf, ett_dcerpc_dg_flags1);
5517 if (dg_flags1_tree) {
5518 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
5519 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
5520 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
5521 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
5522 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
5523 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
5524 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
5525 proto_tree_add_boolean(dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
5526 if (hdr.flags1) {
5527 proto_item_append_text(tf, " %s%s%s%s%s%s",
5528 (hdr.flags1 & PFCL1_BROADCAST) ? "\"Broadcast\" " : "",
5529 (hdr.flags1 & PFCL1_IDEMPOTENT) ? "\"Idempotent\" " : "",
5530 (hdr.flags1 & PFCL1_MAYBE) ? "\"Maybe\" " : "",
5531 (hdr.flags1 & PFCL1_NOFACK) ? "\"No Fack\" " : "",
5532 (hdr.flags1 & PFCL1_FRAG) ? "\"Fragment\" " : "",
5533 (hdr.flags1 & PFCL1_LASTFRAG) ? "\"Last Fragment\" " : "");
5537 offset++;
5539 if (tree) {
5540 tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
5541 dg_flags2_tree = proto_item_add_subtree(tf, ett_dcerpc_dg_flags2);
5542 if (dg_flags2_tree) {
5543 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
5544 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
5545 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
5546 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
5547 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
5548 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
5549 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
5550 proto_tree_add_boolean(dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
5551 if (hdr.flags2) {
5552 proto_item_append_text(tf, " %s",
5553 (hdr.flags2 & PFCL2_CANCEL_PENDING) ? "\"Cancel Pending\" " : "");
5557 offset++;
5559 if (tree) {
5560 tf = proto_tree_add_bytes(dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
5561 drep_tree = proto_item_add_subtree(tf, ett_dcerpc_drep);
5562 if (drep_tree) {
5563 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
5564 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
5565 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
5566 proto_item_append_text(tf, " (Order: %s, Char: %s, Float: %s)",
5567 val_to_str_const(hdr.drep[0] >> 4, drep_byteorder_vals, "Unknown"),
5568 val_to_str_const(hdr.drep[0] & 0x0f, drep_character_vals, "Unknown"),
5569 val_to_str_const(hdr.drep[1], drep_fp_vals, "Unknown"));
5572 offset += (int)sizeof (hdr.drep);
5574 if (tree)
5575 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
5576 offset++;
5578 if (tree) {
5579 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
5580 offset, 16, (e_guid_t *) &hdr.obj_id, "Object UUID: %s",
5581 guid_to_str((e_guid_t *) &hdr.obj_id));
5583 offset += 16;
5585 if (tree) {
5586 uuid_str = guid_to_str((e_guid_t*)&hdr.if_id);
5587 uuid_name = guids_get_uuid_name(&hdr.if_id);
5588 if (uuid_name) {
5589 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
5590 offset, 16, (e_guid_t *) &hdr.if_id, "Interface: %s UUID: %s", uuid_name, uuid_str);
5591 } else {
5592 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
5593 offset, 16, (e_guid_t *) &hdr.if_id, "Interface UUID: %s", uuid_str);
5596 offset += 16;
5598 if (tree) {
5599 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
5600 offset, 16, (e_guid_t *) &hdr.act_id, "Activity: %s",
5601 guid_to_str((e_guid_t *) &hdr.act_id));
5603 offset += 16;
5605 if (tree) {
5606 nstime_t server_boot;
5608 server_boot.secs = hdr.server_boot;
5609 server_boot.nsecs = 0;
5611 if (hdr.server_boot == 0)
5612 proto_tree_add_time_format_value(dcerpc_tree, hf_dcerpc_dg_server_boot,
5613 tvb, offset, 4, &server_boot,
5614 "Unknown (0)");
5615 else
5616 proto_tree_add_time(dcerpc_tree, hf_dcerpc_dg_server_boot,
5617 tvb, offset, 4, &server_boot);
5619 offset += 4;
5621 if (tree)
5622 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
5623 offset += 4;
5625 if (tree)
5626 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
5627 col_append_fstr(pinfo->cinfo, COL_INFO, ": seq: %u", hdr.seqnum);
5628 col_append_fstr(pinfo->cinfo, COL_DCE_CALL, "%u", hdr.seqnum);
5629 offset += 4;
5631 if (tree)
5632 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
5633 offset += 2;
5635 if (tree)
5636 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
5637 offset += 2;
5639 if (tree)
5640 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
5641 offset += 2;
5643 if (tree)
5644 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
5645 offset += 2;
5647 if (tree)
5648 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
5649 if (hdr.flags1 & PFCL1_FRAG) {
5650 /* Fragmented - put the fragment number into the Info column */
5651 col_append_fstr(pinfo->cinfo, COL_INFO, " frag: %u",
5652 hdr.frag_num);
5654 offset += 2;
5656 if (tree)
5657 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
5658 offset++;
5660 if (tree)
5661 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
5662 if (hdr.flags1 & PFCL1_FRAG) {
5663 /* Fragmented - put the serial number into the Info column */
5664 col_append_fstr(pinfo->cinfo, COL_INFO, " serial: %u",
5665 (hdr.serial_hi << 8) | hdr.serial_lo);
5667 offset++;
5669 if (tree) {
5671 * XXX - for Kerberos, we get a protection level; if it's
5672 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
5673 * stub data.
5675 dissect_dcerpc_dg_auth(tvb, offset, dcerpc_tree, &hdr,
5676 &auth_level);
5680 * keeping track of the conversation shouldn't really be necessary
5681 * for connectionless packets, because everything we need to know
5682 * to dissect is in the header for each packet. Unfortunately,
5683 * Microsoft's implementation is buggy and often puts the
5684 * completely wrong if_id in the header. go figure. So, keep
5685 * track of the seqnum and use that if possible. Note: that's not
5686 * completely correct. It should really be done based on both the
5687 * activity_id and seqnum. I haven't seen anywhere that it would
5688 * make a difference, but for future reference...
5690 conv = find_or_create_conversation(pinfo);
5693 * Packet type specific stuff is next.
5696 switch (hdr.ptype) {
5698 case PDU_CANCEL_ACK:
5699 /* Body is optional */
5700 /* XXX - we assume "frag_len" is the length of the body */
5701 if (hdr.frag_len != 0)
5702 dissect_dcerpc_dg_cancel_ack(tvb, offset, pinfo, dcerpc_tree, &hdr);
5703 break;
5705 case PDU_CL_CANCEL:
5707 * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
5708 * but in at least one capture none of the Cl_cancel PDUs had a
5709 * body.
5711 /* XXX - we assume "frag_len" is the length of the body */
5712 if (hdr.frag_len != 0)
5713 dissect_dcerpc_dg_cancel(tvb, offset, pinfo, dcerpc_tree, &hdr);
5714 break;
5716 case PDU_NOCALL:
5717 /* Body is optional; if present, it's the same as PDU_FACK */
5718 /* XXX - we assume "frag_len" is the length of the body */
5719 if (hdr.frag_len != 0)
5720 dissect_dcerpc_dg_fack(tvb, offset, pinfo, dcerpc_tree, &hdr);
5721 break;
5723 case PDU_FACK:
5724 /* Body is optional */
5725 /* XXX - we assume "frag_len" is the length of the body */
5726 if (hdr.frag_len != 0)
5727 dissect_dcerpc_dg_fack(tvb, offset, pinfo, dcerpc_tree, &hdr);
5728 break;
5730 case PDU_REJECT:
5731 case PDU_FAULT:
5732 dissect_dcerpc_dg_reject_fault(tvb, offset, pinfo, dcerpc_tree, &hdr);
5733 break;
5735 case PDU_REQ:
5736 dissect_dcerpc_dg_rqst(tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
5737 break;
5739 case PDU_RESP:
5740 dissect_dcerpc_dg_resp(tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
5741 break;
5743 /* these requests have no body */
5744 case PDU_ACK:
5745 case PDU_PING:
5746 dissect_dcerpc_dg_ping_ack(tvb, offset, pinfo, dcerpc_tree, &hdr, conv);
5747 break;
5748 case PDU_WORKING:
5749 default:
5750 break;
5753 return TRUE;
5756 static void
5757 dcerpc_init_protocol(void)
5759 /* structures and data for BIND */
5760 if (dcerpc_binds) {
5761 g_hash_table_destroy(dcerpc_binds);
5762 dcerpc_binds = NULL;
5764 if (!dcerpc_binds) {
5765 dcerpc_binds = g_hash_table_new(dcerpc_bind_hash, dcerpc_bind_equal);
5768 /* structures and data for CALL */
5769 if (dcerpc_cn_calls) {
5770 g_hash_table_destroy(dcerpc_cn_calls);
5772 dcerpc_cn_calls = g_hash_table_new(dcerpc_cn_call_hash, dcerpc_cn_call_equal);
5773 if (dcerpc_dg_calls) {
5774 g_hash_table_destroy(dcerpc_dg_calls);
5776 dcerpc_dg_calls = g_hash_table_new(dcerpc_dg_call_hash, dcerpc_dg_call_equal);
5778 /* structure and data for MATCHED */
5779 if (dcerpc_matched) {
5780 g_hash_table_destroy(dcerpc_matched);
5782 dcerpc_matched = g_hash_table_new(dcerpc_matched_hash, dcerpc_matched_equal);
5784 /* call the registered hooks */
5785 g_hook_list_invoke(&dcerpc_hooks_init_protos, FALSE /* not may_recurse */);
5788 void
5789 proto_register_dcerpc(void)
5791 static hf_register_info hf[] = {
5792 { &hf_dcerpc_request_in,
5793 { "Request in frame", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE,
5794 NULL, 0, "This packet is a response to the packet with this number", HFILL }},
5795 { &hf_dcerpc_response_in,
5796 { "Response in frame", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
5797 NULL, 0, "This packet will be responded in the packet with this number", HFILL }},
5798 { &hf_dcerpc_referent_id,
5799 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
5800 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
5801 { &hf_dcerpc_ver,
5802 { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5803 { &hf_dcerpc_ver_minor,
5804 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5805 { &hf_dcerpc_packet_type,
5806 { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS(pckt_vals), 0x0, NULL, HFILL }},
5807 { &hf_dcerpc_cn_flags,
5808 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5809 { &hf_dcerpc_cn_flags_first_frag,
5810 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_FIRST_FRAG, NULL, HFILL }},
5811 { &hf_dcerpc_cn_flags_last_frag,
5812 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_LAST_FRAG, NULL, HFILL }},
5813 { &hf_dcerpc_cn_flags_cancel_pending,
5814 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_PENDING_CANCEL, NULL, HFILL }},
5815 { &hf_dcerpc_cn_flags_reserved,
5816 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_RESERVED_1, NULL, HFILL }},
5817 { &hf_dcerpc_cn_flags_mpx,
5818 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_CONC_MPX, NULL, HFILL }},
5819 { &hf_dcerpc_cn_flags_dne,
5820 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_DID_NOT_EXECUTE, NULL, HFILL }},
5821 { &hf_dcerpc_cn_flags_maybe,
5822 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_MAYBE, NULL, HFILL }},
5823 { &hf_dcerpc_cn_flags_object,
5824 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_OBJECT_UUID, NULL, HFILL }},
5825 { &hf_dcerpc_drep,
5826 { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5827 { &hf_dcerpc_drep_byteorder,
5828 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS(drep_byteorder_vals), 0x0, NULL, HFILL }},
5829 { &hf_dcerpc_drep_character,
5830 { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS(drep_character_vals), 0x0, NULL, HFILL }},
5831 { &hf_dcerpc_drep_fp,
5832 { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS(drep_fp_vals), 0x0, NULL, HFILL }},
5833 { &hf_dcerpc_cn_frag_len,
5834 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5835 { &hf_dcerpc_cn_auth_len,
5836 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5837 { &hf_dcerpc_cn_call_id,
5838 { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5839 { &hf_dcerpc_cn_max_xmit,
5840 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5841 { &hf_dcerpc_cn_max_recv,
5842 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5843 { &hf_dcerpc_cn_assoc_group,
5844 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5845 { &hf_dcerpc_cn_num_ctx_items,
5846 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5847 { &hf_dcerpc_cn_ctx_item,
5848 { "Ctx Item", "dcerpc.cn_ctx_item", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5849 { &hf_dcerpc_cn_ctx_id,
5850 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5851 { &hf_dcerpc_cn_num_trans_items,
5852 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5853 { &hf_dcerpc_cn_bind_abstract_syntax,
5854 { "Abstract Syntax", "dcerpc.cn_bind_abstract_syntax", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5855 { &hf_dcerpc_cn_bind_if_id,
5856 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5857 { &hf_dcerpc_cn_bind_if_ver,
5858 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5859 { &hf_dcerpc_cn_bind_if_ver_minor,
5860 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5861 { &hf_dcerpc_cn_bind_trans_syntax,
5862 { "Transfer Syntax", "dcerpc.cn_bind_trans", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5863 { &hf_dcerpc_cn_bind_trans_id,
5864 { "ID", "dcerpc.cn_bind_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5865 { &hf_dcerpc_cn_bind_trans_ver,
5866 { "ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5867 { &hf_dcerpc_cn_bind_trans_btfn_01, /* [MS-RPCE] 2.2.2.14 */
5868 { "Security Context Multiplexing Supported", "dcerpc.cn_bind_trans_btfn.01", FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x01, NULL, HFILL }},
5869 { &hf_dcerpc_cn_bind_trans_btfn_02,
5870 { "Keep Connection On Orphan Supported", "dcerpc.cn_bind_trans_btfn.02", FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x02, NULL, HFILL }},
5871 { &hf_dcerpc_cn_alloc_hint,
5872 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5873 { &hf_dcerpc_cn_sec_addr_len,
5874 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5875 { &hf_dcerpc_cn_sec_addr,
5876 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5877 { &hf_dcerpc_cn_num_results,
5878 { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5879 { &hf_dcerpc_cn_ack_result,
5880 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, NULL, HFILL }},
5881 { &hf_dcerpc_cn_ack_reason,
5882 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, NULL, HFILL }},
5883 { &hf_dcerpc_cn_ack_trans_id,
5884 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5885 { &hf_dcerpc_cn_ack_trans_ver,
5886 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5887 { &hf_dcerpc_cn_ack_btfn,
5888 { "Bind Time Feature Negotiation Bitmask", "dcerpc.cn_ack_btfn", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5889 { &hf_dcerpc_cn_reject_reason,
5890 { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, NULL, HFILL }},
5891 { &hf_dcerpc_cn_num_protocols,
5892 { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5893 { &hf_dcerpc_cn_protocol_ver_major,
5894 { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5895 { &hf_dcerpc_cn_protocol_ver_minor,
5896 { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5897 { &hf_dcerpc_cn_cancel_count,
5898 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5899 { &hf_dcerpc_cn_status,
5900 { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, NULL, HFILL }},
5901 { &hf_dcerpc_cn_deseg_req,
5902 { "Desegmentation Required", "dcerpc.cn_deseg_req", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5903 { &hf_dcerpc_auth_type,
5904 { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS(authn_protocol_vals), 0x0, NULL, HFILL }},
5905 { &hf_dcerpc_auth_level,
5906 { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, NULL, HFILL }},
5907 { &hf_dcerpc_auth_pad_len,
5908 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5909 { &hf_dcerpc_auth_rsrvd,
5910 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5911 { &hf_dcerpc_auth_ctx_id,
5912 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5913 { &hf_dcerpc_dg_flags1,
5914 { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5915 { &hf_dcerpc_dg_flags1_rsrvd_01,
5916 { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_RESERVED_01, NULL, HFILL }},
5917 { &hf_dcerpc_dg_flags1_last_frag,
5918 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_LASTFRAG, NULL, HFILL }},
5919 { &hf_dcerpc_dg_flags1_frag,
5920 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_FRAG, NULL, HFILL }},
5921 { &hf_dcerpc_dg_flags1_nofack,
5922 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_NOFACK, NULL, HFILL }},
5923 { &hf_dcerpc_dg_flags1_maybe,
5924 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_MAYBE, NULL, HFILL }},
5925 { &hf_dcerpc_dg_flags1_idempotent,
5926 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_IDEMPOTENT, NULL, HFILL }},
5927 { &hf_dcerpc_dg_flags1_broadcast,
5928 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_BROADCAST, NULL, HFILL }},
5929 { &hf_dcerpc_dg_flags1_rsrvd_80,
5930 { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_RESERVED_80, NULL, HFILL }},
5931 { &hf_dcerpc_dg_flags2,
5932 { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5933 { &hf_dcerpc_dg_flags2_rsrvd_01,
5934 { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_01, NULL, HFILL }},
5935 { &hf_dcerpc_dg_flags2_cancel_pending,
5936 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_CANCEL_PENDING, NULL, HFILL }},
5937 { &hf_dcerpc_dg_flags2_rsrvd_04,
5938 { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_04, NULL, HFILL }},
5939 { &hf_dcerpc_dg_flags2_rsrvd_08,
5940 { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_08, NULL, HFILL }},
5941 { &hf_dcerpc_dg_flags2_rsrvd_10,
5942 { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_10, NULL, HFILL }},
5943 { &hf_dcerpc_dg_flags2_rsrvd_20,
5944 { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_20, NULL, HFILL }},
5945 { &hf_dcerpc_dg_flags2_rsrvd_40,
5946 { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_40, NULL, HFILL }},
5947 { &hf_dcerpc_dg_flags2_rsrvd_80,
5948 { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_80, NULL, HFILL }},
5949 { &hf_dcerpc_dg_serial_lo,
5950 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5951 { &hf_dcerpc_dg_serial_hi,
5952 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5953 { &hf_dcerpc_dg_ahint,
5954 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5955 { &hf_dcerpc_dg_ihint,
5956 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5957 { &hf_dcerpc_dg_frag_len,
5958 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5959 { &hf_dcerpc_dg_frag_num,
5960 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5961 { &hf_dcerpc_dg_auth_proto,
5962 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS(authn_protocol_vals), 0x0, NULL, HFILL }},
5963 { &hf_dcerpc_dg_seqnum,
5964 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5965 { &hf_dcerpc_dg_server_boot,
5966 { "Server boot time", "dcerpc.dg_server_boot", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0, NULL, HFILL }},
5967 { &hf_dcerpc_dg_if_ver,
5968 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5969 { &hf_dcerpc_krb5_av_prot_level,
5970 { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, NULL, HFILL }},
5971 { &hf_dcerpc_krb5_av_key_vers_num,
5972 { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5973 { &hf_dcerpc_krb5_av_key_auth_verifier,
5974 { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5975 { &hf_dcerpc_obj_id,
5976 { "Object", "dcerpc.obj_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5977 { &hf_dcerpc_dg_if_id,
5978 { "Interface", "dcerpc.dg_if_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5979 { &hf_dcerpc_dg_act_id,
5980 { "Activity", "dcerpc.dg_act_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5981 { &hf_dcerpc_opnum,
5982 { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5984 { &hf_dcerpc_dg_cancel_vers,
5985 { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5987 { &hf_dcerpc_dg_cancel_id,
5988 { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5990 { &hf_dcerpc_dg_server_accepting_cancels,
5991 { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5993 { &hf_dcerpc_dg_fack_vers,
5994 { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5996 { &hf_dcerpc_dg_fack_window_size,
5997 { "Window Size", "dcerpc.fack_window_size", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5999 { &hf_dcerpc_dg_fack_max_tsdu,
6000 { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6002 { &hf_dcerpc_dg_fack_max_frag_size,
6003 { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6005 { &hf_dcerpc_dg_fack_serial_num,
6006 { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6008 { &hf_dcerpc_dg_fack_selack_len,
6009 { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6011 { &hf_dcerpc_dg_fack_selack,
6012 { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6014 { &hf_dcerpc_dg_status,
6015 { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, NULL, HFILL }},
6017 { &hf_dcerpc_array_max_count,
6018 { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
6020 { &hf_dcerpc_array_offset,
6021 { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
6023 { &hf_dcerpc_array_actual_count,
6024 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
6026 { &hf_dcerpc_array_buffer,
6027 { "Buffer", "dcerpc.array.buffer", FT_BYTES, BASE_NONE, NULL, 0x0, "Buffer: Buffer containing elements of the array", HFILL }},
6029 { &hf_dcerpc_op,
6030 { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6032 { &hf_dcerpc_fragments,
6033 { "Reassembled DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
6034 NULL, 0x0, "DCE/RPC Fragments", HFILL }},
6036 { &hf_dcerpc_fragment,
6037 { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM, BASE_NONE,
6038 NULL, 0x0, NULL, HFILL }},
6040 { &hf_dcerpc_fragment_overlap,
6041 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE,
6042 NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
6044 { &hf_dcerpc_fragment_overlap_conflict,
6045 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE,
6046 NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
6048 { &hf_dcerpc_fragment_multiple_tails,
6049 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE,
6050 NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
6052 { &hf_dcerpc_fragment_too_long_fragment,
6053 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE,
6054 NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
6056 { &hf_dcerpc_fragment_error,
6057 { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE,
6058 NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
6060 { &hf_dcerpc_fragment_count,
6061 { "Fragment count", "dcerpc.fragment.count", FT_UINT32, BASE_DEC,
6062 NULL, 0x0, NULL, HFILL }},
6064 { &hf_dcerpc_time,
6065 { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE,
6066 NULL, 0, "Time between Request and Response for DCE-RPC calls", HFILL }},
6068 { &hf_dcerpc_reassembled_in,
6069 { "Reassembled PDU in frame", "dcerpc.reassembled_in", FT_FRAMENUM, BASE_NONE,
6070 NULL, 0x0, "The DCE/RPC PDU is completely reassembled in the packet with this number", HFILL }},
6072 { &hf_dcerpc_reassembled_length,
6073 { "Reassembled DCE/RPC length", "dcerpc.reassembled.length", FT_UINT32, BASE_DEC,
6074 NULL, 0x0, "The total length of the reassembled payload", HFILL }},
6076 { &hf_dcerpc_unknown_if_id,
6077 { "Unknown DCERPC interface id", "dcerpc.unknown_if_id", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6079 { &hf_dcerpc_cn_rts_flags,
6080 { "RTS Flags", "dcerpc.cn_rts_flags", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6081 { &hf_dcerpc_cn_rts_flags_none,
6082 {"None", "dcerpc.cn_rts_flags.none", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_NONE, NULL, HFILL }},
6083 { &hf_dcerpc_cn_rts_flags_ping,
6084 { "Ping", "dcerpc.cn_rts.flags.ping", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_PING, NULL, HFILL }},
6085 { &hf_dcerpc_cn_rts_flags_other_cmd,
6086 { "Other Cmd", "dcerpc.cn_rts_flags.other_cmd", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_OTHER_CMD, NULL, HFILL }},
6087 { &hf_dcerpc_cn_rts_flags_recycle_channel,
6088 { "Recycle Channel", "dcerpc.cn_rts_flags.recycle_channel", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_RECYCLE_CHANNEL, NULL, HFILL }},
6089 { &hf_dcerpc_cn_rts_flags_in_channel,
6090 { "In Channel", "dcerpc.cn_rts_flags.in_channel", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_IN_CHANNEL, NULL, HFILL }},
6091 { &hf_dcerpc_cn_rts_flags_out_channel,
6092 { "Out Channel", "dcerpc.cn_rts_flags.out_channel", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_OUT_CHANNEL, NULL, HFILL }},
6093 { &hf_dcerpc_cn_rts_flags_eof,
6094 { "EOF", "dcerpc.cn_rts_flags.eof", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_EOF, NULL, HFILL }},
6095 { &hf_dcerpc_cn_rts_commands_nb,
6096 { "RTS Number of Commands", "dcerpc.cn_rts_commands_nb", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6097 { &hf_dcerpc_cn_rts_command,
6098 { "RTS Command", "dcerpc.cn_rts_command", FT_UINT32, BASE_HEX, VALS(rts_command_vals), 0x0, NULL, HFILL }},
6099 { &hf_dcerpc_cn_rts_command_receivewindowsize,
6100 {"Receive Window Size", "dcerpc.cn_rts_command.receivewindowsize", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6101 { &hf_dcerpc_cn_rts_command_fack_bytesreceived,
6102 {"Bytes Received", "dcerpc.cn_rts_command.fack.bytesreceived", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6103 { &hf_dcerpc_cn_rts_command_fack_availablewindow,
6104 {"Available Window", "dcerpc.cn_rts_command.fack.availablewindow", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6105 { &hf_dcerpc_cn_rts_command_fack_channelcookie,
6106 {"Channel Cookie", "dcerpc.cn_rts_command.fack.channelcookie", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6107 { &hf_dcerpc_cn_rts_command_connectiontimeout,
6108 {"Connection Timeout", "dcerpc.cn_rts_command.connectiontimeout", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6109 { &hf_dcerpc_cn_rts_command_cookie,
6110 {"Cookie", "dcerpc.cn_rts_command.cookie", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6111 { &hf_dcerpc_cn_rts_command_channellifetime,
6112 {"Channel Lifetime", "dcerpc.cn_rts_command.channellifetime", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6113 { &hf_dcerpc_cn_rts_command_clientkeepalive,
6114 {"Client Keepalive", "dcerpc.cn_rts_command.clientkeepalive", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6115 { &hf_dcerpc_cn_rts_command_version,
6116 {"Version", "dcerpc.cn_rts_command.version", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6117 { &hf_dcerpc_cn_rts_command_conformancecount,
6118 {"Conformance Count", "dcerpc.cn_rts_command.padding.conformancecount", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6119 { &hf_dcerpc_cn_rts_command_padding,
6120 { "Padding", "dcerpc.cn_rts_command.padding.padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
6121 { &hf_dcerpc_cn_rts_command_addrtype,
6122 { "Address Type", "dcerpc.cn_rts_command.addrtype", FT_UINT32, BASE_DEC, VALS(rts_addresstype_vals), 0x0, NULL, HFILL }},
6123 { &hf_dcerpc_cn_rts_command_associationgroupid,
6124 {"Association Group ID", "dcerpc.cn_rts_command.associationgroupid", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6125 { &hf_dcerpc_cn_rts_command_forwarddestination,
6126 {"Forward Destination", "dcerpc.cn_rts_command.forwarddestination", FT_UINT32, BASE_DEC, VALS(rts_forward_destination_vals), 0x0, NULL, HFILL }},
6127 { &hf_dcerpc_cn_rts_command_pingtrafficsentnotify,
6128 {"Ping Traffic Sent Notify", "dcerpc.cn_rts_command.pingtrafficsentnotify", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6129 { &hf_dcerpc_sec_vt_command_end,
6130 {"SEC_VT_COMMAND_END", "dcerpc.rpc_sec_vt.command.end", FT_BOOLEAN, 16, NULL, 0x4000, NULL, HFILL }},
6131 { &hf_dcerpc_sec_vt_command_must,
6132 {"SEC_VT_MUST_PROCESS_COMMAND", "dcerpc.rpc_sec_vt.command.must_process", FT_BOOLEAN, 16, NULL, 0x8000, NULL, HFILL }},
6133 { &hf_dcerpc_sec_vt_command_cmd,
6134 {"SEC_VT_COMMAND", "dcerpc.rpc_sec_vt.command.cmd", FT_UINT16, BASE_HEX, VALS(sec_vt_command_cmd_vals), 0x3fff, NULL, HFILL }},
6135 { &hf_dcerpc_sec_vt_command,
6136 {"Command", "dcerpc.rpc_sec_vt.command", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
6137 { &hf_dcerpc_sec_vt_command_length,
6138 {"Length", "dcerpc.rpc_sec_vt.command.length", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL}},
6139 { &hf_dcerpc_sec_vt_bitmask,
6140 {"rpc_sec_vt_bitmask", "dcerpc.rpc_sec_vt.bitmask", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
6141 { &hf_dcerpc_sec_vt_bitmask_sign,
6142 {"CLIENT_SUPPORT_HEADER_SIGNING", "dcerpc.rpc_sec_vt.bitmask.sign", FT_BOOLEAN, 32, NULL, 0x1, NULL, HFILL }},
6144 static gint *ett[] = {
6145 &ett_dcerpc,
6146 &ett_dcerpc_cn_flags,
6147 &ett_dcerpc_cn_ctx,
6148 &ett_dcerpc_cn_iface,
6149 &ett_dcerpc_cn_trans_syntax,
6150 &ett_dcerpc_cn_trans_btfn,
6151 &ett_dcerpc_cn_rts_flags,
6152 &ett_dcerpc_cn_rts_command,
6153 &ett_dcerpc_cn_rts_pdu,
6154 &ett_dcerpc_drep,
6155 &ett_dcerpc_dg_flags1,
6156 &ett_dcerpc_dg_flags2,
6157 &ett_dcerpc_pointer_data,
6158 &ett_dcerpc_string,
6159 &ett_dcerpc_fragments,
6160 &ett_dcerpc_fragment,
6161 &ett_dcerpc_krb5_auth_verf,
6162 &ett_dcerpc_verification_trailer,
6163 &ett_dcerpc_sec_vt_command,
6164 &ett_dcerpc_sec_vt_bitmask,
6167 static ei_register_info ei[] = {
6168 { &ei_dcerpc_fragment, { "dcerpc.fragment", PI_REASSEMBLE, PI_CHAT, "%s fragment", EXPFILL }},
6169 { &ei_dcerpc_fragment_reassembled, { "dcerpc.fragment_reassembled", PI_REASSEMBLE, PI_CHAT, "%s fragment, reassembled", EXPFILL }},
6170 { &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 }},
6171 { &ei_dcerpc_no_request_found, { "dcerpc.no_request_found", PI_SEQUENCE, PI_NOTE, "No request to this DCE/RPC call found", EXPFILL }},
6172 { &ei_dcerpc_cn_status, { "dcerpc.cn_status.expert", PI_RESPONSE_CODE, PI_NOTE, "Fault: %s", EXPFILL }},
6173 { &ei_dcerpc_fragment_multiple, { "dcerpc.fragment_multiple", PI_SEQUENCE, PI_CHAT, "Multiple DCE/RPC fragments/PDU's in one packet", EXPFILL }},
6174 { &ei_dcerpc_context_change, { "dcerpc.context_change", PI_SEQUENCE, PI_CHAT, "Context change: %s", EXPFILL }},
6175 { &ei_dcerpc_bind_not_acknowledged, { "dcerpc.bind_not_acknowledged", PI_SEQUENCE, PI_WARN, "Bind not acknowledged", EXPFILL }},
6178 module_t *dcerpc_module;
6179 expert_module_t* expert_dcerpc;
6181 proto_dcerpc = proto_register_protocol("Distributed Computing Environment / Remote Procedure Call (DCE/RPC)", "DCERPC", "dcerpc");
6182 proto_register_field_array(proto_dcerpc, hf, array_length(hf));
6183 proto_register_subtree_array(ett, array_length(ett));
6184 expert_dcerpc = expert_register_protocol(proto_dcerpc);
6185 expert_register_field_array(expert_dcerpc, ei, array_length(ei));
6187 register_init_routine(dcerpc_init_protocol);
6188 dcerpc_module = prefs_register_protocol(proto_dcerpc, NULL);
6189 prefs_register_bool_preference(dcerpc_module,
6190 "desegment_dcerpc",
6191 "Reassemble DCE/RPC messages spanning multiple TCP segments",
6192 "Whether the DCE/RPC dissector should reassemble messages"
6193 " spanning multiple TCP segments."
6194 " To use this option, you must also enable"
6195 " \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
6196 &dcerpc_cn_desegment);
6197 prefs_register_bool_preference(dcerpc_module,
6198 "reassemble_dcerpc",
6199 "Reassemble DCE/RPC fragments",
6200 "Whether the DCE/RPC dissector should reassemble fragmented DCE/RPC PDUs",
6201 &dcerpc_reassemble);
6202 register_init_routine(dcerpc_reassemble_init);
6203 dcerpc_uuids = g_hash_table_new(dcerpc_uuid_hash, dcerpc_uuid_equal);
6204 dcerpc_tap = register_tap("dcerpc");
6206 g_hook_list_init(&dcerpc_hooks_init_protos, sizeof(GHook));
6209 void
6210 proto_reg_handoff_dcerpc(void)
6212 heur_dissector_add("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
6213 heur_dissector_add("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
6214 heur_dissector_add("udp", dissect_dcerpc_dg, proto_dcerpc);
6215 heur_dissector_add("smb_transact", dissect_dcerpc_cn_smbpipe, proto_dcerpc);
6216 heur_dissector_add("smb2_heur_subdissectors", dissect_dcerpc_cn_smb2, proto_dcerpc);
6217 heur_dissector_add("http", dissect_dcerpc_cn_bs, proto_dcerpc);
6218 dcerpc_smb_init(proto_dcerpc);
6220 guids_add_uuid(&uuid_data_repr_proto, "32bit NDR");
6221 guids_add_uuid(&uuid_ndr64, "64bit NDR");
6222 guids_add_uuid(&uuid_bind_time_feature_nego_00, "bind time feature negotiation");
6223 guids_add_uuid(&uuid_bind_time_feature_nego_01, "bind time feature negotiation");
6224 guids_add_uuid(&uuid_bind_time_feature_nego_02, "bind time feature negotiation");
6225 guids_add_uuid(&uuid_bind_time_feature_nego_03, "bind time feature negotiation");
6226 guids_add_uuid(&uuid_asyncemsmdb, "async MAPI");
6230 * Editor modelines - http://www.wireshark.org/tools/modelines.html
6232 * Local variables:
6233 * c-basic-offset: 4
6234 * tab-width: 8
6235 * indent-tabs-mode: nil
6236 * End:
6238 * vi: set shiftwidth=4 tabstop=8 expandtab:
6239 * :indentSize=4:tabSize=8:noTabs=true: