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>
6 *
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
10 *
11 * SPDX-License-Identifier: GPL-2.0-or-later
12 */
13
14 /* The DCE RPC 1.1 specification can be found at:
15 *
16 * https://publications.opengroup.org/c706
17 * https://pubs.opengroup.org/onlinepubs/009629399/
18 * https://pubs.opengroup.org/onlinepubs/009629399/toc.htm
19 * https://pubs.opengroup.org/onlinepubs/009629399/toc.pdf
20 *
21 * Microsoft extensions can be found at:
22 *
23 * MS-WPO section 7.3.1 "RPC":
24 * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wpo/7d2df784-557e-4fde-9281-9509653a0f17
25 */
26
27 #include "config.h"
28
29 #include <stdio.h>
30 #include <epan/packet.h>
31 #include <epan/exceptions.h>
32 #include <epan/prefs.h>
33 #include <epan/reassemble.h>
34 #include <epan/tap.h>
35 #include <epan/srt_table.h>
36 #include <epan/expert.h>
37 #include <epan/addr_resolv.h>
38 #include <epan/show_exception.h>
39 #include <epan/decode_as.h>
40 #include <epan/proto_data.h>
41
42 #include <wsutil/str_util.h>
43 #include "packet-tcp.h"
44 #include "packet-dcerpc.h"
45 #include "packet-dcerpc-nt.h"
46
47 void proto_register_dcerpc(void);
48 void proto_reg_handoff_dcerpc(void);
49
50 static int dcerpc_tap = -1;
51
52 /* 32bit Network Data Representation, see DCE/RPC Appendix I */
53 static e_guid_t uuid_data_repr_proto = { 0x8a885d04, 0x1ceb, 0x11c9,
54 { 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60 } };
55
56 /* 64bit Network Data Representation, introduced in Windows Server 2008 */
57 static e_guid_t uuid_ndr64 = { 0x71710533, 0xbeba, 0x4937,
58 { 0x83, 0x19, 0xb5, 0xdb, 0xef, 0x9c, 0xcc, 0x36 } };
59
60 /* see [MS-OXRPC] Appendix A: Full IDL, https://docs.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-oxcrpc/70adbb71-85a1-4023-bfdb-41e32ff37bf1 */
61 static e_guid_t uuid_asyncemsmdb = { 0x5261574a, 0x4572, 0x206e,
62 { 0xb2, 0x68, 0x6b, 0x19, 0x92, 0x13, 0xb4, 0xe4 } };
63
64 static const value_string pckt_vals[] = {
65 { PDU_REQ, "Request"},
66 { PDU_PING, "Ping"},
67 { PDU_RESP, "Response"},
68 { PDU_FAULT, "Fault"},
69 { PDU_WORKING, "Working"},
70 { PDU_NOCALL, "Nocall"},
71 { PDU_REJECT, "Reject"},
72 { PDU_ACK, "Ack"},
73 { PDU_CL_CANCEL, "Cl_cancel"},
74 { PDU_FACK, "Fack"},
75 { PDU_CANCEL_ACK, "Cancel_ack"},
76 { PDU_BIND, "Bind"},
77 { PDU_BIND_ACK, "Bind_ack"},
78 { PDU_BIND_NAK, "Bind_nak"},
79 { PDU_ALTER, "Alter_context"},
80 { PDU_ALTER_ACK, "Alter_context_resp"},
81 { PDU_AUTH3, "AUTH3"},
82 { PDU_SHUTDOWN, "Shutdown"},
83 { PDU_CO_CANCEL, "Co_cancel"},
84 { PDU_ORPHANED, "Orphaned"},
85 { PDU_RTS, "RPC-over-HTTP RTS"},
86 { 0, NULL }
87 };
88
89 static const value_string drep_byteorder_vals[] = {
90 { 0, "Big-endian" },
91 { 1, "Little-endian" },
92 { 0, NULL }
93 };
94
95 static const value_string drep_character_vals[] = {
96 { 0, "ASCII" },
97 { 1, "EBCDIC" },
98 { 0, NULL }
99 };
100
101 #define DCE_RPC_DREP_FP_IEEE 0
102 #define DCE_RPC_DREP_FP_VAX 1
103 #define DCE_RPC_DREP_FP_CRAY 2
104 #define DCE_RPC_DREP_FP_IBM 3
105
106 static const value_string drep_fp_vals[] = {
107 { DCE_RPC_DREP_FP_IEEE, "IEEE" },
108 { DCE_RPC_DREP_FP_VAX, "VAX" },
109 { DCE_RPC_DREP_FP_CRAY, "Cray" },
110 { DCE_RPC_DREP_FP_IBM, "IBM" },
111 { 0, NULL }
112 };
113
114 /*
115 * Authentication services.
116 */
117 static const value_string authn_protocol_vals[] = {
118 { DCE_C_RPC_AUTHN_PROTOCOL_NONE, "None" },
119 { DCE_C_RPC_AUTHN_PROTOCOL_KRB5, "Kerberos 5" },
120 { DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO, "SPNEGO" },
121 { DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP, "NTLMSSP" },
122 { DCE_C_RPC_AUTHN_PROTOCOL_GSS_SCHANNEL, "SCHANNEL SSP" },
123 { DCE_C_RPC_AUTHN_PROTOCOL_GSS_KERBEROS, "Kerberos SSP" },
124 { DCE_C_RPC_AUTHN_PROTOCOL_DPA,
125 "Distributed Password Authentication SSP"},
126 { DCE_C_RPC_AUTHN_PROTOCOL_MSN, "MSN SSP"},
127 { DCE_C_RPC_AUTHN_PROTOCOL_DIGEST, "Digest SSP"},
128 { DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN, "NETLOGON Secure Channel" },
129 { DCE_C_RPC_AUTHN_PROTOCOL_MQ, "MSMQ SSP"},
130 { 0, NULL }
131 };
132
133 /*
134 * Protection levels.
135 */
136 static const value_string authn_level_vals[] = {
137 { DCE_C_AUTHN_LEVEL_NONE, "None" },
138 { DCE_C_AUTHN_LEVEL_CONNECT, "Connect" },
139 { DCE_C_AUTHN_LEVEL_CALL, "Call" },
140 { DCE_C_AUTHN_LEVEL_PKT, "Packet" },
141 { DCE_C_AUTHN_LEVEL_PKT_INTEGRITY, "Packet integrity" },
142 { DCE_C_AUTHN_LEVEL_PKT_PRIVACY, "Packet privacy" },
143 { 0, NULL }
144 };
145
146 /*
147 * Flag bits in first flag field in connectionless PDU header.
148 */
149 #define PFCL1_RESERVED_01 0x01 /* Reserved for use by implementations */
150 #define PFCL1_LASTFRAG 0x02 /* If set, the PDU is the last
151 * fragment of a multi-PDU
152 * transmission */
153 #define PFCL1_FRAG 0x04 /* If set, the PDU is a fragment of
154 a multi-PDU transmission */
155 #define PFCL1_NOFACK 0x08 /* If set, the receiver is not
156 * requested to send a `fack' PDU
157 * for the fragment */
158 #define PFCL1_MAYBE 0x10 /* If set, the PDU is for a `maybe'
159 * request */
160 #define PFCL1_IDEMPOTENT 0x20 /* If set, the PDU is for an idempotent
161 * request */
162 #define PFCL1_BROADCAST 0x40 /* If set, the PDU is for a broadcast
163 * request */
164 #define PFCL1_RESERVED_80 0x80 /* Reserved for use by implementations */
165
166 /*
167 * Flag bits in second flag field in connectionless PDU header.
168 */
169 #define PFCL2_RESERVED_01 0x01 /* Reserved for use by implementations */
170 #define PFCL2_CANCEL_PENDING 0x02 /* Cancel pending at the call end */
171 #define PFCL2_RESERVED_04 0x04 /* Reserved for future use */
172 #define PFCL2_RESERVED_08 0x08 /* Reserved for future use */
173 #define PFCL2_RESERVED_10 0x10 /* Reserved for future use */
174 #define PFCL2_RESERVED_20 0x20 /* Reserved for future use */
175 #define PFCL2_RESERVED_40 0x40 /* Reserved for future use */
176 #define PFCL2_RESERVED_80 0x80 /* Reserved for future use */
177
178 /*
179 * Flag bits in connection-oriented PDU header.
180 */
181 #define PFC_FIRST_FRAG 0x01 /* First fragment */
182 #define PFC_LAST_FRAG 0x02 /* Last fragment */
183 #define PFC_PENDING_CANCEL 0x04 /* Cancel was pending at sender */
184 #define PFC_HDR_SIGNING PFC_PENDING_CANCEL /* on bind and alter req */
185 #define PFC_RESERVED_1 0x08
186 #define PFC_CONC_MPX 0x10 /* supports concurrent multiplexing
187 * of a single connection. */
188 #define PFC_DID_NOT_EXECUTE 0x20 /* only meaningful on `fault' packet;
189 * if true, guaranteed call did not
190 * execute. */
191 #define PFC_MAYBE 0x40 /* `maybe' call semantics requested */
192 #define PFC_OBJECT_UUID 0x80 /* if true, a non-nil object UUID
193 * was specified in the handle, and
194 * is present in the optional object
195 * field. If false, the object field
196 * is omitted. */
197
198 /*
199 * Tests whether a connection-oriented PDU is fragmented; returns TRUE if
200 * it's not fragmented (i.e., this is both the first *and* last fragment),
201 * and FALSE otherwise.
202 */
203 #define PFC_NOT_FRAGMENTED(hdr) \
204 ((hdr->flags&(PFC_FIRST_FRAG|PFC_LAST_FRAG)) == (PFC_FIRST_FRAG|PFC_LAST_FRAG))
205
206 /*
207 * Presentation context negotiation result.
208 */
209 static const value_string p_cont_result_vals[] = {
210 { 0, "Acceptance" },
211 { 1, "User rejection" },
212 { 2, "Provider rejection" },
213 { 3, "Negotiate ACK" }, /* [MS-RPCE] 2.2.2.4 */
214 { 0, NULL }
215 };
216
217 /*
218 * Presentation context negotiation rejection reasons.
219 */
220 static const value_string p_provider_reason_vals[] = {
221 { 0, "Reason not specified" },
222 { 1, "Abstract syntax not supported" },
223 { 2, "Proposed transfer syntaxes not supported" },
224 { 3, "Local limit exceeded" },
225 { 0, NULL }
226 };
227
228 /*
229 * Reject reasons.
230 */
231 #define REASON_NOT_SPECIFIED 0
232 #define TEMPORARY_CONGESTION 1
233 #define LOCAL_LIMIT_EXCEEDED 2
234 #define CALLED_PADDR_UNKNOWN 3 /* not used */
235 #define PROTOCOL_VERSION_NOT_SUPPORTED 4
236 #define DEFAULT_CONTEXT_NOT_SUPPORTED 5 /* not used */
237 #define USER_DATA_NOT_READABLE 6 /* not used */
238 #define NO_PSAP_AVAILABLE 7 /* not used */
239 #define AUTH_TYPE_NOT_RECOGNIZED 8 /* [MS-RPCE] 2.2.2.5 */
240 #define INVALID_CHECKSUM 9 /* [MS-RPCE] 2.2.2.5 */
241
242 static const value_string reject_reason_vals[] = {
243 { REASON_NOT_SPECIFIED, "Reason not specified" },
244 { TEMPORARY_CONGESTION, "Temporary congestion" },
245 { LOCAL_LIMIT_EXCEEDED, "Local limit exceeded" },
246 { CALLED_PADDR_UNKNOWN, "Called paddr unknown" },
247 { PROTOCOL_VERSION_NOT_SUPPORTED, "Protocol version not supported" },
248 { DEFAULT_CONTEXT_NOT_SUPPORTED, "Default context not supported" },
249 { USER_DATA_NOT_READABLE, "User data not readable" },
250 { NO_PSAP_AVAILABLE, "No PSAP available" },
251 { AUTH_TYPE_NOT_RECOGNIZED, "Authentication type not recognized" },
252 { INVALID_CHECKSUM, "Invalid checksum" },
253 { 0, NULL }
254 };
255
256 /*
257 * Reject status codes.
258 */
259 static const value_string reject_status_vals[] = {
260 { 0, "Stub-defined exception" },
261 { 0x00000001, "nca_s_fault_other" },
262 { 0x00000005, "nca_s_fault_access_denied" },
263 { 0x000006f7, "nca_s_fault_ndr" },
264 { 0x000006d8, "nca_s_fault_cant_perform" },
265 { 0x00000721, "nca_s_fault_sec_pkg_error" },
266 { 0x1c000001, "nca_s_fault_int_div_by_zero" },
267 { 0x1c000002, "nca_s_fault_addr_error" },
268 { 0x1c000003, "nca_s_fault_fp_div_zero" },
269 { 0x1c000004, "nca_s_fault_fp_underflow" },
270 { 0x1c000005, "nca_s_fault_fp_overflow" },
271 { 0x1c000006, "nca_s_fault_invalid_tag" },
272 { 0x1c000007, "nca_s_fault_invalid_bound" },
273 { 0x1c000008, "nca_rpc_version_mismatch" },
274 { 0x1c000009, "nca_unspec_reject" },
275 { 0x1c00000a, "nca_s_bad_actid" },
276 { 0x1c00000b, "nca_who_are_you_failed" },
277 { 0x1c00000c, "nca_manager_not_entered" },
278 { 0x1c00000d, "nca_s_fault_cancel" },
279 { 0x1c00000e, "nca_s_fault_ill_inst" },
280 { 0x1c00000f, "nca_s_fault_fp_error" },
281 { 0x1c000010, "nca_s_fault_int_overflow" },
282 { 0x1c000014, "nca_s_fault_pipe_empty" },
283 { 0x1c000015, "nca_s_fault_pipe_closed" },
284 { 0x1c000016, "nca_s_fault_pipe_order" },
285 { 0x1c000017, "nca_s_fault_pipe_discipline" },
286 { 0x1c000018, "nca_s_fault_pipe_comm_error" },
287 { 0x1c000019, "nca_s_fault_pipe_memory" },
288 { 0x1c00001a, "nca_s_fault_context_mismatch" },
289 { 0x1c00001b, "nca_s_fault_remote_no_memory" },
290 { 0x1c00001c, "nca_invalid_pres_context_id" },
291 { 0x1c00001d, "nca_unsupported_authn_level" },
292 { 0x1c00001f, "nca_invalid_checksum" },
293 { 0x1c000020, "nca_invalid_crc" },
294 { 0x1c000021, "ncs_s_fault_user_defined" },
295 { 0x1c000022, "nca_s_fault_tx_open_failed" },
296 { 0x1c000023, "nca_s_fault_codeset_conv_error" },
297 { 0x1c000024, "nca_s_fault_object_not_found" },
298 { 0x1c000025, "nca_s_fault_no_client_stub" },
299 { 0x1c010002, "nca_op_rng_error" },
300 { 0x1c010003, "nca_unk_if"},
301 { 0x1c010006, "nca_wrong_boot_time" },
302 { 0x1c010009, "nca_s_you_crashed" },
303 { 0x1c01000b, "nca_proto_error" },
304 { 0x1c010013, "nca_out_args_too_big" },
305 { 0x1c010014, "nca_server_too_busy" },
306 { 0x1c010017, "nca_unsupported_type" },
307 /* MS Windows specific values
308 * see: https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes--1700-3999-
309 * and: https://docs.microsoft.com/en-us/windows/win32/seccrypto/common-hresult-values
310 * and: https://web.archive.org/web/20150825015741/http://www.megos.ch/support/doserrors.txt
311 *
312 * XXX - we might need a way to dynamically add entries here, as higher layer protocols use these values too,
313 * at least MS protocols (like DCOM) do it that way ... */
314 { 0x80004001, "E_NOTIMPL" },
315 { 0x80004003, "E_POINTER" },
316 { 0x80004004, "E_ABORT" },
317 { 0x8000FFFF, "E_UNEXPECTED" },
318 { 0x80010105, "RPC_E_SERVERFAULT" },
319 { 0x80010108, "RPC_E_DISCONNECTED" },
320 { 0x80010113, "RPC_E_INVALID_IPID" },
321 { 0x8001011F, "RPC_E_TIMEOUT" },
322 { 0x80020003, "DISP_E_MEMBERNOTFOUND" },
323 { 0x80020006, "DISP_E_UNKNOWNNAME" },
324 { 0x8002000E, "DISP_E_BADPARAMCOUNT" },
325 { 0x8004CB00, "CBA_E_MALFORMED" },
326 { 0x8004CB01, "CBA_E_UNKNOWNOBJECT" },
327 { 0x8004CB05, "CBA_E_INVALIDID" },
328 { 0x8004CB09, "CBA_E_INVALIDCOOKIE" },
329 { 0x8004CB0B, "CBA_E_QOSTYPEUNSUPPORTED" },
330 { 0x8004CB0C, "CBA_E_QOSVALUEUNSUPPORTED" },
331 { 0x8004CB0F, "CBA_E_NOTAPPLICABLE" },
332 { 0x8004CB12, "CBA_E_LIMITVIOLATION" },
333 { 0x8004CB13, "CBA_E_QOSTYPENOTAPPLICABLE" },
334 { 0x8004CB18, "CBA_E_OUTOFPARTNERACCOS" },
335 { 0x8004CB1C, "CBA_E_FLAGUNSUPPORTED" },
336 { 0x8004CB23, "CBA_E_FRAMECOUNTUNSUPPORTED" },
337 { 0x8004CB25, "CBA_E_MODECHANGE" },
338 { 0x8007000E, "E_OUTOFMEMORY" },
339 { 0x80070057, "E_INVALIDARG" },
340 { 0x800706d1, "RPC_S_PROCNUM_OUT_OF_RANGE" },
341 { 0x80070776, "OR_INVALID_OXID" },
342 { 0, NULL }
343 };
344
345
346 /*
347 * RTS Flags
348 */
349 #define RTS_FLAG_NONE 0x0000
350 #define RTS_FLAG_PING 0x0001
351 #define RTS_FLAG_OTHER_CMD 0x0002
352 #define RTS_FLAG_RECYCLE_CHANNEL 0x0004
353 #define RTS_FLAG_IN_CHANNEL 0x0008
354 #define RTS_FLAG_OUT_CHANNEL 0x0010
355 #define RTS_FLAG_EOF 0x0020
356 #define RTS_FLAG_ECHO 0x0040
357
358 /*
359 * RTS Commands
360 */
361
362 #define RTS_CMD_RECEIVEWINDOWSIZE 0x0
363 #define RTS_CMD_FLOWCONTROLACK 0x1
364 #define RTS_CMD_CONNECTIONTIMEOUT 0x2
365 #define RTS_CMD_COOKIE 0x3
366 #define RTS_CMD_CHANNELLIFETIME 0x4
367 #define RTS_CMD_CLIENTKEEPALIVE 0x5
368 #define RTS_CMD_VERSION 0x6
369 #define RTS_CMD_EMPTY 0x7
370 #define RTS_CMD_PADDING 0x8
371 #define RTS_CMD_NEGATIVEANCE 0x9
372 #define RTS_CMD_ANCE 0xA
373 #define RTS_CMD_CLIENTADDRESS 0xB
374 #define RTS_CMD_ASSOCIATIONGROUPID 0xC
375 #define RTS_CMD_DESTINATION 0xD
376 #define RTS_CMD_PINGTRAFFICSENTNOTIFY 0xE
377
378 static const value_string rts_command_vals[] = {
379 { RTS_CMD_RECEIVEWINDOWSIZE, "ReceiveWindowSize" },
380 { RTS_CMD_FLOWCONTROLACK, "FlowControlAck" },
381 { RTS_CMD_CONNECTIONTIMEOUT, "ConnectionTimeOut" },
382 { RTS_CMD_COOKIE, "Cookie" },
383 { RTS_CMD_CHANNELLIFETIME, "ChannelLifetime" },
384 { RTS_CMD_CLIENTKEEPALIVE, "ClientKeepalive" },
385 { RTS_CMD_VERSION, "Version" },
386 { RTS_CMD_EMPTY, "Empty" },
387 { RTS_CMD_PADDING, "Padding" },
388 { RTS_CMD_NEGATIVEANCE, "NegativeANCE" },
389 { RTS_CMD_ANCE, "ANCE" },
390 { RTS_CMD_CLIENTADDRESS, "ClientAddress" },
391 { RTS_CMD_ASSOCIATIONGROUPID, "AssociationGroupId" },
392 { RTS_CMD_DESTINATION, "Destination" },
393 { RTS_CMD_PINGTRAFFICSENTNOTIFY, "PingTrafficSentNotify" },
394 { 0x0, NULL }
395 };
396
397 /*
398 * RTS client address type
399 */
400 #define RTS_IPV4 0
401 #define RTS_IPV6 1
402
403 static const value_string rts_addresstype_vals[] = {
404 { RTS_IPV4, "IPV4" },
405 { RTS_IPV6, "IPV6" },
406 { 0x0, NULL }
407 };
408
409 /*
410 * RTS Forward destination
411 */
412
413 static const value_string rts_forward_destination_vals[] = {
414 { 0x0, "FDClient" },
415 { 0x1, "FDInProxy" },
416 { 0x2, "FDServer" },
417 { 0x3, "FDOutProxy" },
418 { 0x0, NULL }
419 };
420
421 /* we need to keep track of what transport were used, ie what handle we came
422 * in through so we know what kind of pinfo->dce_smb_fid was passed to us.
423 */
424 /* Value of -1 is reserved for "not DCE packet" in packet_info.dcetransporttype. */
425 #define DCE_TRANSPORT_UNKNOWN 0
426 #define DCE_CN_TRANSPORT_SMBPIPE 1
427
428
429 static int proto_dcerpc = -1;
430
431 /* field defines */
432 static int hf_dcerpc_request_in = -1;
433 static int hf_dcerpc_time = -1;
434 static int hf_dcerpc_response_in = -1;
435 static int hf_dcerpc_ver = -1;
436 static int hf_dcerpc_ver_minor = -1;
437 static int hf_dcerpc_packet_type = -1;
438 static int hf_dcerpc_cn_flags = -1;
439 static int hf_dcerpc_cn_flags_first_frag = -1;
440 static int hf_dcerpc_cn_flags_last_frag = -1;
441 static int hf_dcerpc_cn_flags_cancel_pending = -1;
442 static int hf_dcerpc_cn_flags_reserved = -1;
443 static int hf_dcerpc_cn_flags_mpx = -1;
444 static int hf_dcerpc_cn_flags_dne = -1;
445 static int hf_dcerpc_cn_flags_maybe = -1;
446 static int hf_dcerpc_cn_flags_object = -1;
447 static int hf_dcerpc_drep = -1;
448 int hf_dcerpc_drep_byteorder = -1;
449 int hf_dcerpc_ndr_padding = -1;
450 static int hf_dcerpc_drep_character = -1;
451 static int hf_dcerpc_drep_fp = -1;
452 static int hf_dcerpc_cn_frag_len = -1;
453 static int hf_dcerpc_cn_auth_len = -1;
454 static int hf_dcerpc_cn_call_id = -1;
455 static int hf_dcerpc_cn_max_xmit = -1;
456 static int hf_dcerpc_cn_max_recv = -1;
457 static int hf_dcerpc_cn_assoc_group = -1;
458 static int hf_dcerpc_cn_num_ctx_items = -1;
459 static int hf_dcerpc_cn_ctx_item = -1;
460 static int hf_dcerpc_cn_ctx_id = -1;
461 static int hf_dcerpc_cn_num_trans_items = -1;
462 static int hf_dcerpc_cn_bind_abstract_syntax = -1;
463 static int hf_dcerpc_cn_bind_if_id = -1;
464 static int hf_dcerpc_cn_bind_if_ver = -1;
465 static int hf_dcerpc_cn_bind_if_ver_minor = -1;
466 static int hf_dcerpc_cn_bind_trans_syntax = -1;
467 static int hf_dcerpc_cn_bind_trans_id = -1;
468 static int hf_dcerpc_cn_bind_trans_ver = -1;
469 static int hf_dcerpc_cn_bind_trans_btfn = -1;
470 static int hf_dcerpc_cn_bind_trans_btfn_01 = -1;
471 static int hf_dcerpc_cn_bind_trans_btfn_02 = -1;
472 static int hf_dcerpc_cn_alloc_hint = -1;
473 static int hf_dcerpc_cn_sec_addr_len = -1;
474 static int hf_dcerpc_cn_sec_addr = -1;
475 static int hf_dcerpc_cn_num_results = -1;
476 static int hf_dcerpc_cn_ack_result = -1;
477 static int hf_dcerpc_cn_ack_reason = -1;
478 static int hf_dcerpc_cn_ack_trans_id = -1;
479 static int hf_dcerpc_cn_ack_trans_ver = -1;
480 static int hf_dcerpc_cn_reject_reason = -1;
481 static int hf_dcerpc_cn_num_protocols = -1;
482 static int hf_dcerpc_cn_protocol_ver_major = -1;
483 static int hf_dcerpc_cn_protocol_ver_minor = -1;
484 static int hf_dcerpc_cn_cancel_count = -1;
485 static int hf_dcerpc_cn_fault_flags = -1;
486 static int hf_dcerpc_cn_fault_flags_extended_error_info = -1;
487 static int hf_dcerpc_cn_status = -1;
488 static int hf_dcerpc_cn_deseg_req = -1;
489 static int hf_dcerpc_cn_rts_flags = -1;
490 static int hf_dcerpc_cn_rts_flags_ping = -1;
491 static int hf_dcerpc_cn_rts_flags_other_cmd = -1;
492 static int hf_dcerpc_cn_rts_flags_recycle_channel = -1;
493 static int hf_dcerpc_cn_rts_flags_in_channel = -1;
494 static int hf_dcerpc_cn_rts_flags_out_channel = -1;
495 static int hf_dcerpc_cn_rts_flags_eof = -1;
496 static int hf_dcerpc_cn_rts_commands_nb = -1;
497 static int hf_dcerpc_cn_rts_command = -1;
498 static int hf_dcerpc_cn_rts_command_receivewindowsize = -1;
499 static int hf_dcerpc_cn_rts_command_fack_bytesreceived = -1;
500 static int hf_dcerpc_cn_rts_command_fack_availablewindow = -1;
501 static int hf_dcerpc_cn_rts_command_fack_channelcookie = -1;
502 static int hf_dcerpc_cn_rts_command_connectiontimeout = -1;
503 static int hf_dcerpc_cn_rts_command_cookie = -1;
504 static int hf_dcerpc_cn_rts_command_channellifetime = -1;
505 static int hf_dcerpc_cn_rts_command_clientkeepalive = -1;
506 static int hf_dcerpc_cn_rts_command_version = -1;
507 static int hf_dcerpc_cn_rts_command_conformancecount = -1;
508 static int hf_dcerpc_cn_rts_command_padding = -1;
509 static int hf_dcerpc_cn_rts_command_addrtype = -1;
510 static int hf_dcerpc_cn_rts_command_associationgroupid = -1;
511 static int hf_dcerpc_cn_rts_command_forwarddestination = -1;
512 static int hf_dcerpc_cn_rts_command_pingtrafficsentnotify = -1;
513 static int hf_dcerpc_auth_type = -1;
514 static int hf_dcerpc_auth_level = -1;
515 static int hf_dcerpc_auth_pad_len = -1;
516 static int hf_dcerpc_auth_rsrvd = -1;
517 static int hf_dcerpc_auth_ctx_id = -1;
518 static int hf_dcerpc_dg_flags1 = -1;
519 static int hf_dcerpc_dg_flags1_rsrvd_01 = -1;
520 static int hf_dcerpc_dg_flags1_last_frag = -1;
521 static int hf_dcerpc_dg_flags1_frag = -1;
522 static int hf_dcerpc_dg_flags1_nofack = -1;
523 static int hf_dcerpc_dg_flags1_maybe = -1;
524 static int hf_dcerpc_dg_flags1_idempotent = -1;
525 static int hf_dcerpc_dg_flags1_broadcast = -1;
526 static int hf_dcerpc_dg_flags1_rsrvd_80 = -1;
527 static int hf_dcerpc_dg_flags2 = -1;
528 static int hf_dcerpc_dg_flags2_rsrvd_01 = -1;
529 static int hf_dcerpc_dg_flags2_cancel_pending = -1;
530 static int hf_dcerpc_dg_flags2_rsrvd_04 = -1;
531 static int hf_dcerpc_dg_flags2_rsrvd_08 = -1;
532 static int hf_dcerpc_dg_flags2_rsrvd_10 = -1;
533 static int hf_dcerpc_dg_flags2_rsrvd_20 = -1;
534 static int hf_dcerpc_dg_flags2_rsrvd_40 = -1;
535 static int hf_dcerpc_dg_flags2_rsrvd_80 = -1;
536 static int hf_dcerpc_dg_serial_hi = -1;
537 static int hf_dcerpc_obj_id = -1;
538 static int hf_dcerpc_dg_if_id = -1;
539 static int hf_dcerpc_dg_act_id = -1;
540 static int hf_dcerpc_dg_serial_lo = -1;
541 static int hf_dcerpc_dg_ahint = -1;
542 static int hf_dcerpc_dg_ihint = -1;
543 static int hf_dcerpc_dg_frag_len = -1;
544 static int hf_dcerpc_dg_frag_num = -1;
545 static int hf_dcerpc_dg_auth_proto = -1;
546 static int hf_dcerpc_opnum = -1;
547 static int hf_dcerpc_dg_seqnum = -1;
548 static int hf_dcerpc_dg_server_boot = -1;
549 static int hf_dcerpc_dg_if_ver = -1;
550 static int hf_dcerpc_krb5_av_prot_level = -1;
551 static int hf_dcerpc_krb5_av_key_vers_num = -1;
552 static int hf_dcerpc_krb5_av_key_auth_verifier = -1;
553 static int hf_dcerpc_dg_cancel_vers = -1;
554 static int hf_dcerpc_dg_cancel_id = -1;
555 static int hf_dcerpc_dg_server_accepting_cancels = -1;
556 static int hf_dcerpc_dg_fack_vers = -1;
557 static int hf_dcerpc_dg_fack_window_size = -1;
558 static int hf_dcerpc_dg_fack_max_tsdu = -1;
559 static int hf_dcerpc_dg_fack_max_frag_size = -1;
560 static int hf_dcerpc_dg_fack_serial_num = -1;
561 static int hf_dcerpc_dg_fack_selack_len = -1;
562 static int hf_dcerpc_dg_fack_selack = -1;
563 static int hf_dcerpc_dg_status = -1;
564 static int hf_dcerpc_array_max_count = -1;
565 static int hf_dcerpc_array_offset = -1;
566 static int hf_dcerpc_array_actual_count = -1;
567 static int hf_dcerpc_op = -1;
568 static int hf_dcerpc_referent_id32 = -1;
569 static int hf_dcerpc_referent_id64 = -1;
570 static int hf_dcerpc_null_pointer = -1;
571 static int hf_dcerpc_fragments = -1;
572 static int hf_dcerpc_fragment = -1;
573 static int hf_dcerpc_fragment_overlap = -1;
574 static int hf_dcerpc_fragment_overlap_conflict = -1;
575 static int hf_dcerpc_fragment_multiple_tails = -1;
576 static int hf_dcerpc_fragment_too_long_fragment = -1;
577 static int hf_dcerpc_fragment_error = -1;
578 static int hf_dcerpc_fragment_count = -1;
579 static int hf_dcerpc_reassembled_in = -1;
580 static int hf_dcerpc_reassembled_length = -1;
581 static int hf_dcerpc_unknown_if_id = -1;
582 static int hf_dcerpc_sec_vt_signature = -1;
583 static int hf_dcerpc_sec_vt_command = -1;
584 static int hf_dcerpc_sec_vt_command_cmd = -1;
585 static int hf_dcerpc_sec_vt_command_end = -1;
586 static int hf_dcerpc_sec_vt_command_must = -1;
587 static int hf_dcerpc_sec_vt_command_length = -1;
588 static int hf_dcerpc_sec_vt_bitmask = -1;
589 static int hf_dcerpc_sec_vt_bitmask_sign = -1;
590 static int hf_dcerpc_sec_vt_pcontext_uuid = -1;
591 static int hf_dcerpc_sec_vt_pcontext_ver = -1;
592
593 static int * const 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
598 };
599 static int hf_dcerpc_reserved = -1;
600 static int hf_dcerpc_unknown = -1;
601 static int hf_dcerpc_missalign = -1;
602
603 /* Generated from convert_proto_tree_add_text.pl */
604 static int hf_dcerpc_duplicate_ptr = -1;
605 static int hf_dcerpc_encrypted_stub_data = -1;
606 static int hf_dcerpc_decrypted_stub_data = -1;
607 static int hf_dcerpc_payload_stub_data = -1;
608 static int hf_dcerpc_stub_data_with_sec_vt = -1;
609 static int hf_dcerpc_stub_data = -1;
610 static int hf_dcerpc_auth_padding = -1;
611 static int hf_dcerpc_auth_info = -1;
612 static int hf_dcerpc_auth_credentials = -1;
613 static int hf_dcerpc_fault_stub_data = -1;
614 static int hf_dcerpc_fragment_data = -1;
615 static int hf_dcerpc_cmd_client_ipv4 = -1;
616 static int hf_dcerpc_cmd_client_ipv6 = -1;
617 static int hf_dcerpc_authentication_verifier = -1;
618
619 static int * const dcerpc_cn_bind_trans_btfn_fields[] = {
620 &hf_dcerpc_cn_bind_trans_btfn_01,
621 &hf_dcerpc_cn_bind_trans_btfn_02,
622 NULL
623 };
624
625 static int * const sec_vt_bitmask_fields[] = {
626 &hf_dcerpc_sec_vt_bitmask_sign,
627 NULL
628 };
629
630 static int * const dcerpc_cn_fault_flags_fields[] = {
631 &hf_dcerpc_cn_fault_flags_extended_error_info,
632 NULL
633 };
634
635 static const value_string sec_vt_command_cmd_vals[] = {
636 {1, "BITMASK_1"},
637 {2, "PCONTEXT"},
638 {3, "HEADER2"},
639 {0, NULL}
640 };
641
642 static gint ett_dcerpc = -1;
643 static gint ett_dcerpc_cn_flags = -1;
644 static gint ett_dcerpc_cn_ctx = -1;
645 static gint ett_dcerpc_cn_iface = -1;
646 static gint ett_dcerpc_cn_trans_syntax = -1;
647 static gint ett_dcerpc_cn_trans_btfn = -1;
648 static gint ett_dcerpc_cn_bind_trans_btfn = -1;
649 static gint ett_dcerpc_cn_rts_flags = -1;
650 static gint ett_dcerpc_cn_rts_command = -1;
651 static gint ett_dcerpc_cn_rts_pdu = -1;
652 static gint ett_dcerpc_drep = -1;
653 static gint ett_dcerpc_dg_flags1 = -1;
654 static gint ett_dcerpc_dg_flags2 = -1;
655 static gint ett_dcerpc_pointer_data = -1;
656 static gint ett_dcerpc_string = -1;
657 static gint ett_dcerpc_fragments = -1;
658 static gint ett_dcerpc_fragment = -1;
659 static gint ett_dcerpc_krb5_auth_verf = -1;
660 static gint ett_dcerpc_auth_info = -1;
661 static gint ett_dcerpc_verification_trailer = -1;
662 static gint ett_dcerpc_sec_vt_command = -1;
663 static gint ett_dcerpc_sec_vt_bitmask = -1;
664 static gint ett_dcerpc_sec_vt_pcontext = -1;
665 static gint ett_dcerpc_sec_vt_header = -1;
666 static gint ett_dcerpc_complete_stub_data = -1;
667 static gint ett_dcerpc_fault_flags = -1;
668 static gint ett_dcerpc_fault_stub_data = -1;
669
670 static expert_field ei_dcerpc_fragment_multiple = EI_INIT;
671 static expert_field ei_dcerpc_cn_status = EI_INIT;
672 static expert_field ei_dcerpc_fragment_reassembled = EI_INIT;
673 static expert_field ei_dcerpc_fragment = EI_INIT;
674 static expert_field ei_dcerpc_no_request_found = EI_INIT;
675 /* static expert_field ei_dcerpc_context_change = EI_INIT; */
676 static expert_field ei_dcerpc_cn_ctx_id_no_bind = EI_INIT;
677 static expert_field ei_dcerpc_bind_not_acknowledged = EI_INIT;
678 static expert_field ei_dcerpc_verifier_unavailable = EI_INIT;
679 static expert_field ei_dcerpc_invalid_pdu_authentication_attempt = EI_INIT;
680 /* Generated from convert_proto_tree_add_text.pl */
681 static expert_field ei_dcerpc_long_frame = EI_INIT;
682 static expert_field ei_dcerpc_cn_rts_command = EI_INIT;
683 static expert_field ei_dcerpc_not_implemented = EI_INIT;
684
685 static const guint8 TRAILER_SIGNATURE[] = {0x8a, 0xe3, 0x13, 0x71, 0x02, 0xf4, 0x36, 0x71};
686 static tvbuff_t *tvb_trailer_signature = NULL;
687
688 static GSList *decode_dcerpc_bindings = NULL;
689 /*
690 * To keep track of ctx_id mappings.
691 *
692 * Every time we see a bind call we update this table.
693 * Note that we always specify a SMB FID. For non-SMB transports this
694 * value is 0.
695 */
696 static wmem_map_t *dcerpc_binds = NULL;
697
698 typedef struct _dcerpc_bind_key {
699 conversation_t *conv;
700 guint16 ctx_id;
701 guint64 transport_salt;
702 } dcerpc_bind_key;
703
704 typedef struct _dcerpc_bind_value {
705 e_guid_t uuid;
706 guint16 ver;
707 e_guid_t transport;
708 } dcerpc_bind_value;
709
710 static wmem_map_t *dcerpc_auths = NULL;
711
712 typedef struct _dcerpc_auth_context {
713 conversation_t *conv;
714 guint64 transport_salt;
715 guint8 auth_type;
716 guint8 auth_level;
717 guint32 auth_context_id;
718 guint32 first_frame;
719 gboolean hdr_signing;
720 } dcerpc_auth_context;
721
722 /* Extra data for DCERPC handling and tracking of context ids */
723 typedef struct _dcerpc_decode_as_data {
724 guint16 dcectxid; /**< Context ID (DCERPC-specific) */
725 int dcetransporttype; /**< Transport type
726 * Value -1 means "not a DCERPC packet"
727 */
728 guint64 dcetransportsalt; /**< fid: if transporttype==DCE_CN_TRANSPORT_SMBPIPE */
729 } dcerpc_decode_as_data;
730
731 static dcerpc_decode_as_data*
dcerpc_get_decode_data(packet_info * pinfo)732 dcerpc_get_decode_data(packet_info* pinfo)
733 {
734 dcerpc_decode_as_data* data = (dcerpc_decode_as_data*)p_get_proto_data(pinfo->pool, pinfo, proto_dcerpc, 0);
735 if (data == NULL)
736 {
737 data = wmem_new0(pinfo->pool, dcerpc_decode_as_data);
738 data->dcetransporttype = -1;
739 p_add_proto_data(pinfo->pool, pinfo, proto_dcerpc, 0, data);
740 }
741
742 return data;
743 }
744
745 /**
746 * Registers a conversation/UUID binding association, so that
747 * we can invoke the proper sub-dissector for a given DCERPC
748 * conversation.
749 *
750 * @param binding all values needed to create and bind a new conversation
751 *
752 * @return Pointer to newly-added UUID/conversation binding.
753 */
754 static struct _dcerpc_bind_value *
dcerpc_add_conv_to_bind_table(decode_dcerpc_bind_values_t * binding)755 dcerpc_add_conv_to_bind_table(decode_dcerpc_bind_values_t *binding)
756 {
757 dcerpc_bind_value *bind_value;
758 dcerpc_bind_key *key;
759 conversation_t *conv;
760
761 conv = find_conversation(
762 0,
763 &binding->addr_a,
764 &binding->addr_b,
765 conversation_pt_to_endpoint_type(binding->ptype),
766 binding->port_a,
767 binding->port_b,
768 0);
769
770 if (!conv) {
771 conv = conversation_new(
772 0,
773 &binding->addr_a,
774 &binding->addr_b,
775 conversation_pt_to_endpoint_type(binding->ptype),
776 binding->port_a,
777 binding->port_b,
778 0);
779 }
780
781 bind_value = wmem_new(wmem_file_scope(), dcerpc_bind_value);
782 bind_value->uuid = binding->uuid;
783 bind_value->ver = binding->ver;
784 /* For now, assume all DCE/RPC we pick from "decode as" is using
785 standard ndr and not ndr64.
786 We should make this selectable from the dialog in the future
787 */
788 bind_value->transport = uuid_data_repr_proto;
789
790 key = wmem_new(wmem_file_scope(), dcerpc_bind_key);
791 key->conv = conv;
792 key->ctx_id = binding->ctx_id;
793 key->transport_salt = binding->transport_salt;
794
795 /* add this entry to the bind table */
796 wmem_map_insert(dcerpc_binds, key, bind_value);
797
798 return bind_value;
799
800 }
801
802 /* inject one of our bindings into the dcerpc binding table */
803 static void
decode_dcerpc_inject_binding(gpointer data,gpointer user_data _U_)804 decode_dcerpc_inject_binding(gpointer data, gpointer user_data _U_)
805 {
806 dcerpc_add_conv_to_bind_table((decode_dcerpc_bind_values_t *) data);
807 }
808
809 /* inject all of our bindings into the dcerpc binding table */
810 static void
decode_dcerpc_inject_bindings(void)811 decode_dcerpc_inject_bindings(void) {
812 g_slist_foreach(decode_dcerpc_bindings, decode_dcerpc_inject_binding, NULL /* user_data */);
813 }
814
815 /* free a binding */
816 static void
decode_dcerpc_binding_free(void * binding_in)817 decode_dcerpc_binding_free(void *binding_in)
818 {
819 decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t *)binding_in;
820
821 free_address(&binding->addr_a);
822 free_address(&binding->addr_b);
823 if (binding->ifname)
824 g_string_free(binding->ifname, TRUE);
825 g_free(binding);
826 }
827
828 static void
dcerpc_decode_as_free(gpointer value)829 dcerpc_decode_as_free(gpointer value)
830 {
831 decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t *)value;
832 if (binding != NULL)
833 decode_dcerpc_binding_free(binding);
834 }
835
836 /* removes all bindings */
837 void
decode_dcerpc_reset_all(void)838 decode_dcerpc_reset_all(void)
839 {
840 decode_dcerpc_bind_values_t *binding;
841
842 while (decode_dcerpc_bindings) {
843 binding = (decode_dcerpc_bind_values_t *)decode_dcerpc_bindings->data;
844
845 decode_dcerpc_bindings = g_slist_remove(
846 decode_dcerpc_bindings,
847 decode_dcerpc_bindings->data);
848 decode_dcerpc_binding_free(binding);
849 }
850 }
851
852
853 void
decode_dcerpc_add_show_list(decode_add_show_list_func func,gpointer user_data)854 decode_dcerpc_add_show_list(decode_add_show_list_func func, gpointer user_data)
855 {
856 g_slist_foreach(decode_dcerpc_bindings, func, user_data);
857 }
858
859 static void
dcerpc_prompt(packet_info * pinfo,gchar * result)860 dcerpc_prompt(packet_info *pinfo, gchar* result)
861 {
862 GString *str = g_string_new("Replace binding between:\r\n"),
863 *address_str = g_string_new("");
864 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
865
866 switch (pinfo->ptype) {
867 case(PT_TCP):
868 g_string_append(address_str, "Address: ToBeDone TCP port");
869 break;
870 case(PT_UDP):
871 g_string_append(address_str, "Address: ToBeDone UDP port");
872 break;
873 default:
874 g_string_append(address_str, "Address: ToBeDone Unknown port type");
875 }
876
877 g_string_append_printf(str, "%s: %u\r\n", address_str->str, pinfo->srcport);
878 g_string_append(str, "&\r\n");
879 g_string_append_printf(str, "%s: %u\r\n", address_str->str, pinfo->destport);
880 g_string_append_printf(str, "&\r\nContext ID: %u\r\n", decode_data->dcectxid);
881 g_string_append_printf(str, "&\r\nSMB FID: %"G_GINT64_MODIFIER"u\r\n",
882 dcerpc_get_transport_salt(pinfo));
883 g_string_append(str, "with:\r\n");
884
885 (void) g_strlcpy(result, str->str, MAX_DECODE_AS_PROMPT_LEN);
886 g_string_free(str, TRUE);
887 g_string_free(address_str, TRUE);
888 }
889
890 static gpointer
dcerpc_value(packet_info * pinfo)891 dcerpc_value(packet_info *pinfo)
892 {
893 decode_dcerpc_bind_values_t *binding;
894 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
895
896 /* clone binding */
897 binding = g_new(decode_dcerpc_bind_values_t,1);
898 copy_address(&binding->addr_a, &pinfo->src);
899 copy_address(&binding->addr_b, &pinfo->dst);
900 binding->ptype = pinfo->ptype;
901 binding->port_a = pinfo->srcport;
902 binding->port_b = pinfo->destport;
903 binding->ctx_id = decode_data->dcectxid;
904 binding->transport_salt = dcerpc_get_transport_salt(pinfo);
905 binding->ifname = NULL;
906 /*binding->uuid = NULL;*/
907 binding->ver = 0;
908
909 return binding;
910 }
911
912 struct dcerpc_decode_as_populate
913 {
914 decode_as_add_to_list_func add_to_list;
915 gpointer ui_element;
916 };
917
918 static void
decode_dcerpc_add_to_list(gpointer key,gpointer value,gpointer user_data)919 decode_dcerpc_add_to_list(gpointer key, gpointer value, gpointer user_data)
920 {
921 struct dcerpc_decode_as_populate* populate = (struct dcerpc_decode_as_populate*)user_data;
922
923 /*guid_key *k = key;*/
924 dcerpc_uuid_value *v = (dcerpc_uuid_value *)value;
925
926 if (strcmp(v->name, "(none)"))
927 populate->add_to_list("DCE-RPC", v->name, key, populate->ui_element);
928 }
929
930 static void
dcerpc_populate_list(const gchar * table_name _U_,decode_as_add_to_list_func add_to_list,gpointer ui_element)931 dcerpc_populate_list(const gchar *table_name _U_, decode_as_add_to_list_func add_to_list, gpointer ui_element)
932 {
933 struct dcerpc_decode_as_populate populate;
934
935 populate.add_to_list = add_to_list;
936 populate.ui_element = ui_element;
937
938 g_hash_table_foreach(dcerpc_uuids, decode_dcerpc_add_to_list, &populate);
939 }
940
941 /* compare two bindings (except the interface related things, e.g. uuid) */
942 static gint
decode_dcerpc_binding_cmp(gconstpointer a,gconstpointer b)943 decode_dcerpc_binding_cmp(gconstpointer a, gconstpointer b)
944 {
945 const decode_dcerpc_bind_values_t *binding_a = (const decode_dcerpc_bind_values_t *)a;
946 const decode_dcerpc_bind_values_t *binding_b = (const decode_dcerpc_bind_values_t *)b;
947
948
949 /* don't compare uuid and ver! */
950 if (
951 addresses_equal(&binding_a->addr_a, &binding_b->addr_a) &&
952 addresses_equal(&binding_a->addr_b, &binding_b->addr_b) &&
953 binding_a->ptype == binding_b->ptype &&
954 binding_a->port_a == binding_b->port_a &&
955 binding_a->port_b == binding_b->port_b &&
956 binding_a->ctx_id == binding_b->ctx_id &&
957 binding_a->transport_salt == binding_b->transport_salt)
958 {
959 /* equal */
960 return 0;
961 }
962
963 /* unequal */
964 return 1;
965 }
966
967 /* remove a binding (looking the same way as the given one) */
968 static gboolean
decode_dcerpc_binding_reset(const char * name _U_,gconstpointer pattern)969 decode_dcerpc_binding_reset(const char *name _U_, gconstpointer pattern)
970 {
971 const decode_dcerpc_bind_values_t *binding = (const decode_dcerpc_bind_values_t *)pattern;
972 GSList *le;
973 decode_dcerpc_bind_values_t *old_binding;
974
975 /* find the old binding (if it exists) */
976 le = g_slist_find_custom(decode_dcerpc_bindings,
977 binding,
978 decode_dcerpc_binding_cmp);
979 if (le == NULL)
980 return FALSE;
981
982 old_binding = (decode_dcerpc_bind_values_t *)le->data;
983
984 decode_dcerpc_bindings = g_slist_remove(decode_dcerpc_bindings, le->data);
985
986 free_address(&old_binding->addr_a);
987 free_address(&old_binding->addr_b);
988 g_string_free(old_binding->ifname, TRUE);
989 g_free(old_binding);
990 return FALSE;
991 }
992
993 static gboolean
dcerpc_decode_as_change(const char * name,gconstpointer pattern,gconstpointer handle,const gchar * list_name)994 dcerpc_decode_as_change(const char *name, gconstpointer pattern, gconstpointer handle, const gchar* list_name)
995 {
996 const decode_dcerpc_bind_values_t *binding = (const decode_dcerpc_bind_values_t*)pattern;
997 decode_dcerpc_bind_values_t *stored_binding;
998 guid_key *key = *((guid_key *const *)handle);
999
1000 /* remove a probably existing old binding */
1001 decode_dcerpc_binding_reset(name, binding);
1002
1003 /*
1004 * Clone the new binding, update the changing parts, and append it
1005 * to the list.
1006 */
1007 stored_binding = g_new(decode_dcerpc_bind_values_t,1);
1008 *stored_binding = *binding;
1009 copy_address(&stored_binding->addr_a, &binding->addr_a);
1010 copy_address(&stored_binding->addr_b, &binding->addr_b);
1011 stored_binding->ifname = g_string_new(list_name);
1012 stored_binding->uuid = key->guid;
1013 stored_binding->ver = key->ver;
1014
1015 decode_dcerpc_bindings = g_slist_append (decode_dcerpc_bindings, stored_binding);
1016
1017 return FALSE;
1018 }
1019
1020 static const fragment_items dcerpc_frag_items = {
1021 &ett_dcerpc_fragments,
1022 &ett_dcerpc_fragment,
1023
1024 &hf_dcerpc_fragments,
1025 &hf_dcerpc_fragment,
1026 &hf_dcerpc_fragment_overlap,
1027 &hf_dcerpc_fragment_overlap_conflict,
1028 &hf_dcerpc_fragment_multiple_tails,
1029 &hf_dcerpc_fragment_too_long_fragment,
1030 &hf_dcerpc_fragment_error,
1031 &hf_dcerpc_fragment_count,
1032 NULL,
1033 &hf_dcerpc_reassembled_length,
1034 /* Reassembled data field */
1035 NULL,
1036 "fragments"
1037 };
1038
1039 /* try to desegment big DCE/RPC packets over TCP? */
1040 static gboolean dcerpc_cn_desegment = TRUE;
1041
1042 /* reassemble DCE/RPC fragments */
1043 /* reassembly of cl dcerpc fragments will not work for the case where ONE frame
1044 might contain multiple dcerpc fragments for different PDUs.
1045 this case would be so unusual/weird so if you got captures like that:
1046 too bad
1047
1048 reassembly of co dcerpc fragments will not work for the case where TCP/SMB frames
1049 are coming in out of sequence, but that will hurt in a lot of other places as well.
1050 */
1051 static gboolean dcerpc_reassemble = TRUE;
1052 static reassembly_table dcerpc_co_reassembly_table;
1053 static reassembly_table dcerpc_cl_reassembly_table;
1054
1055 typedef struct _dcerpc_fragment_key {
1056 address src;
1057 address dst;
1058 guint32 id;
1059 e_guid_t act_id;
1060 } dcerpc_fragment_key;
1061
1062 static guint
dcerpc_fragment_hash(gconstpointer k)1063 dcerpc_fragment_hash(gconstpointer k)
1064 {
1065 const dcerpc_fragment_key* key = (const dcerpc_fragment_key*) k;
1066 guint hash_val;
1067
1068 hash_val = 0;
1069
1070 hash_val += key->id;
1071 hash_val += key->act_id.data1;
1072 hash_val += key->act_id.data2 << 16;
1073 hash_val += key->act_id.data3;
1074
1075 return hash_val;
1076 }
1077
1078 static gint
dcerpc_fragment_equal(gconstpointer k1,gconstpointer k2)1079 dcerpc_fragment_equal(gconstpointer k1, gconstpointer k2)
1080 {
1081 const dcerpc_fragment_key* key1 = (const dcerpc_fragment_key*) k1;
1082 const dcerpc_fragment_key* key2 = (const dcerpc_fragment_key*) k2;
1083
1084 /*key.id is the first item to compare since item is most
1085 likely to differ between sessions, thus shortcircuiting
1086 the comparison of addresses.
1087 */
1088 return (((key1->id == key2->id)
1089 && (addresses_equal(&key1->src, &key2->src))
1090 && (addresses_equal(&key1->dst, &key2->dst))
1091 && (memcmp (&key1->act_id, &key2->act_id, sizeof (e_guid_t)) == 0))
1092 ? TRUE : FALSE);
1093 }
1094
1095 /* allocate a persistent dcerpc fragment key to insert in the hash */
1096 static void *
dcerpc_fragment_temporary_key(const packet_info * pinfo,const guint32 id,const void * data)1097 dcerpc_fragment_temporary_key(const packet_info *pinfo, const guint32 id,
1098 const void *data)
1099 {
1100 dcerpc_fragment_key *key = g_slice_new(dcerpc_fragment_key);
1101 const e_dce_dg_common_hdr_t *hdr = (const e_dce_dg_common_hdr_t *)data;
1102
1103 copy_address_shallow(&key->src, &pinfo->src);
1104 copy_address_shallow(&key->dst, &pinfo->dst);
1105 key->id = id;
1106 key->act_id = hdr->act_id;
1107
1108 return key;
1109 }
1110
1111 /* allocate a persistent dcerpc fragment key to insert in the hash */
1112 static void *
dcerpc_fragment_persistent_key(const packet_info * pinfo,const guint32 id,const void * data)1113 dcerpc_fragment_persistent_key(const packet_info *pinfo, const guint32 id,
1114 const void *data)
1115 {
1116 dcerpc_fragment_key *key = g_slice_new(dcerpc_fragment_key);
1117 const e_dce_dg_common_hdr_t *hdr = (const e_dce_dg_common_hdr_t *)data;
1118
1119 copy_address(&key->src, &pinfo->src);
1120 copy_address(&key->dst, &pinfo->dst);
1121 key->id = id;
1122 key->act_id = hdr->act_id;
1123
1124 return key;
1125 }
1126
1127 static void
dcerpc_fragment_free_temporary_key(gpointer ptr)1128 dcerpc_fragment_free_temporary_key(gpointer ptr)
1129 {
1130 dcerpc_fragment_key *key = (dcerpc_fragment_key *)ptr;
1131
1132 g_slice_free(dcerpc_fragment_key, key);
1133 }
1134
1135 static void
dcerpc_fragment_free_persistent_key(gpointer ptr)1136 dcerpc_fragment_free_persistent_key(gpointer ptr)
1137 {
1138 dcerpc_fragment_key *key = (dcerpc_fragment_key *)ptr;
1139
1140 if (key) {
1141 /*
1142 * Free up the copies of the addresses from the old key.
1143 */
1144 free_address(&key->src);
1145 free_address(&key->dst);
1146
1147 g_slice_free(dcerpc_fragment_key, key);
1148 }
1149 }
1150
1151 static const reassembly_table_functions dcerpc_cl_reassembly_table_functions = {
1152 dcerpc_fragment_hash,
1153 dcerpc_fragment_equal,
1154 dcerpc_fragment_temporary_key,
1155 dcerpc_fragment_persistent_key,
1156 dcerpc_fragment_free_temporary_key,
1157 dcerpc_fragment_free_persistent_key
1158 };
1159
1160 /*
1161 * Authentication subdissectors. Used to dissect authentication blobs in
1162 * DCERPC binds, requests and responses.
1163 */
1164
1165 typedef struct _dcerpc_auth_subdissector {
1166 guint8 auth_level;
1167 guint8 auth_type;
1168 dcerpc_auth_subdissector_fns auth_fns;
1169 } dcerpc_auth_subdissector;
1170
1171 static GSList *dcerpc_auth_subdissector_list;
1172
get_auth_subdissector_fns(guint8 auth_level,guint8 auth_type)1173 static dcerpc_auth_subdissector_fns *get_auth_subdissector_fns(
1174 guint8 auth_level, guint8 auth_type)
1175 {
1176 gpointer data;
1177 int i;
1178
1179 for (i = 0; (data = g_slist_nth_data(dcerpc_auth_subdissector_list, i)); i++) {
1180 dcerpc_auth_subdissector *asd = (dcerpc_auth_subdissector *)data;
1181
1182 if ((asd->auth_level == auth_level) &&
1183 (asd->auth_type == auth_type))
1184 return &asd->auth_fns;
1185 }
1186
1187 return NULL;
1188 }
1189
register_dcerpc_auth_subdissector(guint8 auth_level,guint8 auth_type,dcerpc_auth_subdissector_fns * fns)1190 void register_dcerpc_auth_subdissector(guint8 auth_level, guint8 auth_type,
1191 dcerpc_auth_subdissector_fns *fns)
1192 {
1193 dcerpc_auth_subdissector *d;
1194
1195 if (get_auth_subdissector_fns(auth_level, auth_type))
1196 return;
1197
1198 d = g_new(dcerpc_auth_subdissector, 1);
1199
1200 d->auth_level = auth_level;
1201 d->auth_type = auth_type;
1202 memcpy(&d->auth_fns, fns, sizeof(dcerpc_auth_subdissector_fns));
1203
1204 dcerpc_auth_subdissector_list = g_slist_append(dcerpc_auth_subdissector_list, d);
1205 }
1206
1207 /* Hand off verifier data to a registered dissector */
1208
dissect_auth_verf(packet_info * pinfo,e_dce_cn_common_hdr_t * hdr,dcerpc_auth_info * auth_info)1209 static void dissect_auth_verf(packet_info *pinfo,
1210 e_dce_cn_common_hdr_t *hdr,
1211 dcerpc_auth_info *auth_info)
1212 {
1213 dcerpc_dissect_fnct_t *fn = NULL;
1214 /* XXX - "stub" a fake DCERPC INFO STRUCTURE
1215 If a dcerpc_info is really needed, update
1216 the call stacks to include it
1217 */
1218 FAKE_DCERPC_INFO_STRUCTURE
1219
1220 if (auth_info == NULL) {
1221 return;
1222 }
1223
1224 if (auth_info->auth_fns == NULL) {
1225 return;
1226 }
1227
1228 switch (hdr->ptype) {
1229 case PDU_BIND:
1230 case PDU_ALTER:
1231 fn = auth_info->auth_fns->bind_fn;
1232 break;
1233 case PDU_BIND_ACK:
1234 case PDU_ALTER_ACK:
1235 fn = auth_info->auth_fns->bind_ack_fn;
1236 break;
1237 case PDU_AUTH3:
1238 fn = auth_info->auth_fns->auth3_fn;
1239 break;
1240 case PDU_REQ:
1241 case PDU_CO_CANCEL:
1242 case PDU_ORPHANED:
1243 fn = auth_info->auth_fns->req_verf_fn;
1244 break;
1245 case PDU_RESP:
1246 case PDU_FAULT:
1247 fn = auth_info->auth_fns->resp_verf_fn;
1248 break;
1249
1250 default:
1251 /* Don't know how to handle authentication data in this
1252 pdu type. */
1253 proto_tree_add_expert_format(auth_info->auth_tree, pinfo,
1254 &ei_dcerpc_invalid_pdu_authentication_attempt,
1255 auth_info->auth_tvb, 0, 0,
1256 "Don't know how to dissect authentication data for %s pdu type",
1257 val_to_str(hdr->ptype, pckt_vals, "Unknown (%u)"));
1258 return;
1259 break;
1260 }
1261
1262 if (fn)
1263 fn(auth_info->auth_tvb, 0, pinfo, auth_info->auth_tree, &di, hdr->drep);
1264 else
1265 proto_tree_add_expert_format(auth_info->auth_tree, pinfo,
1266 &ei_dcerpc_verifier_unavailable,
1267 auth_info->auth_tvb, 0, hdr->auth_len,
1268 "%s Verifier unavailable",
1269 val_to_str(auth_info->auth_type,
1270 authn_protocol_vals,
1271 "Unknown (%u)"));
1272 }
1273
1274 static proto_item*
proto_tree_add_dcerpc_drep(proto_tree * tree,tvbuff_t * tvb,int offset,guint8 drep[],int drep_len)1275 proto_tree_add_dcerpc_drep(proto_tree *tree, tvbuff_t *tvb, int offset, guint8 drep[], int drep_len)
1276 {
1277 const guint8 byteorder = drep[0] >> 4;
1278 const guint8 character = drep[0] & 0x0f;
1279 const guint8 fp = drep[1];
1280 proto_item *ti = proto_tree_add_bytes(tree, hf_dcerpc_drep, tvb, offset, drep_len, drep);
1281 proto_tree *tr = proto_item_add_subtree(ti, ett_dcerpc_drep);
1282
1283 proto_tree_add_uint(tr, hf_dcerpc_drep_byteorder, tvb, offset, 1, byteorder);
1284 proto_tree_add_uint(tr, hf_dcerpc_drep_character, tvb, offset, 1, character);
1285 proto_tree_add_uint(tr, hf_dcerpc_drep_fp, tvb, offset+1, 1, fp);
1286
1287 proto_item_append_text(ti, " (Order: %s, Char: %s, Float: %s)",
1288 val_to_str(byteorder, drep_byteorder_vals, "Unknown (%u)"),
1289 val_to_str(character, drep_character_vals, "Unknown (%u)"),
1290 val_to_str(fp, drep_fp_vals, "Unknown (%u)"));
1291 return ti;
1292 }
1293
1294 /* Hand off payload data to a registered dissector */
1295
decode_encrypted_data(tvbuff_t * header_tvb,tvbuff_t * payload_tvb,tvbuff_t * trailer_tvb,packet_info * pinfo,e_dce_cn_common_hdr_t * hdr,dcerpc_auth_info * auth_info)1296 static tvbuff_t *decode_encrypted_data(tvbuff_t *header_tvb,
1297 tvbuff_t *payload_tvb,
1298 tvbuff_t *trailer_tvb,
1299 packet_info *pinfo,
1300 e_dce_cn_common_hdr_t *hdr,
1301 dcerpc_auth_info *auth_info)
1302 {
1303 dcerpc_decode_data_fnct_t *fn = NULL;
1304
1305 if (auth_info == NULL)
1306 return NULL;
1307
1308 if (auth_info->auth_fns == NULL)
1309 return NULL;
1310
1311 switch (hdr->ptype) {
1312 case PDU_REQ:
1313 fn = auth_info->auth_fns->req_data_fn;
1314 break;
1315 case PDU_RESP:
1316 case PDU_FAULT:
1317 fn = auth_info->auth_fns->resp_data_fn;
1318 break;
1319 }
1320
1321 if (fn)
1322 return fn(header_tvb, payload_tvb, trailer_tvb, auth_info->auth_tvb, pinfo, auth_info);
1323
1324 return NULL;
1325 }
1326
1327 typedef struct _dcerpc_dissector_data
1328 {
1329 dcerpc_uuid_value *sub_proto;
1330 dcerpc_info *info;
1331 gboolean decrypted;
1332 dcerpc_auth_info *auth_info;
1333 guint8 *drep;
1334 proto_tree *dcerpc_tree;
1335 } dcerpc_dissector_data_t;
1336
1337 /*
1338 * Subdissectors
1339 */
1340
1341 static dissector_table_t uuid_dissector_table;
1342
1343 /* the registered subdissectors */
1344 GHashTable *dcerpc_uuids = NULL;
1345
1346 static gint
dcerpc_uuid_equal(gconstpointer k1,gconstpointer k2)1347 dcerpc_uuid_equal(gconstpointer k1, gconstpointer k2)
1348 {
1349 const guid_key *key1 = (const guid_key *)k1;
1350 const guid_key *key2 = (const guid_key *)k2;
1351 return ((memcmp(&key1->guid, &key2->guid, sizeof (e_guid_t)) == 0)
1352 && (key1->ver == key2->ver));
1353 }
1354
1355 static guint
dcerpc_uuid_hash(gconstpointer k)1356 dcerpc_uuid_hash(gconstpointer k)
1357 {
1358 const guid_key *key = (const guid_key *)k;
1359 /* This isn't perfect, but the Data1 part of these is almost always
1360 unique. */
1361 return key->guid.data1;
1362 }
1363
1364
1365 static int
1366 dissect_verification_trailer(packet_info *pinfo, tvbuff_t *tvb, int stub_offset,
1367 proto_tree *parent_tree, int *signature_offset);
1368
1369 static void
show_stub_data(packet_info * pinfo,tvbuff_t * tvb,gint offset,proto_tree * dcerpc_tree,dcerpc_auth_info * auth_info,gboolean is_encrypted)1370 show_stub_data(packet_info *pinfo, tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
1371 dcerpc_auth_info *auth_info, gboolean is_encrypted)
1372 {
1373 int length, plain_length, auth_pad_len;
1374 guint auth_pad_offset;
1375
1376 /*
1377 * We don't show stub data unless we have some in the tvbuff;
1378 * however, in the protocol tree, we show, as the number of
1379 * bytes, the reported number of bytes, not the number of bytes
1380 * that happen to be in the tvbuff.
1381 */
1382 if (tvb_reported_length_remaining(tvb, offset) > 0) {
1383 auth_pad_len = auth_info?auth_info->auth_pad_len:0;
1384 length = tvb_reported_length_remaining(tvb, offset);
1385
1386 /* if auth_pad_len is larger than length then we ignore auth_pad_len totally */
1387 plain_length = length - auth_pad_len;
1388 if (plain_length < 1) {
1389 plain_length = length;
1390 auth_pad_len = 0;
1391 }
1392 auth_pad_offset = offset + plain_length;
1393
1394 if ((auth_info != NULL) &&
1395 (auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)) {
1396 if (is_encrypted) {
1397 proto_tree_add_item(dcerpc_tree, hf_dcerpc_encrypted_stub_data, tvb, offset, length, ENC_NA);
1398 /* is the padding is still inside the encrypted blob, don't display it explicit */
1399 auth_pad_len = 0;
1400 } else {
1401 proto_tree_add_item(dcerpc_tree, hf_dcerpc_decrypted_stub_data, tvb, offset, plain_length, ENC_NA);
1402 dissect_verification_trailer(pinfo, tvb, offset, dcerpc_tree, NULL);
1403 }
1404 } else {
1405 proto_tree_add_item(dcerpc_tree, hf_dcerpc_stub_data, tvb, offset, plain_length, ENC_NA);
1406 dissect_verification_trailer(pinfo, tvb, offset, dcerpc_tree, NULL);
1407 }
1408 /* If there is auth padding at the end of the stub, display it */
1409 if (auth_pad_len != 0) {
1410 proto_tree_add_item(dcerpc_tree, hf_dcerpc_auth_padding, tvb, auth_pad_offset, auth_pad_len, ENC_NA);
1411 }
1412 }
1413 }
1414
1415 static int
dissect_dcerpc_guid(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)1416 dissect_dcerpc_guid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1417 {
1418 dcerpc_dissector_data_t* dissector_data = (dcerpc_dissector_data_t*)data;
1419 const gchar *name = NULL;
1420 dcerpc_sub_dissector *proc;
1421 int (*volatile sub_dissect)(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) = NULL;
1422 proto_item *pi, *sub_item;
1423 proto_tree *sub_tree;
1424 volatile guint length;
1425 guint reported_length;
1426 volatile gint offset = 0;
1427 tvbuff_t *volatile stub_tvb;
1428 tvbuff_t *volatile payload_tvb = NULL;
1429 volatile guint auth_pad_len;
1430 volatile int auth_pad_offset;
1431 const char *volatile saved_proto;
1432
1433 for (proc = dissector_data->sub_proto->procs; proc->name; proc++) {
1434 if (proc->num == dissector_data->info->call_data->opnum) {
1435 name = proc->name;
1436 break;
1437 }
1438 }
1439
1440 col_set_str(pinfo->cinfo, COL_PROTOCOL, dissector_data->sub_proto->name);
1441
1442 if (!name)
1443 col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown operation %u %s",
1444 dissector_data->info->call_data->opnum,
1445 (dissector_data->info->ptype == PDU_REQ) ? "request" : "response");
1446 else
1447 col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
1448 name, (dissector_data->info->ptype == PDU_REQ) ? "request" : "response");
1449
1450 sub_dissect = (dissector_data->info->ptype == PDU_REQ) ?
1451 proc->dissect_rqst : proc->dissect_resp;
1452
1453 sub_item = proto_tree_add_item(tree, dissector_data->sub_proto->proto_id,
1454 tvb,//(decrypted_tvb != NULL)?decrypted_tvb:tvb,
1455 0, -1, ENC_NA);
1456 sub_tree = proto_item_add_subtree(sub_item, dissector_data->sub_proto->ett);
1457 if (!name)
1458 proto_item_append_text(sub_item, ", unknown operation %u",
1459 dissector_data->info->call_data->opnum);
1460 else
1461 proto_item_append_text(sub_item, ", %s", name);
1462
1463 if (tree) {
1464 /*
1465 * Put the operation number into the tree along with
1466 * the operation's name.
1467 */
1468 if (dissector_data->sub_proto->opnum_hf != -1)
1469 proto_tree_add_uint_format(sub_tree, dissector_data->sub_proto->opnum_hf,
1470 tvb, 0, 0, dissector_data->info->call_data->opnum,
1471 "Operation: %s (%u)",
1472 name ? name : "Unknown operation",
1473 dissector_data->info->call_data->opnum);
1474 else
1475 proto_tree_add_uint_format_value(sub_tree, hf_dcerpc_op, tvb,
1476 0, 0, dissector_data->info->call_data->opnum,
1477 "%s (%u)",
1478 name ? name : "Unknown operation",
1479 dissector_data->info->call_data->opnum);
1480
1481 if ((dissector_data->info->ptype == PDU_REQ) && (dissector_data->info->call_data->rep_frame != 0)) {
1482 pi = proto_tree_add_uint(sub_tree, hf_dcerpc_response_in,
1483 tvb, 0, 0, dissector_data->info->call_data->rep_frame);
1484 proto_item_set_generated(pi);
1485 }
1486 if ((dissector_data->info->ptype == PDU_RESP) && (dissector_data->info->call_data->req_frame != 0)) {
1487 pi = proto_tree_add_uint(sub_tree, hf_dcerpc_request_in,
1488 tvb, 0, 0, dissector_data->info->call_data->req_frame);
1489 proto_item_set_generated(pi);
1490 }
1491 } /* tree */
1492
1493 if (!dissector_data->decrypted || (sub_dissect == NULL))
1494 {
1495 show_stub_data(pinfo, tvb, 0, sub_tree, dissector_data->auth_info, !dissector_data->decrypted);
1496 return tvb_captured_length(tvb);
1497 }
1498
1499 /* Either there was no encryption or we successfully decrypted
1500 the encrypted payload. */
1501
1502 /* We have a subdissector - call it. */
1503 saved_proto = pinfo->current_proto;
1504 pinfo->current_proto = dissector_data->sub_proto->name;
1505
1506 init_ndr_pointer_list(dissector_data->info);
1507
1508 length = tvb_captured_length(tvb);
1509 reported_length = tvb_reported_length(tvb);
1510
1511 /*
1512 * Remove the authentication padding from the stub data.
1513 */
1514 if ((dissector_data->auth_info != NULL) && (dissector_data->auth_info->auth_pad_len != 0)) {
1515 if (reported_length >= dissector_data->auth_info->auth_pad_len) {
1516 /*
1517 * OK, the padding length isn't so big that it
1518 * exceeds the stub length. Trim the reported
1519 * length of the tvbuff.
1520 */
1521 reported_length -= dissector_data->auth_info->auth_pad_len;
1522
1523 /*
1524 * If that exceeds the actual amount of data in
1525 * the tvbuff (which means we have at least one
1526 * byte of authentication padding in the tvbuff),
1527 * trim the actual amount.
1528 */
1529 if (length > reported_length)
1530 length = reported_length;
1531
1532 stub_tvb = tvb_new_subset_length_caplen(tvb, 0, length, reported_length);
1533 auth_pad_len = dissector_data->auth_info->auth_pad_len;
1534 auth_pad_offset = reported_length;
1535 } else {
1536 /*
1537 * The padding length exceeds the stub length.
1538 * Don't bother dissecting the stub, trim the padding
1539 * length to what's in the stub data, and show the
1540 * entire stub as authentication padding.
1541 */
1542 stub_tvb = NULL;
1543 auth_pad_len = reported_length;
1544 auth_pad_offset = 0;
1545 length = 0;
1546 }
1547 } else {
1548 /*
1549 * No authentication padding.
1550 */
1551 stub_tvb = tvb;
1552 auth_pad_len = 0;
1553 auth_pad_offset = 0;
1554 }
1555
1556 if (sub_item) {
1557 proto_item_set_len(sub_item, length);
1558 }
1559
1560 if (stub_tvb != NULL) {
1561 /*
1562 * Catch all exceptions other than BoundsError, so that even
1563 * if the stub data is bad, we still show the authentication
1564 * padding, if any.
1565 *
1566 * If we get BoundsError, it means the frame was cut short
1567 * by a snapshot length, so there's nothing more to
1568 * dissect; just re-throw that exception.
1569 */
1570 TRY {
1571 proto_tree *stub_tree = NULL;
1572 int remaining;
1573 int trailer_start_offset = -1;
1574 int trailer_end_offset = -1;
1575
1576 stub_tree = proto_tree_add_subtree_format(dissector_data->dcerpc_tree,
1577 stub_tvb, 0, length,
1578 ett_dcerpc_complete_stub_data, NULL,
1579 "Complete stub data (%d byte%s)", length,
1580 plurality(length, "", "s"));
1581 trailer_end_offset = dissect_verification_trailer(pinfo,
1582 stub_tvb, 0,
1583 stub_tree,
1584 &trailer_start_offset);
1585
1586 if (trailer_end_offset != -1) {
1587 remaining = tvb_captured_length_remaining(stub_tvb,
1588 trailer_start_offset);
1589 length -= remaining;
1590
1591 if (sub_item) {
1592 proto_item_set_len(sub_item, length);
1593 }
1594 } else {
1595 proto_item *payload_item;
1596
1597 payload_item = proto_tree_add_item(stub_tree,
1598 hf_dcerpc_payload_stub_data,
1599 stub_tvb, 0, length, ENC_NA);
1600 proto_item_append_text(payload_item, " (%d byte%s)",
1601 length, plurality(length, "", "s"));
1602 }
1603
1604 payload_tvb = tvb_new_subset_length_caplen(stub_tvb, 0, length, length);
1605 offset = sub_dissect(payload_tvb, 0, pinfo, sub_tree,
1606 dissector_data->info, dissector_data->drep);
1607
1608 /* If we have a subdissector and it didn't dissect all
1609 data in the tvb, make a note of it. */
1610 remaining = tvb_reported_length_remaining(stub_tvb, offset);
1611
1612 if (trailer_end_offset != -1) {
1613 if (offset > trailer_start_offset) {
1614 remaining = offset - trailer_start_offset;
1615 proto_tree_add_item(sub_tree, hf_dcerpc_stub_data_with_sec_vt,
1616 stub_tvb, trailer_start_offset, remaining, ENC_NA);
1617 col_append_fstr(pinfo->cinfo, COL_INFO,
1618 "[Payload with Verification Trailer (%d byte%s)]",
1619 remaining,
1620 plurality(remaining, "", "s"));
1621 remaining = 0;
1622 } else {
1623 remaining = trailer_start_offset - offset;
1624 }
1625 }
1626
1627 if (remaining > 0) {
1628 proto_tree_add_expert(sub_tree, pinfo, &ei_dcerpc_long_frame, stub_tvb, offset, remaining);
1629 col_append_fstr(pinfo->cinfo, COL_INFO,
1630 "[Long frame (%d byte%s)]",
1631 remaining,
1632 plurality(remaining, "", "s"));
1633 }
1634 } CATCH_NONFATAL_ERRORS {
1635 /*
1636 * Somebody threw an exception that means that there
1637 * was a problem dissecting the payload; that means
1638 * that a dissector was found, so we don't need to
1639 * dissect the payload as data or update the protocol
1640 * or info columns.
1641 *
1642 * Just show the exception and then drive on to show
1643 * the authentication padding.
1644 */
1645 show_exception(stub_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
1646 } ENDTRY;
1647 }
1648
1649 /* If there is auth padding at the end of the stub, display it */
1650 if (auth_pad_len != 0) {
1651 proto_tree_add_item(sub_tree, hf_dcerpc_auth_padding, tvb, auth_pad_offset, auth_pad_len, ENC_NA);
1652 }
1653
1654 pinfo->current_proto = saved_proto;
1655
1656 return tvb_captured_length(tvb);
1657 }
1658
1659 void
dcerpc_init_uuid(int proto,int ett,e_guid_t * uuid,guint16 ver,dcerpc_sub_dissector * procs,int opnum_hf)1660 dcerpc_init_uuid(int proto, int ett, e_guid_t *uuid, guint16 ver,
1661 dcerpc_sub_dissector *procs, int opnum_hf)
1662 {
1663 guid_key *key = (guid_key *)g_malloc(sizeof (*key));
1664 dcerpc_uuid_value *value = (dcerpc_uuid_value *)g_malloc(sizeof (*value));
1665 header_field_info *hf_info;
1666 module_t *samr_module;
1667 const char *filter_name = proto_get_protocol_filter_name(proto);
1668 dissector_handle_t guid_handle;
1669
1670 key->guid = *uuid;
1671 key->ver = ver;
1672
1673 value->proto = find_protocol_by_id(proto);
1674 value->proto_id = proto;
1675 value->ett = ett;
1676 value->name = proto_get_protocol_short_name(value->proto);
1677 value->procs = procs;
1678 value->opnum_hf = opnum_hf;
1679
1680 g_hash_table_insert(dcerpc_uuids, key, value);
1681
1682 hf_info = proto_registrar_get_nth(opnum_hf);
1683 hf_info->strings = value_string_from_subdissectors(procs);
1684
1685 /* Register the GUID with the dissector table */
1686 guid_handle = create_dissector_handle( dissect_dcerpc_guid, proto);
1687 dissector_add_guid( "dcerpc.uuid", key, guid_handle );
1688
1689 /* add this GUID to the global name resolving */
1690 guids_add_uuid(uuid, proto_get_protocol_short_name(value->proto));
1691
1692 /* Register the samr.nt_password preference as obsolete */
1693 /* This should be in packet-dcerpc-samr.c */
1694 if (strcmp(filter_name, "samr") == 0) {
1695 samr_module = prefs_register_protocol_obsolete(proto);
1696 prefs_register_obsolete_preference(samr_module, "nt_password");
1697 }
1698 }
1699
1700 /* Function to find the name of a registered protocol
1701 * or NULL if the protocol/version is not known to wireshark.
1702 */
1703 const char *
dcerpc_get_proto_name(e_guid_t * uuid,guint16 ver)1704 dcerpc_get_proto_name(e_guid_t *uuid, guint16 ver)
1705 {
1706 dissector_handle_t handle;
1707 guid_key key;
1708
1709 key.guid = *uuid;
1710 key.ver = ver;
1711
1712 handle = dissector_get_guid_handle(uuid_dissector_table, &key);
1713 if (handle == NULL) {
1714 return NULL;
1715 }
1716
1717 return dissector_handle_get_short_name(handle);
1718 }
1719
1720 /* Function to find the opnum hf-field of a registered protocol
1721 * or -1 if the protocol/version is not known to wireshark.
1722 */
1723 int
dcerpc_get_proto_hf_opnum(e_guid_t * uuid,guint16 ver)1724 dcerpc_get_proto_hf_opnum(e_guid_t *uuid, guint16 ver)
1725 {
1726 guid_key key;
1727 dcerpc_uuid_value *sub_proto;
1728
1729 key.guid = *uuid;
1730 key.ver = ver;
1731 if (!(sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key))) {
1732 return -1;
1733 }
1734 return sub_proto->opnum_hf;
1735 }
1736
1737 /* Create a value_string consisting of DCERPC opnum and name from a
1738 subdissector array. */
1739
value_string_from_subdissectors(dcerpc_sub_dissector * sd)1740 value_string *value_string_from_subdissectors(dcerpc_sub_dissector *sd)
1741 {
1742 value_string *vs = NULL;
1743 int i;
1744 int num_sd = 0;
1745
1746 again:
1747 for (i = 0; sd[i].name; i++) {
1748 if (vs) {
1749 vs[i].value = sd[i].num;
1750 vs[i].strptr = sd[i].name;
1751 } else
1752 num_sd++;
1753 }
1754
1755 if (!vs) {
1756 vs = (value_string *)wmem_alloc(wmem_epan_scope(), (num_sd + 1) * sizeof(value_string));
1757 goto again;
1758 }
1759
1760 vs[num_sd].value = 0;
1761 vs[num_sd].strptr = NULL;
1762
1763 return vs;
1764 }
1765
1766 /* Function to find the subdissector table of a registered protocol
1767 * or NULL if the protocol/version is not known to wireshark.
1768 */
1769 dcerpc_sub_dissector *
dcerpc_get_proto_sub_dissector(e_guid_t * uuid,guint16 ver)1770 dcerpc_get_proto_sub_dissector(e_guid_t *uuid, guint16 ver)
1771 {
1772 guid_key key;
1773 dcerpc_uuid_value *sub_proto;
1774
1775 key.guid = *uuid;
1776 key.ver = ver;
1777 if (!(sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key))) {
1778 return NULL;
1779 }
1780 return sub_proto->procs;
1781 }
1782
1783
1784
1785 static gint
dcerpc_bind_equal(gconstpointer k1,gconstpointer k2)1786 dcerpc_bind_equal(gconstpointer k1, gconstpointer k2)
1787 {
1788 const dcerpc_bind_key *key1 = (const dcerpc_bind_key *)k1;
1789 const dcerpc_bind_key *key2 = (const dcerpc_bind_key *)k2;
1790 return ((key1->conv == key2->conv)
1791 && (key1->ctx_id == key2->ctx_id)
1792 && (key1->transport_salt == key2->transport_salt));
1793 }
1794
1795 static guint
dcerpc_bind_hash(gconstpointer k)1796 dcerpc_bind_hash(gconstpointer k)
1797 {
1798 const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
1799 guint hash;
1800
1801 hash = GPOINTER_TO_UINT(key->conv);
1802 hash += key->ctx_id;
1803 /* sizeof(guint) might be smaller than sizeof(guint64) */
1804 hash += (guint)key->transport_salt;
1805 hash += (guint)(key->transport_salt << sizeof(guint));
1806
1807 return hash;
1808 }
1809
1810 static gint
dcerpc_auth_context_equal(gconstpointer k1,gconstpointer k2)1811 dcerpc_auth_context_equal(gconstpointer k1, gconstpointer k2)
1812 {
1813 const dcerpc_auth_context *key1 = (const dcerpc_auth_context *)k1;
1814 const dcerpc_auth_context *key2 = (const dcerpc_auth_context *)k2;
1815 return ((key1->conv == key2->conv)
1816 && (key1->auth_context_id == key2->auth_context_id)
1817 && (key1->transport_salt == key2->transport_salt));
1818 }
1819
1820 static guint
dcerpc_auth_context_hash(gconstpointer k)1821 dcerpc_auth_context_hash(gconstpointer k)
1822 {
1823 const dcerpc_auth_context *key = (const dcerpc_auth_context *)k;
1824 guint hash;
1825
1826 hash = GPOINTER_TO_UINT(key->conv);
1827 hash += key->auth_context_id;
1828 /* sizeof(guint) might be smaller than sizeof(guint64) */
1829 hash += (guint)key->transport_salt;
1830 hash += (guint)(key->transport_salt << sizeof(guint));
1831
1832 return hash;
1833 }
1834
1835 /*
1836 * To keep track of callid mappings. Should really use some generic
1837 * conversation support instead.
1838 */
1839 static wmem_map_t *dcerpc_cn_calls = NULL;
1840 static wmem_map_t *dcerpc_dg_calls = NULL;
1841
1842 typedef struct _dcerpc_cn_call_key {
1843 conversation_t *conv;
1844 guint32 call_id;
1845 guint64 transport_salt;
1846 } dcerpc_cn_call_key;
1847
1848 typedef struct _dcerpc_dg_call_key {
1849 conversation_t *conv;
1850 guint32 seqnum;
1851 e_guid_t act_id ;
1852 } dcerpc_dg_call_key;
1853
1854
1855 static gint
dcerpc_cn_call_equal(gconstpointer k1,gconstpointer k2)1856 dcerpc_cn_call_equal(gconstpointer k1, gconstpointer k2)
1857 {
1858 const dcerpc_cn_call_key *key1 = (const dcerpc_cn_call_key *)k1;
1859 const dcerpc_cn_call_key *key2 = (const dcerpc_cn_call_key *)k2;
1860 return ((key1->conv == key2->conv)
1861 && (key1->call_id == key2->call_id)
1862 && (key1->transport_salt == key2->transport_salt));
1863 }
1864
1865 static gint
dcerpc_dg_call_equal(gconstpointer k1,gconstpointer k2)1866 dcerpc_dg_call_equal(gconstpointer k1, gconstpointer k2)
1867 {
1868 const dcerpc_dg_call_key *key1 = (const dcerpc_dg_call_key *)k1;
1869 const dcerpc_dg_call_key *key2 = (const dcerpc_dg_call_key *)k2;
1870 return ((key1->conv == key2->conv)
1871 && (key1->seqnum == key2->seqnum)
1872 && ((memcmp(&key1->act_id, &key2->act_id, sizeof (e_guid_t)) == 0)));
1873 }
1874
1875 static guint
dcerpc_cn_call_hash(gconstpointer k)1876 dcerpc_cn_call_hash(gconstpointer k)
1877 {
1878 const dcerpc_cn_call_key *key = (const dcerpc_cn_call_key *)k;
1879 guint hash;
1880
1881 hash = GPOINTER_TO_UINT(key->conv);
1882 hash += key->call_id;
1883 /* sizeof(guint) might be smaller than sizeof(guint64) */
1884 hash += (guint)key->transport_salt;
1885 hash += (guint)(key->transport_salt << sizeof(guint));
1886
1887 return hash;
1888 }
1889
1890 static guint
dcerpc_dg_call_hash(gconstpointer k)1891 dcerpc_dg_call_hash(gconstpointer k)
1892 {
1893 const dcerpc_dg_call_key *key = (const dcerpc_dg_call_key *)k;
1894 return (GPOINTER_TO_UINT(key->conv) + key->seqnum + key->act_id.data1
1895 + (key->act_id.data2 << 16) + key->act_id.data3
1896 + (key->act_id.data4[0] << 24) + (key->act_id.data4[1] << 16)
1897 + (key->act_id.data4[2] << 8) + (key->act_id.data4[3] << 0)
1898 + (key->act_id.data4[4] << 24) + (key->act_id.data4[5] << 16)
1899 + (key->act_id.data4[6] << 8) + (key->act_id.data4[7] << 0));
1900 }
1901
1902 /* to keep track of matched calls/responses
1903 this one uses the same value struct as calls, but the key is the frame id
1904 and call id; there can be more than one call in a frame.
1905
1906 XXX - why not just use the same keys as are used for calls?
1907 */
1908
1909 static wmem_map_t *dcerpc_matched = NULL;
1910
1911 typedef struct _dcerpc_matched_key {
1912 guint32 frame;
1913 guint32 call_id;
1914 } dcerpc_matched_key;
1915
1916 static gint
dcerpc_matched_equal(gconstpointer k1,gconstpointer k2)1917 dcerpc_matched_equal(gconstpointer k1, gconstpointer k2)
1918 {
1919 const dcerpc_matched_key *key1 = (const dcerpc_matched_key *)k1;
1920 const dcerpc_matched_key *key2 = (const dcerpc_matched_key *)k2;
1921 return ((key1->frame == key2->frame)
1922 && (key1->call_id == key2->call_id));
1923 }
1924
1925 static guint
dcerpc_matched_hash(gconstpointer k)1926 dcerpc_matched_hash(gconstpointer k)
1927 {
1928 const dcerpc_matched_key *key = (const dcerpc_matched_key *)k;
1929 return key->frame;
1930 }
1931
1932 static gboolean
uuid_equal(e_guid_t * uuid1,e_guid_t * uuid2)1933 uuid_equal(e_guid_t *uuid1, e_guid_t *uuid2)
1934 {
1935 if( (uuid1->data1 != uuid2->data1)
1936 ||(uuid1->data2 != uuid2->data2)
1937 ||(uuid1->data3 != uuid2->data3)
1938 ||(uuid1->data4[0] != uuid2->data4[0])
1939 ||(uuid1->data4[1] != uuid2->data4[1])
1940 ||(uuid1->data4[2] != uuid2->data4[2])
1941 ||(uuid1->data4[3] != uuid2->data4[3])
1942 ||(uuid1->data4[4] != uuid2->data4[4])
1943 ||(uuid1->data4[5] != uuid2->data4[5])
1944 ||(uuid1->data4[6] != uuid2->data4[6])
1945 ||(uuid1->data4[7] != uuid2->data4[7]) ){
1946 return FALSE;
1947 }
1948 return TRUE;
1949 }
1950
1951 static void
dcerpcstat_init(struct register_srt * srt,GArray * srt_array)1952 dcerpcstat_init(struct register_srt* srt, GArray* srt_array)
1953 {
1954 dcerpcstat_tap_data_t* tap_data = (dcerpcstat_tap_data_t*)get_srt_table_param_data(srt);
1955 srt_stat_table *dcerpc_srt_table;
1956 int i, hf_opnum;
1957 dcerpc_sub_dissector *procs;
1958
1959 DISSECTOR_ASSERT(tap_data);
1960
1961 hf_opnum = dcerpc_get_proto_hf_opnum(&tap_data->uuid, tap_data->ver);
1962 procs = dcerpc_get_proto_sub_dissector(&tap_data->uuid, tap_data->ver);
1963
1964 if(hf_opnum != -1){
1965 dcerpc_srt_table = init_srt_table(tap_data->prog, NULL, srt_array, tap_data->num_procedures, NULL, proto_registrar_get_nth(hf_opnum)->abbrev, tap_data);
1966 } else {
1967 dcerpc_srt_table = init_srt_table(tap_data->prog, NULL, srt_array, tap_data->num_procedures, NULL, NULL, tap_data);
1968 }
1969
1970 for(i=0;i<tap_data->num_procedures;i++){
1971 int j;
1972 const char *proc_name;
1973
1974 proc_name = "unknown";
1975 for(j=0;procs[j].name;j++)
1976 {
1977 if (procs[j].num == i)
1978 {
1979 proc_name = procs[j].name;
1980 }
1981 }
1982
1983 init_srt_table_row(dcerpc_srt_table, i, proc_name);
1984 }
1985 }
1986
1987 static tap_packet_status
dcerpcstat_packet(void * pss,packet_info * pinfo,epan_dissect_t * edt _U_,const void * prv)1988 dcerpcstat_packet(void *pss, packet_info *pinfo, epan_dissect_t *edt _U_, const void *prv)
1989 {
1990 guint i = 0;
1991 srt_stat_table *dcerpc_srt_table;
1992 srt_data_t *data = (srt_data_t *)pss;
1993 const dcerpc_info *ri = (const dcerpc_info *)prv;
1994 dcerpcstat_tap_data_t* tap_data;
1995
1996 dcerpc_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
1997 tap_data = (dcerpcstat_tap_data_t*)dcerpc_srt_table->table_specific_data;
1998
1999 if(!ri->call_data){
2000 return TAP_PACKET_DONT_REDRAW;
2001 }
2002 if(!ri->call_data->req_frame){
2003 /* we have not seen the request so we don't know the delta*/
2004 return TAP_PACKET_DONT_REDRAW;
2005 }
2006 if(ri->call_data->opnum >= tap_data->num_procedures){
2007 /* don't handle this since it's outside of known table */
2008 return TAP_PACKET_DONT_REDRAW;
2009 }
2010
2011 /* we are only interested in reply packets */
2012 if(ri->ptype != PDU_RESP){
2013 return TAP_PACKET_DONT_REDRAW;
2014 }
2015
2016 /* we are only interested in certain program/versions */
2017 if( (!uuid_equal( (&ri->call_data->uuid), (&tap_data->uuid)))
2018 ||(ri->call_data->ver != tap_data->ver)){
2019 return TAP_PACKET_DONT_REDRAW;
2020 }
2021
2022 add_srt_table_data(dcerpc_srt_table, ri->call_data->opnum, &ri->call_data->req_time, pinfo);
2023
2024 return TAP_PACKET_REDRAW;
2025 }
2026
2027 static guint
dcerpcstat_param(register_srt_t * srt,const char * opt_arg,char ** err)2028 dcerpcstat_param(register_srt_t* srt, const char* opt_arg, char** err)
2029 {
2030 int pos = 0;
2031 guint32 i, max_procs;
2032 dcerpcstat_tap_data_t* tap_data;
2033 guint d1,d2,d3,d40,d41,d42,d43,d44,d45,d46,d47;
2034 int major, minor;
2035 guint16 ver;
2036 dcerpc_sub_dissector *procs;
2037
2038 if (sscanf(opt_arg, ",%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x,%d.%d%n",
2039 &d1,&d2,&d3,&d40,&d41,&d42,&d43,&d44,&d45,&d46,&d47,&major,&minor,&pos) == 13)
2040 {
2041 if ((major < 0) || (major > 65535)) {
2042 *err = g_strdup_printf("dcerpcstat_init() Major version number %d is invalid - must be positive and <= 65535", major);
2043 return pos;
2044 }
2045 if ((minor < 0) || (minor > 65535)) {
2046 *err = g_strdup_printf("dcerpcstat_init() Minor version number %d is invalid - must be positive and <= 65535", minor);
2047 return pos;
2048 }
2049 ver = major;
2050
2051 tap_data = g_new0(dcerpcstat_tap_data_t, 1);
2052
2053 tap_data->uuid.data1 = d1;
2054 tap_data->uuid.data2 = d2;
2055 tap_data->uuid.data3 = d3;
2056 tap_data->uuid.data4[0] = d40;
2057 tap_data->uuid.data4[1] = d41;
2058 tap_data->uuid.data4[2] = d42;
2059 tap_data->uuid.data4[3] = d43;
2060 tap_data->uuid.data4[4] = d44;
2061 tap_data->uuid.data4[5] = d45;
2062 tap_data->uuid.data4[6] = d46;
2063 tap_data->uuid.data4[7] = d47;
2064
2065 procs = dcerpc_get_proto_sub_dissector(&tap_data->uuid, ver);
2066 tap_data->prog = dcerpc_get_proto_name(&tap_data->uuid, ver);
2067 tap_data->ver = ver;
2068
2069 for(i=0,max_procs=0;procs[i].name;i++)
2070 {
2071 if(procs[i].num>max_procs)
2072 {
2073 max_procs = procs[i].num;
2074 }
2075 }
2076 tap_data->num_procedures = max_procs+1;
2077
2078 set_srt_table_param_data(srt, tap_data);
2079 }
2080 else
2081 {
2082 *err = g_strdup_printf("<uuid>,<major version>.<minor version>[,<filter>]");
2083 }
2084
2085 return pos;
2086 }
2087
2088
2089 /*
2090 * Utility functions. Modeled after packet-rpc.c
2091 */
2092
2093 int
dissect_dcerpc_char(tvbuff_t * tvb,gint offset,packet_info * pinfo _U_,proto_tree * tree,guint8 * drep,int hfindex,guint8 * pdata)2094 dissect_dcerpc_char(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
2095 proto_tree *tree, guint8 *drep,
2096 int hfindex, guint8 *pdata)
2097 {
2098 guint8 data;
2099
2100 /*
2101 * XXX - fix to handle EBCDIC if we ever support EBCDIC FT_CHAR.
2102 */
2103 data = tvb_get_guint8(tvb, offset);
2104 if (hfindex != -1) {
2105 proto_tree_add_item(tree, hfindex, tvb, offset, 1, ENC_ASCII|DREP_ENC_INTEGER(drep));
2106 }
2107 if (pdata)
2108 *pdata = data;
2109 tvb_ensure_bytes_exist(tvb, offset, 1);
2110 return offset + 1;
2111 }
2112
2113 int
dissect_dcerpc_uint8(tvbuff_t * tvb,gint offset,packet_info * pinfo _U_,proto_tree * tree,guint8 * drep,int hfindex,guint8 * pdata)2114 dissect_dcerpc_uint8(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
2115 proto_tree *tree, guint8 *drep,
2116 int hfindex, guint8 *pdata)
2117 {
2118 guint8 data;
2119
2120 data = tvb_get_guint8(tvb, offset);
2121 if (hfindex != -1) {
2122 proto_tree_add_item(tree, hfindex, tvb, offset, 1, DREP_ENC_INTEGER(drep));
2123 }
2124 if (pdata)
2125 *pdata = data;
2126 tvb_ensure_bytes_exist(tvb, offset, 1);
2127 return offset + 1;
2128 }
2129
2130 int
dissect_dcerpc_uint16(tvbuff_t * tvb,gint offset,packet_info * pinfo _U_,proto_tree * tree,guint8 * drep,int hfindex,guint16 * pdata)2131 dissect_dcerpc_uint16(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
2132 proto_tree *tree, guint8 *drep,
2133 int hfindex, guint16 *pdata)
2134 {
2135 guint16 data;
2136
2137 data = ((drep[0] & DREP_LITTLE_ENDIAN)
2138 ? tvb_get_letohs(tvb, offset)
2139 : tvb_get_ntohs(tvb, offset));
2140
2141 if (hfindex != -1) {
2142 proto_tree_add_item(tree, hfindex, tvb, offset, 2, DREP_ENC_INTEGER(drep));
2143 }
2144 if (pdata)
2145 *pdata = data;
2146 tvb_ensure_bytes_exist(tvb, offset, 2);
2147 return offset + 2;
2148 }
2149
2150 int
dissect_dcerpc_uint32(tvbuff_t * tvb,gint offset,packet_info * pinfo _U_,proto_tree * tree,guint8 * drep,int hfindex,guint32 * pdata)2151 dissect_dcerpc_uint32(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
2152 proto_tree *tree, guint8 *drep,
2153 int hfindex, guint32 *pdata)
2154 {
2155 guint32 data;
2156
2157 data = ((drep[0] & DREP_LITTLE_ENDIAN)
2158 ? tvb_get_letohl(tvb, offset)
2159 : tvb_get_ntohl(tvb, offset));
2160
2161 if (hfindex != -1) {
2162 proto_tree_add_item(tree, hfindex, tvb, offset, 4, DREP_ENC_INTEGER(drep));
2163 }
2164 if (pdata)
2165 *pdata = data;
2166 tvb_ensure_bytes_exist(tvb, offset, 4);
2167 return offset+4;
2168 }
2169
2170 /* handles 32 bit unix time_t */
2171 int
dissect_dcerpc_time_t(tvbuff_t * tvb,gint offset,packet_info * pinfo _U_,proto_tree * tree,guint8 * drep,int hfindex,guint32 * pdata)2172 dissect_dcerpc_time_t(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
2173 proto_tree *tree, guint8 *drep,
2174 int hfindex, guint32 *pdata)
2175 {
2176 guint32 data;
2177 nstime_t tv;
2178
2179 data = ((drep[0] & DREP_LITTLE_ENDIAN)
2180 ? tvb_get_letohl(tvb, offset)
2181 : tvb_get_ntohl(tvb, offset));
2182
2183 tv.secs = data;
2184 tv.nsecs = 0;
2185 if (hfindex != -1) {
2186 if (data == 0xffffffff) {
2187 /* special case, no time specified */
2188 proto_tree_add_time_format_value(tree, hfindex, tvb, offset, 4, &tv, "No time specified");
2189 } else {
2190 proto_tree_add_time(tree, hfindex, tvb, offset, 4, &tv);
2191 }
2192 }
2193 if (pdata)
2194 *pdata = data;
2195
2196 tvb_ensure_bytes_exist(tvb, offset, 4);
2197 return offset+4;
2198 }
2199
2200 int
dissect_dcerpc_uint64(tvbuff_t * tvb,gint offset,packet_info * pinfo _U_,proto_tree * tree,dcerpc_info * di,guint8 * drep,int hfindex,guint64 * pdata)2201 dissect_dcerpc_uint64(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
2202 proto_tree *tree, dcerpc_info *di, guint8 *drep,
2203 int hfindex, guint64 *pdata)
2204 {
2205 guint64 data;
2206
2207 data = ((drep[0] & DREP_LITTLE_ENDIAN)
2208 ? tvb_get_letoh64(tvb, offset)
2209 : tvb_get_ntoh64(tvb, offset));
2210
2211 if (hfindex != -1) {
2212 header_field_info *hfinfo;
2213
2214 /* This might be a field that is either 32bit, in NDR or
2215 64 bits in NDR64. So we must be careful and call the right
2216 helper here
2217 */
2218 hfinfo = proto_registrar_get_nth(hfindex);
2219
2220 switch (hfinfo->type) {
2221 case FT_UINT64:
2222 proto_tree_add_uint64(tree, hfindex, tvb, offset, 8, data);
2223 break;
2224 case FT_INT64:
2225 proto_tree_add_int64(tree, hfindex, tvb, offset, 8, data);
2226 break;
2227 default:
2228 /* The value is truncated to 32bits. 64bit values have only been
2229 seen on fuzz-tested files */
2230 DISSECTOR_ASSERT((di->call_data->flags & DCERPC_IS_NDR64) || (data <= G_MAXUINT32));
2231 proto_tree_add_uint(tree, hfindex, tvb, offset, 8, (guint32)data);
2232 }
2233 }
2234 if (pdata)
2235 *pdata = data;
2236 tvb_ensure_bytes_exist(tvb, offset, 8);
2237 return offset+8;
2238 }
2239
2240
2241 int
dissect_dcerpc_float(tvbuff_t * tvb,gint offset,packet_info * pinfo,proto_tree * tree,guint8 * drep,int hfindex,gfloat * pdata)2242 dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2243 proto_tree *tree, guint8 *drep,
2244 int hfindex, gfloat *pdata)
2245 {
2246 gfloat data;
2247
2248
2249 switch (drep[1]) {
2250 case(DCE_RPC_DREP_FP_IEEE):
2251 data = ((drep[0] & DREP_LITTLE_ENDIAN)
2252 ? tvb_get_letohieee_float(tvb, offset)
2253 : tvb_get_ntohieee_float(tvb, offset));
2254 if (tree && hfindex != -1) {
2255 proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
2256 }
2257 break;
2258 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
2259 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
2260 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
2261 default:
2262 /* ToBeDone: non IEEE floating formats */
2263 /* Set data to a negative infinity value */
2264 data = -G_MAXFLOAT;
2265 proto_tree_add_expert_format(tree, pinfo, &ei_dcerpc_not_implemented, tvb, offset, 4,
2266 "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!",
2267 drep[1]);
2268 }
2269 if (pdata)
2270 *pdata = data;
2271 tvb_ensure_bytes_exist(tvb, offset, 4);
2272 return offset + 4;
2273 }
2274
2275
2276 int
dissect_dcerpc_double(tvbuff_t * tvb,gint offset,packet_info * pinfo _U_,proto_tree * tree,guint8 * drep,int hfindex,gdouble * pdata)2277 dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
2278 proto_tree *tree, guint8 *drep,
2279 int hfindex, gdouble *pdata)
2280 {
2281 gdouble data;
2282
2283
2284 switch (drep[1]) {
2285 case(DCE_RPC_DREP_FP_IEEE):
2286 data = ((drep[0] & DREP_LITTLE_ENDIAN)
2287 ? tvb_get_letohieee_double(tvb, offset)
2288 : tvb_get_ntohieee_double(tvb, offset));
2289 if (tree && hfindex != -1) {
2290 proto_tree_add_double(tree, hfindex, tvb, offset, 8, data);
2291 }
2292 break;
2293 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
2294 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
2295 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
2296 default:
2297 /* ToBeDone: non IEEE double formats */
2298 /* Set data to a negative infinity value */
2299 data = -G_MAXDOUBLE;
2300 proto_tree_add_expert_format(tree, pinfo, &ei_dcerpc_not_implemented, tvb, offset, 8,
2301 "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!",
2302 drep[1]);
2303 }
2304 if (pdata)
2305 *pdata = data;
2306 tvb_ensure_bytes_exist(tvb, offset, 8);
2307 return offset + 8;
2308 }
2309
2310
2311 int
dissect_dcerpc_uuid_t(tvbuff_t * tvb,gint offset,packet_info * pinfo _U_,proto_tree * tree,guint8 * drep,int hfindex,e_guid_t * pdata)2312 dissect_dcerpc_uuid_t(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
2313 proto_tree *tree, guint8 *drep,
2314 int hfindex, e_guid_t *pdata)
2315 {
2316 e_guid_t uuid;
2317
2318
2319 if (drep[0] & DREP_LITTLE_ENDIAN) {
2320 tvb_get_letohguid(tvb, offset, (e_guid_t *) &uuid);
2321 } else {
2322 tvb_get_ntohguid(tvb, offset, (e_guid_t *) &uuid);
2323 }
2324 if (tree && hfindex != -1) {
2325 proto_tree_add_guid(tree, hfindex, tvb, offset, 16, (e_guid_t *) &uuid);
2326 }
2327 if (pdata) {
2328 *pdata = uuid;
2329 }
2330 return offset + 16;
2331 }
2332
2333
2334 /*
2335 * a couple simpler things
2336 */
2337 guint16
dcerpc_tvb_get_ntohs(tvbuff_t * tvb,gint offset,guint8 * drep)2338 dcerpc_tvb_get_ntohs(tvbuff_t *tvb, gint offset, guint8 *drep)
2339 {
2340 if (drep[0] & DREP_LITTLE_ENDIAN) {
2341 return tvb_get_letohs(tvb, offset);
2342 } else {
2343 return tvb_get_ntohs(tvb, offset);
2344 }
2345 }
2346
2347 guint32
dcerpc_tvb_get_ntohl(tvbuff_t * tvb,gint offset,guint8 * drep)2348 dcerpc_tvb_get_ntohl(tvbuff_t *tvb, gint offset, guint8 *drep)
2349 {
2350 if (drep[0] & DREP_LITTLE_ENDIAN) {
2351 return tvb_get_letohl(tvb, offset);
2352 } else {
2353 return tvb_get_ntohl(tvb, offset);
2354 }
2355 }
2356
2357 void
dcerpc_tvb_get_uuid(tvbuff_t * tvb,gint offset,guint8 * drep,e_guid_t * uuid)2358 dcerpc_tvb_get_uuid(tvbuff_t *tvb, gint offset, guint8 *drep, e_guid_t *uuid)
2359 {
2360 if (drep[0] & DREP_LITTLE_ENDIAN) {
2361 tvb_get_letohguid(tvb, offset, (e_guid_t *) uuid);
2362 } else {
2363 tvb_get_ntohguid(tvb, offset, (e_guid_t *) uuid);
2364 }
2365 }
2366
2367
2368 /* NDR arrays */
2369 /* function to dissect a unidimensional conformant array */
2370 static int
dissect_ndr_ucarray_core(tvbuff_t * tvb,gint offset,packet_info * pinfo,proto_tree * tree,dcerpc_info * di,guint8 * drep,dcerpc_dissect_fnct_t * fnct_bytes,dcerpc_dissect_fnct_blk_t * fnct_block)2371 dissect_ndr_ucarray_core(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2372 proto_tree *tree, dcerpc_info *di, guint8 *drep,
2373 dcerpc_dissect_fnct_t *fnct_bytes,
2374 dcerpc_dissect_fnct_blk_t *fnct_block)
2375 {
2376 guint32 i;
2377 int old_offset;
2378 int conformance_size = 4;
2379
2380 /* ensure that just one pointer is set in the call */
2381 DISSECTOR_ASSERT((fnct_bytes && !fnct_block) || (!fnct_bytes && fnct_block));
2382
2383 if (di->call_data->flags & DCERPC_IS_NDR64) {
2384 conformance_size = 8;
2385 }
2386
2387 if (di->conformant_run) {
2388 guint64 val;
2389
2390 /* conformant run, just dissect the max_count header */
2391 old_offset = offset;
2392 di->conformant_run = 0;
2393 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
2394 hf_dcerpc_array_max_count, &val);
2395 di->array_max_count = (gint32)val;
2396 di->array_max_count_offset = offset-conformance_size;
2397 di->conformant_run = 1;
2398 di->conformant_eaten = offset-old_offset;
2399 } else {
2400 /* we don't remember where in the bytestream this field was */
2401 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, conformance_size, di->array_max_count);
2402
2403 /* real run, dissect the elements */
2404 if (fnct_block) {
2405 offset = (*fnct_block)(tvb, offset, di->array_max_count,
2406 pinfo, tree, di, drep);
2407 } else {
2408 for (i=0 ;i<di->array_max_count; i++) {
2409 offset = (*fnct_bytes)(tvb, offset, pinfo, tree, di, drep);
2410 }
2411 }
2412 }
2413
2414 return offset;
2415 }
2416
2417 int
dissect_ndr_ucarray_block(tvbuff_t * tvb,gint offset,packet_info * pinfo,proto_tree * tree,dcerpc_info * di,guint8 * drep,dcerpc_dissect_fnct_blk_t * fnct)2418 dissect_ndr_ucarray_block(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2419 proto_tree *tree, dcerpc_info *di, guint8 *drep,
2420 dcerpc_dissect_fnct_blk_t *fnct)
2421 {
2422 return dissect_ndr_ucarray_core(tvb, offset, pinfo, tree, di, drep, NULL, fnct);
2423 }
2424
2425 int
dissect_ndr_ucarray(tvbuff_t * tvb,gint offset,packet_info * pinfo,proto_tree * tree,dcerpc_info * di,guint8 * drep,dcerpc_dissect_fnct_t * fnct)2426 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2427 proto_tree *tree, dcerpc_info *di, guint8 *drep,
2428 dcerpc_dissect_fnct_t *fnct)
2429 {
2430 return dissect_ndr_ucarray_core(tvb, offset, pinfo, tree, di, drep, fnct, NULL);
2431 }
2432
2433 /* function to dissect a unidimensional conformant and varying array
2434 * depending on the dissection function passed as a parameter,
2435 * content of the array will be dissected as a block or byte by byte
2436 */
2437 static int
dissect_ndr_ucvarray_core(tvbuff_t * tvb,gint offset,packet_info * pinfo,proto_tree * tree,dcerpc_info * di,guint8 * drep,dcerpc_dissect_fnct_t * fnct_bytes,dcerpc_dissect_fnct_blk_t * fnct_block)2438 dissect_ndr_ucvarray_core(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2439 proto_tree *tree, dcerpc_info *di, guint8 *drep,
2440 dcerpc_dissect_fnct_t *fnct_bytes,
2441 dcerpc_dissect_fnct_blk_t *fnct_block)
2442 {
2443 guint32 i;
2444 int old_offset;
2445 int conformance_size = 4;
2446
2447 if (di->call_data->flags & DCERPC_IS_NDR64) {
2448 conformance_size = 8;
2449 }
2450
2451 if (di->conformant_run) {
2452 guint64 val;
2453
2454 /* conformant run, just dissect the max_count header */
2455 old_offset = offset;
2456 di->conformant_run = 0;
2457 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
2458 hf_dcerpc_array_max_count, &val);
2459 DISSECTOR_ASSERT(val <= G_MAXUINT32);
2460 di->array_max_count = (guint32)val;
2461 di->array_max_count_offset = offset-conformance_size;
2462 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
2463 hf_dcerpc_array_offset, &val);
2464 DISSECTOR_ASSERT(val <= G_MAXUINT32);
2465 di->array_offset = (guint32)val;
2466 di->array_offset_offset = offset-conformance_size;
2467 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
2468 hf_dcerpc_array_actual_count, &val);
2469 DISSECTOR_ASSERT(val <= G_MAXUINT32);
2470 di->array_actual_count = (guint32)val;
2471 di->array_actual_count_offset = offset-conformance_size;
2472 di->conformant_run = 1;
2473 di->conformant_eaten = offset-old_offset;
2474 } else {
2475 /* we don't remember where in the bytestream these fields were */
2476 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, conformance_size, di->array_max_count);
2477 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, conformance_size, di->array_offset);
2478 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, conformance_size, di->array_actual_count);
2479
2480 /* real run, dissect the elements */
2481 if (fnct_block) {
2482 offset = (*fnct_block)(tvb, offset, di->array_actual_count,
2483 pinfo, tree, di, drep);
2484 } else if (fnct_bytes) {
2485 for (i=0 ;i<di->array_actual_count; i++) {
2486 old_offset = offset;
2487 offset = (*fnct_bytes)(tvb, offset, pinfo, tree, di, drep);
2488 /* Make sure we're moving forward */
2489 if (old_offset >= offset)
2490 break;
2491 }
2492 }
2493 }
2494
2495 return offset;
2496 }
2497
2498 int
dissect_ndr_ucvarray_block(tvbuff_t * tvb,gint offset,packet_info * pinfo,proto_tree * tree,dcerpc_info * di,guint8 * drep,dcerpc_dissect_fnct_blk_t * fnct)2499 dissect_ndr_ucvarray_block(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2500 proto_tree *tree, dcerpc_info *di, guint8 *drep,
2501 dcerpc_dissect_fnct_blk_t *fnct)
2502 {
2503 return dissect_ndr_ucvarray_core(tvb, offset, pinfo, tree, di, drep, NULL, fnct);
2504 }
2505
2506 int
dissect_ndr_ucvarray(tvbuff_t * tvb,gint offset,packet_info * pinfo,proto_tree * tree,dcerpc_info * di,guint8 * drep,dcerpc_dissect_fnct_t * fnct)2507 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2508 proto_tree *tree, dcerpc_info *di, guint8 *drep,
2509 dcerpc_dissect_fnct_t *fnct)
2510 {
2511 return dissect_ndr_ucvarray_core(tvb, offset, pinfo, tree, di, drep, fnct, NULL);
2512 }
2513 /* function to dissect a unidimensional varying array */
2514 int
dissect_ndr_uvarray(tvbuff_t * tvb,gint offset,packet_info * pinfo,proto_tree * tree,dcerpc_info * di,guint8 * drep,dcerpc_dissect_fnct_t * fnct)2515 dissect_ndr_uvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2516 proto_tree *tree, dcerpc_info *di, guint8 *drep,
2517 dcerpc_dissect_fnct_t *fnct)
2518 {
2519 guint32 i;
2520 int old_offset;
2521 int conformance_size = 4;
2522
2523 if (di->call_data->flags & DCERPC_IS_NDR64) {
2524 conformance_size = 8;
2525 }
2526
2527 if (di->conformant_run) {
2528 guint64 val;
2529
2530 /* conformant run, just dissect the max_count header */
2531 old_offset = offset;
2532 di->conformant_run = 0;
2533 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
2534 hf_dcerpc_array_offset, &val);
2535 DISSECTOR_ASSERT(val <= G_MAXUINT32);
2536 di->array_offset = (guint32)val;
2537 di->array_offset_offset = offset-conformance_size;
2538 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
2539 hf_dcerpc_array_actual_count, &val);
2540 DISSECTOR_ASSERT(val <= G_MAXUINT32);
2541 di->array_actual_count = (guint32)val;
2542 di->array_actual_count_offset = offset-conformance_size;
2543 di->conformant_run = 1;
2544 di->conformant_eaten = offset-old_offset;
2545 } else {
2546 /* we don't remember where in the bytestream these fields were */
2547 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, conformance_size, di->array_offset);
2548 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, conformance_size, di->array_actual_count);
2549
2550 /* real run, dissect the elements */
2551 for (i=0; i<di->array_actual_count; i++) {
2552 offset = (*fnct)(tvb, offset, pinfo, tree, di, drep);
2553 }
2554 }
2555
2556 return offset;
2557 }
2558
2559 /* Dissect an string of bytes. This corresponds to
2560 IDL of the form '[string] byte *foo'.
2561
2562 It can also be used for a conformant varying array of bytes if
2563 the contents of the array should be shown as a big blob, rather
2564 than showing each byte as an individual element.
2565
2566 XXX - which of those is really the IDL type for, for example,
2567 the encrypted data in some MAPI packets? (Microsoft hasn't
2568 released that IDL.)
2569
2570 XXX - does this need to do all the conformant array stuff that
2571 "dissect_ndr_ucvarray()" does? These are presumably for strings
2572 that are conformant and varying - they're stored like conformant
2573 varying arrays of bytes. */
2574 int
dissect_ndr_byte_array(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * tree,dcerpc_info * di,guint8 * drep)2575 dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo,
2576 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2577 {
2578 guint64 len;
2579
2580 if (di->conformant_run) {
2581 /* just a run to handle conformant arrays, no scalars to dissect */
2582 return offset;
2583 }
2584
2585 /* NDR array header */
2586
2587 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
2588 hf_dcerpc_array_max_count, NULL);
2589
2590 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
2591 hf_dcerpc_array_offset, NULL);
2592
2593 offset = dissect_ndr_uint3264(tvb, offset, pinfo, tree, di, drep,
2594 hf_dcerpc_array_actual_count, &len);
2595
2596 DISSECTOR_ASSERT(len <= G_MAXUINT32);
2597 if (len) {
2598 proto_tree_add_item(tree, di->hf_index, tvb, offset, (guint32)len,
2599 ENC_NA);
2600 }
2601
2602 offset += (guint32)len;
2603
2604 return offset;
2605 }
2606
2607 /* For dissecting arrays that are to be interpreted as strings. */
2608
2609 /* Dissect an NDR conformant varying string of elements.
2610 The length of each element is given by the 'size_is' parameter;
2611 the elements are assumed to be characters or wide characters.
2612
2613 XXX - does this need to do all the conformant array stuff that
2614 "dissect_ndr_ucvarray()" does? */
2615 int
dissect_ndr_cvstring(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * tree,dcerpc_info * di,guint8 * drep,int size_is,int hfindex,gboolean add_subtree,char ** data)2616 dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2617 proto_tree *tree, dcerpc_info *di, guint8 *drep, int size_is,
2618 int hfindex, gboolean add_subtree, char **data)
2619 {
2620 header_field_info *hfinfo;
2621 proto_item *string_item;
2622 proto_tree *string_tree;
2623 guint64 len;
2624 guint32 buffer_len;
2625 char *s;
2626
2627 /* Make sure this really is a string field. */
2628 hfinfo = proto_registrar_get_nth(hfindex);
2629 DISSECTOR_ASSERT_FIELD_TYPE(hfinfo, FT_STRING);
2630
2631 if (di->conformant_run) {
2632 /* just a run to handle conformant arrays, no scalars to dissect */
2633 return offset;
2634 }
2635
2636 if (add_subtree) {
2637 string_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_dcerpc_string, &string_item,
2638 proto_registrar_get_name(hfindex));
2639 } else {
2640 string_item = NULL;
2641 string_tree = tree;
2642 }
2643
2644 /* NDR array header */
2645
2646 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
2647 hf_dcerpc_array_max_count, NULL);
2648
2649 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
2650 hf_dcerpc_array_offset, NULL);
2651
2652 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
2653 hf_dcerpc_array_actual_count, &len);
2654
2655 /* The value is truncated to 32bits. 64bit values have only been
2656 seen on fuzztested files */
2657 buffer_len = size_is * (guint32)len;
2658
2659 /* Adjust offset */
2660 if (!di->no_align && (offset % size_is))
2661 offset += size_is - (offset % size_is);
2662
2663 /*
2664 * "tvb_get_string_enc()" throws an exception if the entire string
2665 * isn't in the tvbuff. If the length is bogus, this should
2666 * keep us from trying to allocate an immensely large buffer.
2667 * (It won't help if the length is *valid* but immensely large,
2668 * but that's another matter; in any case, that would happen only
2669 * if we had an immensely large tvbuff....)
2670 *
2671 * XXX - so why are we doing tvb_ensure_bytes_exist()?
2672 */
2673 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
2674 if (size_is == sizeof(guint16)) {
2675 s = tvb_get_string_enc(pinfo->pool, tvb, offset, buffer_len,
2676 ENC_UTF_16|DREP_ENC_INTEGER(drep));
2677 } else {
2678 /*
2679 * XXX - what if size_is is neither 1 nor 2?
2680 */
2681 s = tvb_get_string_enc(pinfo->pool, tvb, offset, buffer_len,
2682 DREP_ENC_CHAR(drep));
2683 }
2684 if (tree && buffer_len)
2685 proto_tree_add_string(string_tree, hfindex, tvb, offset,
2686 buffer_len, s);
2687
2688 if (string_item != NULL)
2689 proto_item_append_text(string_item, ": %s", s);
2690
2691 if (data)
2692 *data = s;
2693
2694 offset += buffer_len;
2695
2696 proto_item_set_end(string_item, tvb, offset);
2697
2698 return offset;
2699 }
2700
2701 int
dissect_ndr_cstring(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * tree,dcerpc_info * di,guint8 * drep,int size_is,int hfindex,gboolean add_subtree,char ** data)2702 dissect_ndr_cstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2703 proto_tree *tree, dcerpc_info *di, guint8 *drep, int size_is,
2704 int hfindex, gboolean add_subtree, char **data)
2705 {
2706 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep, size_is, hfindex, add_subtree, data);
2707 }
2708
2709 /* Dissect an conformant varying string of chars.
2710 This corresponds to IDL of the form '[string] char *foo'.
2711
2712 XXX - at least according to the DCE RPC 1.1 spec, a string has
2713 a null terminator, which isn't necessary as a terminator for
2714 the transfer language (as there's a length), but is presumably
2715 there for the benefit of null-terminated-string languages
2716 such as C. Is this ever used for purely counted strings?
2717 (Not that it matters if it is.) */
2718 int
dissect_ndr_char_cvstring(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * tree,dcerpc_info * di,guint8 * drep)2719 dissect_ndr_char_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2720 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2721 {
2722 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep,
2723 sizeof(guint8), di->hf_index,
2724 FALSE, NULL);
2725 }
2726
2727 /* Dissect a conformant varying string of wchars (wide characters).
2728 This corresponds to IDL of the form '[string] wchar *foo'
2729
2730 XXX - at least according to the DCE RPC 1.1 spec, a string has
2731 a null terminator, which isn't necessary as a terminator for
2732 the transfer language (as there's a length), but is presumably
2733 there for the benefit of null-terminated-string languages
2734 such as C. Is this ever used for purely counted strings?
2735 (Not that it matters if it is.) */
2736 int
dissect_ndr_wchar_cvstring(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * tree,dcerpc_info * di,guint8 * drep)2737 dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2738 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2739 {
2740 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep,
2741 sizeof(guint16), di->hf_index,
2742 FALSE, NULL);
2743 }
2744
2745 /* This function is aimed for PIDL usage and dissects a UNIQUE pointer to
2746 * unicode string.
2747 */
2748 int
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)2749 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)
2750 {
2751 char *s = NULL;
2752 gint levels = CB_STR_ITEM_LEVELS(param);
2753
2754 offset = dissect_ndr_cvstring(tvb, offset, pinfo, tree, di, drep,
2755 chsize, hfindex,
2756 FALSE, &s);
2757
2758 if (!di->conformant_run) {
2759 /* Append string to COL_INFO */
2760 if (param & PIDL_SET_COL_INFO) {
2761 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", s);
2762 }
2763 /* Save string to dcv->private_data */
2764 if ((param & PIDL_STR_SAVE)
2765 && (!pinfo->fd->visited)) {
2766 dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
2767 dcv->private_data = wmem_strdup(wmem_file_scope(), s);
2768 }
2769 /* Append string to upper-level proto_items */
2770 if ((levels > 0) && tree && s && s[0]) {
2771 proto_item_append_text(tree, ": %s", s);
2772 tree = tree->parent;
2773 levels--;
2774 if (levels > 0) {
2775 proto_item_append_text(tree, ": %s", s);
2776 tree = tree->parent;
2777 levels--;
2778 while (levels > 0) {
2779 proto_item_append_text(tree, " %s", s);
2780 tree = tree->parent;
2781 levels--;
2782 }
2783 }
2784 }
2785
2786 }
2787
2788 return offset;
2789 }
2790
2791 /* Dissect an NDR varying string of elements.
2792 The length of each element is given by the 'size_is' parameter;
2793 the elements are assumed to be characters or wide characters.
2794 */
2795 int
dissect_ndr_vstring(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * tree,dcerpc_info * di,guint8 * drep,int size_is,int hfindex,gboolean add_subtree,char ** data)2796 dissect_ndr_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2797 proto_tree *tree, dcerpc_info *di, guint8 *drep, int size_is,
2798 int hfindex, gboolean add_subtree, char **data)
2799 {
2800 header_field_info *hfinfo;
2801 proto_item *string_item;
2802 proto_tree *string_tree;
2803 guint64 len;
2804 guint32 buffer_len;
2805 char *s;
2806
2807 /* Make sure this really is a string field. */
2808 hfinfo = proto_registrar_get_nth(hfindex);
2809 DISSECTOR_ASSERT_FIELD_TYPE(hfinfo, FT_STRING);
2810
2811 if (di->conformant_run) {
2812 /* just a run to handle conformant arrays, no scalars to dissect */
2813 return offset;
2814 }
2815
2816 if (add_subtree) {
2817 string_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_dcerpc_string, &string_item,
2818 proto_registrar_get_name(hfindex));
2819 } else {
2820 string_item = NULL;
2821 string_tree = tree;
2822 }
2823
2824 /* NDR array header */
2825 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
2826 hf_dcerpc_array_offset, NULL);
2827
2828 offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
2829 hf_dcerpc_array_actual_count, &len);
2830
2831 DISSECTOR_ASSERT(len <= G_MAXUINT32);
2832 buffer_len = size_is * (guint32)len;
2833
2834 /* Adjust offset */
2835 if (!di->no_align && (offset % size_is))
2836 offset += size_is - (offset % size_is);
2837
2838 /*
2839 * "tvb_get_string_enc()" throws an exception if the entire string
2840 * isn't in the tvbuff. If the length is bogus, this should
2841 * keep us from trying to allocate an immensely large buffer.
2842 * (It won't help if the length is *valid* but immensely large,
2843 * but that's another matter; in any case, that would happen only
2844 * if we had an immensely large tvbuff....)
2845 *
2846 * XXX - so why are we doing tvb_ensure_bytes_exist()?
2847 */
2848 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
2849 if (size_is == sizeof(guint16)) {
2850 s = tvb_get_string_enc(pinfo->pool, tvb, offset, buffer_len,
2851 ENC_UTF_16|DREP_ENC_INTEGER(drep));
2852 } else {
2853 /*
2854 * XXX - what if size_is is neither 1 nor 2?
2855 */
2856 s = tvb_get_string_enc(pinfo->pool, tvb, offset, buffer_len,
2857 DREP_ENC_CHAR(drep));
2858 }
2859 if (tree && buffer_len)
2860 proto_tree_add_string(string_tree, hfindex, tvb, offset,
2861 buffer_len, s);
2862
2863 if (string_item != NULL)
2864 proto_item_append_text(string_item, ": %s", s);
2865
2866 if (data)
2867 *data = s;
2868
2869 offset += buffer_len;
2870
2871 proto_item_set_end(string_item, tvb, offset);
2872
2873 return offset;
2874 }
2875
2876 /* Dissect an varying string of chars.
2877 This corresponds to IDL of the form '[string] char *foo'.
2878
2879 XXX - at least according to the DCE RPC 1.1 spec, a string has
2880 a null terminator, which isn't necessary as a terminator for
2881 the transfer language (as there's a length), but is presumably
2882 there for the benefit of null-terminated-string languages
2883 such as C. Is this ever used for purely counted strings?
2884 (Not that it matters if it is.) */
2885 int
dissect_ndr_char_vstring(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * tree,dcerpc_info * di,guint8 * drep)2886 dissect_ndr_char_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2887 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2888 {
2889 return dissect_ndr_vstring(tvb, offset, pinfo, tree, di, drep,
2890 sizeof(guint8), di->hf_index,
2891 FALSE, NULL);
2892 }
2893
2894 /* Dissect a varying string of wchars (wide characters).
2895 This corresponds to IDL of the form '[string] wchar *foo'
2896
2897 XXX - at least according to the DCE RPC 1.1 spec, a string has
2898 a null terminator, which isn't necessary as a terminator for
2899 the transfer language (as there's a length), but is presumably
2900 there for the benefit of null-terminated-string languages
2901 such as C. Is this ever used for purely counted strings?
2902 (Not that it matters if it is.) */
2903 int
dissect_ndr_wchar_vstring(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * tree,dcerpc_info * di,guint8 * drep)2904 dissect_ndr_wchar_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
2905 proto_tree *tree, dcerpc_info *di, guint8 *drep)
2906 {
2907 return dissect_ndr_vstring(tvb, offset, pinfo, tree, di, drep,
2908 sizeof(guint16), di->hf_index,
2909 FALSE, NULL);
2910 }
2911
2912 /* ndr pointer handling */
2913 /* Should we re-read the size of the list ?
2914 * Instead of re-calculating the size everytime, use the stored value unless this
2915 * flag is set which means: re-read the size of the list
2916 */
2917 static gboolean must_check_size = FALSE;
2918 /*
2919 * List of pointers encountered so far in the current level. Points to an
2920 * element of list_ndr_pointer_list.
2921 */
2922 static GSList *ndr_pointer_list = NULL;
2923
2924 static GHashTable *ndr_pointer_hash = NULL;
2925 /*
2926 * List of pointer list, in order to avoid huge performance penalty
2927 * when dealing with list bigger than 100 elements due to the way we
2928 * try to insert in the list.
2929 * We instead maintain a stack of pointer list
2930 * To make it easier to manage we just use a list to materialize the stack
2931 */
2932 static GSList *list_ndr_pointer_list = NULL;
2933
2934 /* Boolean controlling whether pointers are top-level or embedded */
2935 static gboolean pointers_are_top_level = TRUE;
2936
2937 /* as a kludge, we represent all embedded reference pointers as id == -1
2938 hoping that his will not collide with any non-ref pointers */
2939 typedef struct ndr_pointer_data {
2940 guint32 id;
2941 proto_item *item; /* proto_item for pointer */
2942 proto_tree *tree; /* subtree of above item */
2943 dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
2944 int hf_index;
2945 dcerpc_callback_fnct_t *callback;
2946 void *callback_args;
2947 } ndr_pointer_data_t;
2948
2949 void
init_ndr_pointer_list(dcerpc_info * di)2950 init_ndr_pointer_list(dcerpc_info *di)
2951 {
2952 di->conformant_run = 0;
2953
2954 while (list_ndr_pointer_list) {
2955 GSList *list = (GSList *)g_slist_nth_data(list_ndr_pointer_list, 0);
2956 list_ndr_pointer_list = g_slist_remove(list_ndr_pointer_list, list);
2957 g_slist_free_full(list, g_free);
2958 }
2959 g_slist_free_full(list_ndr_pointer_list, g_free);
2960
2961 list_ndr_pointer_list = NULL;
2962 pointers_are_top_level = TRUE;
2963 must_check_size = FALSE;
2964
2965 ndr_pointer_list = NULL;
2966 if (ndr_pointer_hash) {
2967 g_hash_table_destroy(ndr_pointer_hash);
2968 }
2969 ndr_pointer_hash = g_hash_table_new(g_int_hash, g_int_equal);
2970 }
2971
2972 int
dissect_deferred_pointers(packet_info * pinfo,tvbuff_t * tvb,int offset,dcerpc_info * di,guint8 * drep)2973 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, dcerpc_info *di, guint8 *drep)
2974 {
2975 int found_new_pointer;
2976 int old_offset;
2977 int next_pointer;
2978 unsigned original_depth;
2979 int len;
2980 GSList *current_ndr_pointer_list;
2981
2982 /*
2983 * pidl has a difficiency of unconditionally emitting calls
2984 * dissect_deferred_pointers() to the generated dissectors.
2985 */
2986 if (list_ndr_pointer_list == NULL) {
2987 return offset;
2988 }
2989
2990 /* Probably not necessary, it is supposed to prevent more pointers from
2991 * being added to the list. */
2992 ndr_pointer_list = NULL;
2993
2994 next_pointer = 0;
2995
2996 /* Obtain the current list of pointers at this level. */
2997 current_ndr_pointer_list = (GSList *)g_slist_last(list_ndr_pointer_list)->data;
2998 original_depth = g_slist_length(list_ndr_pointer_list);
2999
3000 len = g_slist_length(current_ndr_pointer_list);
3001 do {
3002 int i;
3003
3004 found_new_pointer = 0;
3005 process_list:
3006 for (i=next_pointer; i<len; i++) {
3007 ndr_pointer_data_t *tnpd = (ndr_pointer_data_t *)g_slist_nth_data(current_ndr_pointer_list, i);
3008
3009 if (tnpd->fnct) {
3010 GSList *saved_ndr_pointer_list = NULL;
3011
3012 dcerpc_dissect_fnct_t *fnct;
3013
3014 next_pointer = i+1;
3015 found_new_pointer = 1;
3016 fnct = tnpd->fnct;
3017 tnpd->fnct = NULL;
3018 di->hf_index = tnpd->hf_index;
3019 /* first a run to handle any conformant
3020 array headers */
3021 di->conformant_run = 1;
3022 di->conformant_eaten = 0;
3023 old_offset = offset;
3024 saved_ndr_pointer_list = current_ndr_pointer_list;
3025 ndr_pointer_list = NULL;
3026 offset = (*(fnct))(tvb, offset, pinfo, NULL, di, drep);
3027
3028 DISSECTOR_ASSERT((offset-old_offset) == di->conformant_eaten);
3029 /* This is to check for any bugs in the dissectors.
3030 *
3031 * Basically, the NDR representation will store all
3032 * arrays in two blocks, one block with the dimension
3033 * description, like size, number of elements and such,
3034 * and another block that contains the actual data stored
3035 * in the array.
3036 * If the array is embedded directly inside another,
3037 * encapsulating aggregate type, like a union or struct,
3038 * then these two blocks will be stored at different places
3039 * in the bytestream, with other data between the blocks.
3040 *
3041 * For this reason, all pointers to types (both aggregate
3042 * and scalar, for simplicity no distinction is made)
3043 * will have its dissector called twice.
3044 * The dissector will first be called with conformant_run == 1
3045 * in which mode the dissector MUST NOT consume any data from
3046 * the tvbuff (i.e. may not dissect anything) except the
3047 * initial control block for arrays.
3048 * The second time the dissector is called, with
3049 * conformant_run == 0, all other data for the type will be
3050 * dissected.
3051 *
3052 * All dissect_ndr_<type> dissectors are already prepared
3053 * for this and knows when it should eat data from the tvb
3054 * and when not to, so implementors of dissectors will
3055 * normally not need to worry about this or even know about
3056 * it. However, if a dissector for an aggregate type calls
3057 * a subdissector from outside packet-dcerpc.c, such as
3058 * the dissector in packet-smb.c for NT Security Descriptors
3059 * as an example, then it is VERY important to encapsulate
3060 * this call to an external subdissector with the appropriate
3061 * test for conformant_run, i.e. it will need something like
3062 *
3063 * dcerpc_info *di (received as function parameter)
3064 *
3065 * if (di->conformant_run) {
3066 * return offset;
3067 * }
3068 *
3069 * to make sure it makes the right thing.
3070 * This assert will signal when someone has forgotten to
3071 * make the dissector aware of this requirement.
3072 */
3073
3074 /* now we dissect the actual pointer */
3075 di->conformant_run = 0;
3076 old_offset = offset;
3077 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, di, drep);
3078 if (tnpd->callback)
3079 tnpd->callback(pinfo, tnpd->tree, tnpd->item, di, tvb, old_offset, offset, tnpd->callback_args);
3080 proto_item_set_len(tnpd->item, offset - old_offset);
3081 if (ndr_pointer_list) {
3082 /* We found some pointers to dissect, descend into it. */
3083 next_pointer = 0;
3084 len = g_slist_length(ndr_pointer_list);
3085 current_ndr_pointer_list = ndr_pointer_list;
3086 ndr_pointer_list = NULL;
3087 goto process_list; /* Process the new current_ndr_pointer_list */
3088 } else {
3089 current_ndr_pointer_list = saved_ndr_pointer_list;
3090 }
3091 }
3092 /* If we found the end of the list, but add_pointer_to_list extended
3093 * it, then be sure to handle those extra elements. */
3094 if (i == (len - 1) && (must_check_size == TRUE)) {
3095 len = g_slist_length(ndr_pointer_list);
3096 must_check_size = FALSE;
3097 }
3098 }
3099
3100 /* We reached the end of one level, go to the level bellow if possible
3101 * reset list a level n
3102 */
3103 if ((i >= (len - 1)) && (g_slist_length(list_ndr_pointer_list) > original_depth)) {
3104 GSList *list;
3105 /* Remove existing list */
3106 g_slist_free_full(current_ndr_pointer_list, g_free);
3107 list = (GSList *)g_slist_last(list_ndr_pointer_list)->data;
3108 list_ndr_pointer_list = g_slist_remove(list_ndr_pointer_list, list);
3109
3110 /* Rewind on the lower level, in theory it's not too great because we
3111 * will one more time iterate on pointers already done
3112 * In practice it shouldn't be that bad !
3113 */
3114 next_pointer = 0;
3115 /* Move to the next list of pointers. */
3116 current_ndr_pointer_list = (GSList *)g_slist_last(list_ndr_pointer_list)->data;
3117 len = g_slist_length(current_ndr_pointer_list);
3118 found_new_pointer = 1;
3119 }
3120
3121 } while (found_new_pointer);
3122 DISSECTOR_ASSERT(original_depth == g_slist_length(list_ndr_pointer_list));
3123
3124 g_slist_free_full(ndr_pointer_list, g_free);
3125 /* Restore the previous list of pointers. */
3126 ndr_pointer_list = (GSList *)g_slist_last(list_ndr_pointer_list)->data;
3127
3128 return offset;
3129 }
3130
3131 static int
find_pointer_index(guint32 id)3132 find_pointer_index(guint32 id)
3133 {
3134 guint *p = (guint*) g_hash_table_lookup(ndr_pointer_hash, &id);
3135
3136 return (p != NULL);
3137 }
3138
3139 static void
add_pointer_to_list(packet_info * pinfo,proto_tree * tree,proto_item * item,dcerpc_info * di,dcerpc_dissect_fnct_t * fnct,guint32 id,int hf_index,dcerpc_callback_fnct_t * callback,void * callback_args)3140 add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
3141 dcerpc_info *di, dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index,
3142 dcerpc_callback_fnct_t *callback, void *callback_args)
3143 {
3144 ndr_pointer_data_t *npd;
3145 guint *p_id;
3146
3147 /* check if this pointer is valid */
3148 if (id != 0xffffffff) {
3149 dcerpc_call_value *value;
3150
3151 value = di->call_data;
3152
3153 if (di->ptype == PDU_REQ) {
3154 if (!(pinfo->fd->visited)) {
3155 if (id > value->max_ptr) {
3156 value->max_ptr = id;
3157 }
3158 }
3159 } else {
3160 /* if we haven't seen the request bail out since we can't
3161 know whether this is the first non-NULL instance
3162 or not */
3163 if (value->req_frame == 0) {
3164 /* XXX THROW EXCEPTION */
3165 }
3166
3167 /* We saw this one in the request frame, nothing to
3168 dissect later */
3169 if (id <= value->max_ptr) {
3170 return;
3171 }
3172 }
3173 }
3174
3175 npd = g_new(ndr_pointer_data_t, 1);
3176 npd->id = id;
3177 npd->tree = tree;
3178 npd->item = item;
3179 npd->fnct = fnct;
3180 npd->hf_index = hf_index;
3181 npd->callback = callback;
3182 npd->callback_args = callback_args;
3183 p_id = wmem_new(wmem_file_scope(), guint);
3184 *p_id = id;
3185
3186 /* Update the list of pointers for use by dissect_deferred_pointers. If this
3187 * is the first pointer, create a list and add it to the stack. */
3188 if (!ndr_pointer_list) {
3189 ndr_pointer_list = g_slist_append(NULL, npd);
3190 list_ndr_pointer_list = g_slist_append(list_ndr_pointer_list, ndr_pointer_list);
3191 } else {
3192 ndr_pointer_list = g_slist_append(ndr_pointer_list, npd);
3193 }
3194 g_hash_table_insert(ndr_pointer_hash, p_id, p_id);
3195 must_check_size = TRUE;
3196 }
3197
3198
3199 /* This function dissects an NDR pointer and stores the callback for later
3200 * deferred dissection.
3201 *
3202 * fnct is the callback function for when we have reached this object in
3203 * the bytestream.
3204 *
3205 * type is what type of pointer.
3206 *
3207 * this is text is what text we should put in any created tree node.
3208 *
3209 * hf_index is what hf value we want to pass to the callback function when
3210 * it is called, the callback can later pick this one up from di->hf_index.
3211 *
3212 * callback is executed after the pointer has been dereferenced.
3213 *
3214 * callback_args is passed as an argument to the callback function
3215 *
3216 * See packet-dcerpc-samr.c for examples
3217 */
3218 int
dissect_ndr_pointer_cb(tvbuff_t * tvb,gint offset,packet_info * pinfo,proto_tree * tree,dcerpc_info * di,guint8 * drep,dcerpc_dissect_fnct_t * fnct,int type,const char * text,int hf_index,dcerpc_callback_fnct_t * callback,void * callback_args)3219 dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3220 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
3221 int type, const char *text, int hf_index,
3222 dcerpc_callback_fnct_t *callback, void *callback_args)
3223 {
3224 proto_tree *tr = NULL;
3225 gint start_offset = offset;
3226 int pointer_size = 4;
3227
3228 if (di->conformant_run) {
3229 /* this call was only for dissecting the header for any
3230 embedded conformant array. we will not parse any
3231 pointers in this mode.
3232 */
3233 return offset;
3234 }
3235 if (di->call_data->flags & DCERPC_IS_NDR64) {
3236 pointer_size = 8;
3237 }
3238
3239
3240 /*TOP LEVEL REFERENCE POINTER*/
3241 if ( pointers_are_top_level
3242 && (type == NDR_POINTER_REF) ) {
3243 proto_item *item;
3244
3245 /* we must find out a nice way to do the length here */
3246 tr = proto_tree_add_subtree(tree, tvb, offset, 0,
3247 ett_dcerpc_pointer_data, &item, text);
3248
3249 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
3250 hf_index, callback, callback_args);
3251 goto after_ref_id;
3252 }
3253
3254 /*TOP LEVEL FULL POINTER*/
3255 if ( pointers_are_top_level
3256 && (type == NDR_POINTER_PTR) ) {
3257 int found;
3258 guint64 id;
3259 proto_item *item;
3260
3261 /* get the referent id */
3262 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
3263
3264 /* we got a NULL pointer */
3265 if (id == 0) {
3266 proto_tree_add_bytes_format_value(tree, hf_dcerpc_null_pointer, tvb, offset-pointer_size,
3267 pointer_size, NULL, "%s", text);
3268 goto after_ref_id;
3269 }
3270
3271 /* see if we have seen this pointer before
3272 The value is truncated to 32bits. 64bit values have only been
3273 seen on fuzz-tested files */
3274 found = find_pointer_index((guint32)id);
3275
3276 /* we have seen this pointer before */
3277 if (found) {
3278 proto_tree_add_string(tree, hf_dcerpc_duplicate_ptr, tvb, offset-pointer_size, pointer_size, text);
3279 goto after_ref_id;
3280 }
3281
3282 /* new pointer */
3283 tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
3284 pointer_size, ett_dcerpc_pointer_data, &item, text);
3285 if (di->call_data->flags & DCERPC_IS_NDR64) {
3286 proto_tree_add_uint64(tr, hf_dcerpc_referent_id64, tvb,
3287 offset-pointer_size, pointer_size, id);
3288 } else {
3289 proto_tree_add_uint(tr, hf_dcerpc_referent_id32, tvb,
3290 offset-pointer_size, pointer_size, (guint32)id);
3291 }
3292 add_pointer_to_list(pinfo, tr, item, di, fnct, (guint32)id, hf_index,
3293 callback, callback_args);
3294 goto after_ref_id;
3295 }
3296 /*TOP LEVEL UNIQUE POINTER*/
3297 if ( pointers_are_top_level
3298 && (type == NDR_POINTER_UNIQUE) ) {
3299 guint64 id;
3300 proto_item *item;
3301
3302 /* get the referent id */
3303 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
3304
3305 /* we got a NULL pointer */
3306 if (id == 0) {
3307 proto_tree_add_bytes_format_value(tree, hf_dcerpc_null_pointer, tvb, offset-pointer_size,
3308 pointer_size, NULL, "%s",text);
3309 goto after_ref_id;
3310 }
3311
3312 /* new pointer */
3313 tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
3314 pointer_size,
3315 ett_dcerpc_pointer_data, &item, text);
3316 if (di->call_data->flags & DCERPC_IS_NDR64) {
3317 proto_tree_add_uint64(tr, hf_dcerpc_referent_id64, tvb,
3318 offset-pointer_size, pointer_size, id);
3319 } else {
3320 proto_tree_add_uint(tr, hf_dcerpc_referent_id32, tvb,
3321 offset-pointer_size, pointer_size, (guint32)id);
3322 }
3323 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
3324 hf_index, callback, callback_args);
3325 goto after_ref_id;
3326 }
3327
3328 /*EMBEDDED REFERENCE POINTER*/
3329 if ( (!pointers_are_top_level)
3330 && (type == NDR_POINTER_REF) ) {
3331 guint64 id;
3332 proto_item *item;
3333
3334 /* get the referent id */
3335 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
3336
3337 /* new pointer */
3338 tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
3339 pointer_size,
3340 ett_dcerpc_pointer_data,&item,text);
3341 if (di->call_data->flags & DCERPC_IS_NDR64) {
3342 proto_tree_add_uint64(tr, hf_dcerpc_referent_id64, tvb,
3343 offset-pointer_size, pointer_size, id);
3344 } else {
3345 proto_tree_add_uint(tr, hf_dcerpc_referent_id32, tvb,
3346 offset-pointer_size, pointer_size, (guint32)id);
3347 }
3348 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
3349 hf_index, callback, callback_args);
3350 goto after_ref_id;
3351 }
3352
3353 /*EMBEDDED UNIQUE POINTER*/
3354 if ( (!pointers_are_top_level)
3355 && (type == NDR_POINTER_UNIQUE) ) {
3356 guint64 id;
3357 proto_item *item;
3358
3359 /* get the referent id */
3360 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
3361
3362 /* we got a NULL pointer */
3363 if (id == 0) {
3364 proto_tree_add_bytes_format_value(tree, hf_dcerpc_null_pointer, tvb, offset-pointer_size,
3365 pointer_size, NULL, "%s",text);
3366 goto after_ref_id;
3367 }
3368
3369 /* new pointer */
3370 tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
3371 pointer_size,
3372 ett_dcerpc_pointer_data,&item,text);
3373 if (di->call_data->flags & DCERPC_IS_NDR64) {
3374 proto_tree_add_uint64(tr, hf_dcerpc_referent_id64, tvb,
3375 offset-pointer_size, pointer_size, id);
3376 } else {
3377 proto_tree_add_uint(tr, hf_dcerpc_referent_id32, tvb,
3378 offset-pointer_size, pointer_size, (guint32)id);
3379 }
3380 add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
3381 hf_index, callback, callback_args);
3382 goto after_ref_id;
3383 }
3384
3385 /*EMBEDDED FULL POINTER*/
3386 if ( (!pointers_are_top_level)
3387 && (type == NDR_POINTER_PTR) ) {
3388 int found;
3389 guint64 id;
3390 proto_item *item;
3391
3392 /* get the referent id */
3393 offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
3394
3395 /* we got a NULL pointer */
3396 if (id == 0) {
3397 proto_tree_add_bytes_format_value(tree, hf_dcerpc_null_pointer, tvb, offset-pointer_size,
3398 pointer_size, NULL, "%s",text);
3399 goto after_ref_id;
3400 }
3401
3402 /* see if we have seen this pointer before
3403 The value is truncated to 32bits. 64bit values have only been
3404 seen on fuzztested files */
3405 found = find_pointer_index((guint32)id);
3406
3407 /* we have seen this pointer before */
3408 if (found) {
3409 proto_tree_add_string(tree, hf_dcerpc_duplicate_ptr, tvb, offset-pointer_size, pointer_size, text);
3410 goto after_ref_id;
3411 }
3412
3413 /* new pointer */
3414 tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
3415 pointer_size,
3416 ett_dcerpc_pointer_data, &item, text);
3417 if (di->call_data->flags & DCERPC_IS_NDR64) {
3418 proto_tree_add_uint64(tr, hf_dcerpc_referent_id64, tvb,
3419 offset-pointer_size, pointer_size, id);
3420 } else {
3421 proto_tree_add_uint(tr, hf_dcerpc_referent_id32, tvb,
3422 offset-pointer_size, pointer_size, (guint32)id);
3423 }
3424 add_pointer_to_list(pinfo, tr, item, di, fnct, (guint32)id, hf_index,
3425 callback, callback_args);
3426 goto after_ref_id;
3427 }
3428
3429
3430 after_ref_id:
3431 /* After each top level pointer we have dissected we have to
3432 dissect all deferrals before we move on to the next top level
3433 argument */
3434 if (pointers_are_top_level == TRUE) {
3435 pointers_are_top_level = FALSE;
3436 offset = dissect_deferred_pointers(pinfo, tvb, offset, di, drep);
3437 pointers_are_top_level = TRUE;
3438 }
3439
3440 /* Set the length for the new subtree */
3441 if (tr) {
3442 proto_item_set_len(tr, offset-start_offset);
3443 }
3444 return offset;
3445 }
3446
3447 int
dissect_ndr_pointer(tvbuff_t * tvb,gint offset,packet_info * pinfo,proto_tree * tree,dcerpc_info * di,guint8 * drep,dcerpc_dissect_fnct_t * fnct,int type,const char * text,int hf_index)3448 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3449 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
3450 int type, const char *text, int hf_index)
3451 {
3452 return dissect_ndr_pointer_cb(
3453 tvb, offset, pinfo, tree, di, drep, fnct, type, text, hf_index,
3454 NULL, NULL);
3455 }
3456 int
dissect_ndr_toplevel_pointer(tvbuff_t * tvb,gint offset,packet_info * pinfo,proto_tree * tree,dcerpc_info * di,guint8 * drep,dcerpc_dissect_fnct_t * fnct,int type,const char * text,int hf_index)3457 dissect_ndr_toplevel_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3458 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
3459 int type, const char *text, int hf_index)
3460 {
3461 int ret;
3462
3463 pointers_are_top_level = TRUE;
3464 ret = dissect_ndr_pointer_cb(
3465 tvb, offset, pinfo, tree, di, drep, fnct, type, text, hf_index,
3466 NULL, NULL);
3467 return ret;
3468 }
3469 int
dissect_ndr_embedded_pointer(tvbuff_t * tvb,gint offset,packet_info * pinfo,proto_tree * tree,dcerpc_info * di,guint8 * drep,dcerpc_dissect_fnct_t * fnct,int type,const char * text,int hf_index)3470 dissect_ndr_embedded_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3471 proto_tree *tree, dcerpc_info *di, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
3472 int type, const char *text, int hf_index)
3473 {
3474 int ret;
3475
3476 pointers_are_top_level = FALSE;
3477 ret = dissect_ndr_pointer_cb(
3478 tvb, offset, pinfo, tree, di, drep, fnct, type, text, hf_index,
3479 NULL, NULL);
3480 return ret;
3481 }
3482
3483 static void
dissect_sec_vt_bitmask(proto_tree * tree,tvbuff_t * tvb)3484 dissect_sec_vt_bitmask(proto_tree *tree, tvbuff_t *tvb)
3485 {
3486 proto_tree_add_bitmask(tree, tvb, 0,
3487 hf_dcerpc_sec_vt_bitmask,
3488 ett_dcerpc_sec_vt_bitmask,
3489 sec_vt_bitmask_fields,
3490 ENC_LITTLE_ENDIAN);
3491 }
3492
3493 static void
dissect_sec_vt_pcontext(packet_info * pinfo,proto_tree * tree,tvbuff_t * tvb)3494 dissect_sec_vt_pcontext(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb)
3495 {
3496 int offset = 0;
3497 proto_item *ti = NULL;
3498 proto_tree *tr = proto_tree_add_subtree(tree, tvb, offset, -1,
3499 ett_dcerpc_sec_vt_pcontext,
3500 &ti, "pcontext");
3501 e_guid_t uuid;
3502 const char *uuid_name;
3503
3504 tvb_get_letohguid(tvb, offset, &uuid);
3505 uuid_name = guids_get_uuid_name(&uuid, pinfo->pool);
3506 if (!uuid_name) {
3507 uuid_name = guid_to_str(pinfo->pool, &uuid);
3508 }
3509
3510 proto_tree_add_guid_format(tr, hf_dcerpc_sec_vt_pcontext_uuid, tvb,
3511 offset, 16, &uuid, "Abstract Syntax: %s", uuid_name);
3512 offset += 16;
3513
3514 proto_tree_add_item(tr, hf_dcerpc_sec_vt_pcontext_ver,
3515 tvb, offset, 4, ENC_LITTLE_ENDIAN);
3516 offset += 4;
3517
3518 tvb_get_letohguid(tvb, offset, &uuid);
3519 uuid_name = guids_get_uuid_name(&uuid, pinfo->pool);
3520 if (!uuid_name) {
3521 uuid_name = guid_to_str(pinfo->pool, &uuid);
3522 }
3523
3524 proto_tree_add_guid_format(tr, hf_dcerpc_sec_vt_pcontext_uuid, tvb,
3525 offset, 16, &uuid, "Transfer Syntax: %s", uuid_name);
3526 offset += 16;
3527
3528 proto_tree_add_item(tr, hf_dcerpc_sec_vt_pcontext_ver,
3529 tvb, offset, 4, ENC_LITTLE_ENDIAN);
3530 offset += 4;
3531
3532 proto_item_set_len(ti, offset);
3533 }
3534
3535 static void
dissect_sec_vt_header(packet_info * pinfo,proto_tree * tree,tvbuff_t * tvb)3536 dissect_sec_vt_header(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb)
3537 {
3538 int offset = 0;
3539 proto_item *ti = NULL;
3540 proto_tree *tr = proto_tree_add_subtree(tree, tvb, offset, -1,
3541 ett_dcerpc_sec_vt_header,
3542 &ti, "header2");
3543 guint8 drep[4];
3544 guint8 ptype = tvb_get_guint8(tvb, offset);
3545
3546 proto_tree_add_uint(tr, hf_dcerpc_packet_type, tvb, offset, 1, ptype);
3547 offset += 1;
3548
3549 proto_tree_add_item(tr, hf_dcerpc_reserved, tvb, offset, 1, ENC_NA);
3550 offset += 1;
3551
3552 proto_tree_add_item(tr, hf_dcerpc_reserved, tvb, offset, 2, ENC_NA);
3553 offset += 2;
3554
3555 tvb_memcpy(tvb, drep, offset, 4);
3556 proto_tree_add_dcerpc_drep(tr, tvb, offset, drep, 4);
3557 offset += 4;
3558
3559 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tr, drep,
3560 hf_dcerpc_cn_call_id, NULL);
3561
3562 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tr, drep,
3563 hf_dcerpc_cn_ctx_id, NULL);
3564
3565 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tr, drep,
3566 hf_dcerpc_opnum, NULL);
3567
3568 proto_item_set_len(ti, offset);
3569 }
3570
3571 static int
dissect_verification_trailer_impl(packet_info * pinfo,tvbuff_t * tvb,int stub_offset,proto_tree * parent_tree,int * signature_offset)3572 dissect_verification_trailer_impl(packet_info *pinfo, tvbuff_t *tvb, int stub_offset,
3573 proto_tree *parent_tree, int *signature_offset)
3574 {
3575 int remaining = tvb_captured_length_remaining(tvb, stub_offset);
3576 int offset;
3577 gint signature_start;
3578 gint payload_length;
3579 typedef enum {
3580 SEC_VT_COMMAND_BITMASK_1 = 0x0001,
3581 SEC_VT_COMMAND_PCONTEXT = 0x0002,
3582 SEC_VT_COMMAND_HEADER2 = 0x0003,
3583 SEC_VT_COMMAND_END = 0x4000,
3584 SEC_VT_MUST_PROCESS_COMMAND = 0x8000,
3585 SEC_VT_COMMAND_MASK = 0x3fff,
3586 } sec_vt_command;
3587 proto_item *payload_item;
3588 proto_item *item;
3589 proto_tree *tree;
3590
3591 if (signature_offset != NULL) {
3592 *signature_offset = -1;
3593 }
3594
3595 /* We need at least signature + the header of one command */
3596 if (remaining < (int)(sizeof(TRAILER_SIGNATURE) + 4)) {
3597 return -1;
3598 }
3599
3600 /* We only scan the last 512 bytes for a possible trailer */
3601 if (remaining > 512) {
3602 offset = remaining - 512;
3603 remaining = 512;
3604 } else {
3605 offset = 0;
3606 }
3607 offset += stub_offset;
3608
3609 signature_start = tvb_find_tvb(tvb, tvb_trailer_signature, offset);
3610 if (signature_start == -1) {
3611 return -1;
3612 }
3613 payload_length = signature_start - stub_offset;
3614 payload_item = proto_tree_add_item(parent_tree,
3615 hf_dcerpc_payload_stub_data,
3616 tvb, stub_offset, payload_length, ENC_NA);
3617 proto_item_append_text(payload_item, " (%d byte%s)",
3618 payload_length, plurality(payload_length, "", "s"));
3619
3620 if (signature_offset != NULL) {
3621 *signature_offset = signature_start;
3622 }
3623 remaining -= (signature_start - offset);
3624 offset = signature_start;
3625
3626 tree = proto_tree_add_subtree(parent_tree, tvb, offset, -1,
3627 ett_dcerpc_verification_trailer,
3628 &item, "Verification Trailer");
3629
3630 proto_tree_add_item(tree, hf_dcerpc_sec_vt_signature,
3631 tvb, offset, sizeof(TRAILER_SIGNATURE), ENC_NA);
3632 offset += (int)sizeof(TRAILER_SIGNATURE);
3633 remaining -= (int)sizeof(TRAILER_SIGNATURE);
3634
3635 while (remaining >= 4) {
3636 sec_vt_command cmd;
3637 guint16 len, len_missalign;
3638 gboolean cmd_end, cmd_must;
3639 proto_item *ti;
3640 proto_tree *tr;
3641 tvbuff_t *cmd_tvb = NULL;
3642
3643 cmd = (sec_vt_command)tvb_get_letohs(tvb, offset);
3644 len = tvb_get_letohs(tvb, offset + 2);
3645 cmd_end = cmd & SEC_VT_COMMAND_END;
3646 cmd_must = cmd & SEC_VT_MUST_PROCESS_COMMAND;
3647 cmd = (sec_vt_command)(cmd & SEC_VT_COMMAND_MASK);
3648
3649 tr = proto_tree_add_subtree_format(tree, tvb, offset, 4 + len,
3650 ett_dcerpc_sec_vt_pcontext,
3651 &ti, "Command: %s",
3652 val_to_str(cmd, sec_vt_command_cmd_vals,
3653 "Unknown (0x%04x)"));
3654
3655 if (cmd_must) {
3656 proto_item_append_text(ti, "!!!");
3657 }
3658 if (cmd_end) {
3659 proto_item_append_text(ti, ", END");
3660 }
3661
3662 proto_tree_add_bitmask(tr, tvb, offset,
3663 hf_dcerpc_sec_vt_command,
3664 ett_dcerpc_sec_vt_command,
3665 sec_vt_command_fields,
3666 ENC_LITTLE_ENDIAN);
3667 offset += 2;
3668
3669 proto_tree_add_item(tr, hf_dcerpc_sec_vt_command_length, tvb,
3670 offset, 2, ENC_LITTLE_ENDIAN);
3671 offset += 2;
3672
3673 cmd_tvb = tvb_new_subset_length(tvb, offset, len);
3674 switch (cmd) {
3675 case SEC_VT_COMMAND_BITMASK_1:
3676 dissect_sec_vt_bitmask(tr, cmd_tvb);
3677 break;
3678 case SEC_VT_COMMAND_PCONTEXT:
3679 dissect_sec_vt_pcontext(pinfo, tr, cmd_tvb);
3680 break;
3681 case SEC_VT_COMMAND_HEADER2:
3682 dissect_sec_vt_header(pinfo, tr, cmd_tvb);
3683 break;
3684 default:
3685 proto_tree_add_item(tr, hf_dcerpc_unknown, cmd_tvb, 0, len, ENC_NA);
3686 break;
3687 }
3688
3689 offset += len;
3690 remaining -= (4 + len);
3691
3692 len_missalign = len & 1;
3693
3694 if (len_missalign) {
3695 int l = 2-len_missalign;
3696 proto_tree_add_item(tr, hf_dcerpc_missalign, tvb, offset, l, ENC_NA);
3697 offset += l;
3698 remaining -= l;
3699 }
3700
3701 if (cmd_end) {
3702 break;
3703 }
3704 }
3705
3706 proto_item_set_end(item, tvb, offset);
3707 return offset;
3708 }
3709
3710 static int
dissect_verification_trailer(packet_info * pinfo,tvbuff_t * tvb,int stub_offset,proto_tree * parent_tree,int * signature_offset)3711 dissect_verification_trailer(packet_info *pinfo, tvbuff_t *tvb, int stub_offset,
3712 proto_tree *parent_tree, int *signature_offset)
3713 {
3714 volatile int ret = -1;
3715 TRY {
3716 /*
3717 * Even if we found a signature we can't be sure to have a
3718 * valid verification trailer, we're only relatively sure
3719 * if we manage to dissect it completely, otherwise it
3720 * may be part of the real payload. That's why we have
3721 * a try/catch block here.
3722 */
3723 ret = dissect_verification_trailer_impl(pinfo, tvb, stub_offset, parent_tree, signature_offset);
3724 } CATCH_NONFATAL_ERRORS {
3725 } ENDTRY;
3726 return ret;
3727 }
3728
3729 static int
dcerpc_try_handoff(packet_info * pinfo,proto_tree * tree,proto_tree * dcerpc_tree,tvbuff_t * volatile tvb,gboolean decrypted,guint8 * drep,dcerpc_info * info,dcerpc_auth_info * auth_info)3730 dcerpc_try_handoff(packet_info *pinfo, proto_tree *tree,
3731 proto_tree *dcerpc_tree,
3732 tvbuff_t *volatile tvb, gboolean decrypted,
3733 guint8 *drep, dcerpc_info *info,
3734 dcerpc_auth_info *auth_info)
3735 {
3736 volatile gint offset = 0;
3737 guid_key key;
3738 dcerpc_dissector_data_t dissector_data;
3739 proto_item *hidden_item;
3740
3741 /* GUID and UUID are same size, but compiler complains about structure "name" differences */
3742 memcpy(&key.guid, &info->call_data->uuid, sizeof(key.guid));
3743 key.ver = info->call_data->ver;
3744
3745 dissector_data.sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key);
3746 dissector_data.info = info;
3747 dissector_data.decrypted = decrypted;
3748 dissector_data.auth_info = auth_info;
3749 dissector_data.drep = drep;
3750 dissector_data.dcerpc_tree = dcerpc_tree;
3751
3752 /* Check the dissector table before the hash table. Hopefully the hash table entries can
3753 all be converted to use dissector table */
3754 if ((dissector_data.sub_proto == NULL) ||
3755 (!dissector_try_guid_new(uuid_dissector_table, &key, tvb, pinfo, tree, FALSE, &dissector_data))) {
3756 /*
3757 * We don't have a dissector for this UUID, or the protocol
3758 * for that UUID is disabled.
3759 */
3760
3761 hidden_item = proto_tree_add_boolean(dcerpc_tree, hf_dcerpc_unknown_if_id,
3762 tvb, offset, 0, TRUE);
3763 proto_item_set_hidden(hidden_item);
3764 col_append_fstr(pinfo->cinfo, COL_INFO, " %s V%u",
3765 guids_resolve_guid_to_str(&info->call_data->uuid, pinfo->pool), info->call_data->ver);
3766
3767 show_stub_data(pinfo, tvb, 0, dcerpc_tree, auth_info, !decrypted);
3768 return -1;
3769 }
3770
3771 tap_queue_packet(dcerpc_tap, pinfo, info);
3772 return 0;
3773 }
3774
3775 static void
dissect_dcerpc_cn_auth_move(dcerpc_auth_info * auth_info,proto_tree * dcerpc_tree)3776 dissect_dcerpc_cn_auth_move(dcerpc_auth_info *auth_info, proto_tree *dcerpc_tree)
3777 {
3778 if (auth_info->auth_item != NULL) {
3779 proto_item *last_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_auth_info,
3780 auth_info->auth_tvb, 0, 0, ENC_NA);
3781 if (last_item != NULL) {
3782 proto_item_set_hidden(last_item);
3783 proto_tree_move_item(dcerpc_tree, last_item, auth_info->auth_item);
3784 }
3785 }
3786 }
3787
find_or_create_dcerpc_auth_context(packet_info * pinfo,dcerpc_auth_info * auth_info)3788 static dcerpc_auth_context *find_or_create_dcerpc_auth_context(packet_info *pinfo,
3789 dcerpc_auth_info *auth_info)
3790 {
3791 dcerpc_auth_context auth_key = {
3792 .conv = find_or_create_conversation(pinfo),
3793 .transport_salt = dcerpc_get_transport_salt(pinfo),
3794 .auth_type = auth_info->auth_type,
3795 .auth_level = auth_info->auth_level,
3796 .auth_context_id = auth_info->auth_context_id,
3797 .first_frame = G_MAXUINT32,
3798 };
3799 dcerpc_auth_context *auth_value = NULL;
3800
3801 auth_value = (dcerpc_auth_context *)wmem_map_lookup(dcerpc_auths, &auth_key);
3802 if (auth_value != NULL) {
3803 goto return_value;
3804 }
3805
3806 auth_value = wmem_new(wmem_file_scope(), dcerpc_auth_context);
3807 if (auth_value == NULL) {
3808 return NULL;
3809 }
3810
3811 *auth_value = auth_key;
3812 wmem_map_insert(dcerpc_auths, auth_value, auth_value);
3813
3814 return_value:
3815 if (pinfo->fd->num < auth_value->first_frame) {
3816 auth_value->first_frame = pinfo->fd->num;
3817 }
3818 return auth_value;
3819 }
3820
3821 static void
dissect_dcerpc_cn_auth(tvbuff_t * tvb,int stub_offset,packet_info * pinfo,proto_tree * dcerpc_tree,e_dce_cn_common_hdr_t * hdr,dcerpc_auth_info * auth_info)3822 dissect_dcerpc_cn_auth(tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
3823 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
3824 dcerpc_auth_info *auth_info)
3825 {
3826 volatile int offset;
3827
3828 /*
3829 * Initially set auth_level and auth_type to zero to indicate that we
3830 * haven't yet seen any authentication level information.
3831 */
3832 auth_info->hdr_signing = FALSE;
3833 auth_info->auth_type = 0;
3834 auth_info->auth_level = 0;
3835 auth_info->auth_context_id = 0;
3836 auth_info->auth_pad_len = 0;
3837 auth_info->auth_size = 0;
3838 auth_info->auth_fns = NULL;
3839 auth_info->auth_tvb = NULL;
3840 auth_info->auth_item = NULL;
3841 auth_info->auth_tree = NULL;
3842 auth_info->auth_hdr_tvb = NULL;
3843
3844 /*
3845 * The authentication information is at the *end* of the PDU; in
3846 * request and response PDUs, the request and response stub data
3847 * come before it.
3848 *
3849 * Is there any authentication data (i.e., is the authentication length
3850 * non-zero), and is the authentication length valid (i.e., is it, plus
3851 * 8 bytes for the type/level/pad length/reserved/context id, less than
3852 * or equal to the fragment length minus the starting offset of the
3853 * stub data?)
3854 */
3855
3856 if (hdr->auth_len
3857 && ((hdr->auth_len + 8) <= (hdr->frag_len - stub_offset))) {
3858
3859 /*
3860 * Yes, there is authentication data, and the length is valid.
3861 * Do we have all the bytes of stub data?
3862 * (If not, we'd throw an exception dissecting *that*, so don't
3863 * bother trying to dissect the authentication information and
3864 * throwing another exception there.)
3865 */
3866 offset = hdr->frag_len - (hdr->auth_len + 8);
3867 if (offset == 0 || tvb_offset_exists(tvb, offset - 1)) {
3868 dcerpc_auth_context *auth_context = NULL;
3869 int auth_offset = offset;
3870
3871 /* Compute the size of the auth block. Note that this should not
3872 include auth padding, since when NTLMSSP encryption is used, the
3873 padding is actually inside the encrypted stub */
3874 auth_info->auth_size = hdr->auth_len + 8;
3875
3876 auth_info->auth_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_auth_info,
3877 tvb, offset, auth_info->auth_size, ENC_NA);
3878 auth_info->auth_tree = proto_item_add_subtree(auth_info->auth_item, ett_dcerpc_auth_info);
3879
3880 /*
3881 * Either there's no stub data, or the last byte of the stub
3882 * data is present in the captured data, so we shouldn't
3883 * get a BoundsError dissecting the stub data.
3884 *
3885 * Try dissecting the authentication data.
3886 * Catch all exceptions, so that even if the auth info is bad
3887 * or we don't have all of it, we still show the stuff we
3888 * dissect after this, such as stub data.
3889 */
3890 TRY {
3891 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, auth_info->auth_tree, hdr->drep,
3892 hf_dcerpc_auth_type,
3893 &auth_info->auth_type);
3894 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, auth_info->auth_tree, hdr->drep,
3895 hf_dcerpc_auth_level,
3896 &auth_info->auth_level);
3897
3898 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, auth_info->auth_tree, hdr->drep,
3899 hf_dcerpc_auth_pad_len,
3900 &auth_info->auth_pad_len);
3901 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, auth_info->auth_tree, hdr->drep,
3902 hf_dcerpc_auth_rsrvd, NULL);
3903 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, auth_info->auth_tree, hdr->drep,
3904 hf_dcerpc_auth_ctx_id,
3905 &auth_info->auth_context_id);
3906
3907 proto_item_append_text(auth_info->auth_item,
3908 ": %s, %s, AuthContextId(%d)",
3909 val_to_str(auth_info->auth_type,
3910 authn_protocol_vals,
3911 "AuthType(%u)"),
3912 val_to_str(auth_info->auth_level,
3913 authn_level_vals,
3914 "AuthLevel(%u)"),
3915 auth_info->auth_context_id);
3916
3917 /*
3918 * Dissect the authentication data.
3919 */
3920 auth_info->auth_hdr_tvb = tvb_new_subset_length_caplen(tvb, auth_offset, 8, 8);
3921 auth_info->auth_tvb = tvb_new_subset_length_caplen(tvb, offset,
3922 MIN(hdr->auth_len,tvb_reported_length_remaining(tvb, offset)),
3923 hdr->auth_len);
3924
3925 auth_context = find_or_create_dcerpc_auth_context(pinfo, auth_info);
3926 if (auth_context != NULL) {
3927 if (hdr->ptype == PDU_BIND || hdr->ptype == PDU_ALTER) {
3928 if (auth_context->first_frame == pinfo->fd->num) {
3929 auth_context->hdr_signing = (hdr->flags & PFC_HDR_SIGNING);
3930 }
3931 }
3932
3933 auth_info->hdr_signing = auth_context->hdr_signing;
3934 }
3935
3936 auth_info->auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
3937 auth_info->auth_type);
3938 if (auth_info->auth_fns != NULL)
3939 dissect_auth_verf(pinfo, hdr, auth_info);
3940 else
3941 proto_tree_add_item(auth_info->auth_tree,
3942 hf_dcerpc_auth_credentials,
3943 auth_info->auth_tvb, 0,
3944 hdr->auth_len, ENC_NA);
3945
3946 } CATCH_BOUNDS_ERRORS {
3947 show_exception(tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
3948 } ENDTRY;
3949 }
3950 }
3951 }
3952
3953
3954 /* We need to hash in the SMB fid number to generate a unique hash table
3955 * key as DCERPC over SMB allows several pipes over the same TCP/IP
3956 * socket.
3957 * We pass this function the transport type here to make sure we only look
3958 * at this function if it came across an SMB pipe.
3959 * Other transports might need to mix in their own extra multiplexing data
3960 * as well in the future.
3961 */
3962
3963 guint64
dcerpc_get_transport_salt(packet_info * pinfo)3964 dcerpc_get_transport_salt(packet_info *pinfo)
3965 {
3966 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
3967
3968 switch (decode_data->dcetransporttype) {
3969 case DCE_CN_TRANSPORT_SMBPIPE:
3970 /* DCERPC over smb */
3971 return decode_data->dcetransportsalt;
3972 }
3973
3974 /* Some other transport... */
3975 return 0;
3976 }
3977
3978 void
dcerpc_set_transport_salt(guint64 dcetransportsalt,packet_info * pinfo)3979 dcerpc_set_transport_salt(guint64 dcetransportsalt, packet_info *pinfo)
3980 {
3981 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
3982
3983 decode_data->dcetransportsalt = dcetransportsalt;
3984 }
3985
3986 /*
3987 * Connection oriented packet types
3988 */
3989
3990 static void
dissect_dcerpc_cn_bind(tvbuff_t * tvb,gint offset,packet_info * pinfo,proto_tree * dcerpc_tree,e_dce_cn_common_hdr_t * hdr)3991 dissect_dcerpc_cn_bind(tvbuff_t *tvb, gint offset, packet_info *pinfo,
3992 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
3993 {
3994 conversation_t *conv = find_or_create_conversation(pinfo);
3995 guint8 num_ctx_items = 0;
3996 guint i;
3997 guint16 ctx_id;
3998 guint8 num_trans_items;
3999 guint j;
4000 e_guid_t if_id;
4001 e_guid_t trans_id;
4002 guint32 trans_ver;
4003 guint16 if_ver, if_ver_minor;
4004 dcerpc_auth_info auth_info;
4005 char *uuid_str;
4006 const char *uuid_name = NULL;
4007 proto_item *iface_item = NULL;
4008 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
4009
4010 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4011 hf_dcerpc_cn_max_xmit, NULL);
4012
4013 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4014 hf_dcerpc_cn_max_recv, NULL);
4015
4016 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4017 hf_dcerpc_cn_assoc_group, NULL);
4018
4019 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4020 hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
4021
4022 /* padding */
4023 offset += 3;
4024
4025 col_append_fstr(pinfo->cinfo, COL_INFO, ", %u context items:", num_ctx_items);
4026
4027 for (i = 0; i < num_ctx_items; i++) {
4028 proto_item *ctx_item = NULL;
4029 proto_tree *ctx_tree = NULL, *iface_tree = NULL;
4030 gint ctx_offset = offset;
4031
4032 dissect_dcerpc_uint16(tvb, offset, pinfo, NULL, hdr->drep,
4033 hf_dcerpc_cn_ctx_id, &ctx_id);
4034
4035 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
4036 /* (if we have multiple contexts, this might cause "decode as"
4037 * to behave unpredictably) */
4038 decode_data->dcectxid = ctx_id;
4039
4040 if (dcerpc_tree) {
4041 ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_item,
4042 tvb, offset, 0,
4043 ENC_NA);
4044 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
4045 }
4046
4047 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree, hdr->drep,
4048 hf_dcerpc_cn_ctx_id, &ctx_id);
4049 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, ctx_tree, hdr->drep,
4050 hf_dcerpc_cn_num_trans_items, &num_trans_items);
4051
4052 if (dcerpc_tree) {
4053 proto_item_append_text(ctx_item, "[%u]: Context ID:%u", i+1, ctx_id);
4054 }
4055
4056 /* padding */
4057 offset += 1;
4058
4059 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &if_id);
4060 if (ctx_tree) {
4061
4062 iface_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_abstract_syntax, tvb, offset, 0, ENC_NA);
4063 iface_tree = proto_item_add_subtree(iface_item, ett_dcerpc_cn_iface);
4064
4065 uuid_str = guid_to_str(pinfo->pool, (e_guid_t*)&if_id);
4066 uuid_name = guids_get_uuid_name(&if_id, pinfo->pool);
4067 if (uuid_name) {
4068 proto_tree_add_guid_format(iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
4069 offset, 16, (e_guid_t *) &if_id, "Interface: %s UUID: %s", uuid_name, uuid_str);
4070 proto_item_append_text(iface_item, ": %s", uuid_name);
4071 proto_item_append_text(ctx_item, ", %s", uuid_name);
4072 } else {
4073 proto_tree_add_guid_format(iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
4074 offset, 16, (e_guid_t *) &if_id, "Interface UUID: %s", uuid_str);
4075 proto_item_append_text(iface_item, ": %s", uuid_str);
4076 proto_item_append_text(ctx_item, ", %s", uuid_str);
4077 }
4078 }
4079 offset += 16;
4080
4081 if (hdr->drep[0] & DREP_LITTLE_ENDIAN) {
4082 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
4083 hf_dcerpc_cn_bind_if_ver, &if_ver);
4084 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
4085 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
4086 } else {
4087 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
4088 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
4089 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iface_tree, hdr->drep,
4090 hf_dcerpc_cn_bind_if_ver, &if_ver);
4091 }
4092
4093 if (ctx_tree) {
4094 proto_item_append_text(iface_item, " V%u.%u", if_ver, if_ver_minor);
4095 proto_item_set_len(iface_item, 20);
4096 }
4097
4098 memset(&trans_id, 0, sizeof(trans_id));
4099 for (j = 0; j < num_trans_items; j++) {
4100 proto_tree *trans_tree = NULL;
4101 proto_item *trans_item = NULL;
4102
4103 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &trans_id);
4104 if (ctx_tree) {
4105
4106 trans_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_trans_syntax, tvb, offset, 0, ENC_NA);
4107 trans_tree = proto_item_add_subtree(trans_item, ett_dcerpc_cn_trans_syntax);
4108
4109 uuid_str = guid_to_str(pinfo->pool, (e_guid_t *) &trans_id);
4110 uuid_name = guids_get_uuid_name(&trans_id, pinfo->pool);
4111
4112 /* check for [MS-RPCE] 3.3.1.5.3 Bind Time Feature Negotiation */
4113 if (trans_id.data1 == 0x6cb71c2c && trans_id.data2 == 0x9812 && trans_id.data3 == 0x4540) {
4114 proto_tree_add_guid_format(trans_tree, hf_dcerpc_cn_bind_trans_id,
4115 tvb, offset, 16, (e_guid_t *) &trans_id,
4116 "Transfer Syntax: Bind Time Feature Negotiation UUID:%s",
4117 uuid_str);
4118 proto_tree_add_bitmask(trans_tree, tvb, offset + 8,
4119 hf_dcerpc_cn_bind_trans_btfn,
4120 ett_dcerpc_cn_bind_trans_btfn,
4121 dcerpc_cn_bind_trans_btfn_fields,
4122 ENC_LITTLE_ENDIAN);
4123 proto_item_append_text(trans_item, "[%u]: Bind Time Feature Negotiation", j+1);
4124 proto_item_append_text(ctx_item, ", Bind Time Feature Negotiation");
4125 } else if (uuid_name) {
4126 proto_tree_add_guid_format(trans_tree, hf_dcerpc_cn_bind_trans_id,
4127 tvb, offset, 16, (e_guid_t *) &trans_id,
4128 "Transfer Syntax: %s UUID:%s", uuid_name, uuid_str);
4129 proto_item_append_text(trans_item, "[%u]: %s", j+1, uuid_name);
4130 proto_item_append_text(ctx_item, ", %s", uuid_name);
4131 } else {
4132 proto_tree_add_guid_format(trans_tree, hf_dcerpc_cn_bind_trans_id,
4133 tvb, offset, 16, (e_guid_t *) &trans_id,
4134 "Transfer Syntax: %s", uuid_str);
4135 proto_item_append_text(trans_item, "[%u]: %s", j+1, uuid_str);
4136 proto_item_append_text(ctx_item, ", %s", uuid_str);
4137 }
4138
4139 }
4140 offset += 16;
4141
4142 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, trans_tree, hdr->drep,
4143 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
4144 if (ctx_tree) {
4145 proto_item_set_len(trans_item, 20);
4146 proto_item_append_text(trans_item, " V%u", trans_ver);
4147 }
4148 }
4149
4150 /* if this is the first time we've seen this packet, we need to
4151 update the dcerpc_binds table so that any later calls can
4152 match to the interface.
4153 XXX We assume that BINDs will NEVER be fragmented.
4154 */
4155 if (!(pinfo->fd->visited)) {
4156 dcerpc_bind_key *key;
4157 dcerpc_bind_value *value;
4158
4159 key = wmem_new(wmem_file_scope(), dcerpc_bind_key);
4160 key->conv = conv;
4161 key->ctx_id = ctx_id;
4162 key->transport_salt = dcerpc_get_transport_salt(pinfo);
4163
4164 value = wmem_new(wmem_file_scope(), dcerpc_bind_value);
4165 value->uuid = if_id;
4166 value->ver = if_ver;
4167 value->transport = trans_id;
4168
4169 /* add this entry to the bind table */
4170 wmem_map_insert(dcerpc_binds, key, value);
4171 }
4172
4173 if (i > 0)
4174 col_append_fstr(pinfo->cinfo, COL_INFO, ",");
4175 col_append_fstr(pinfo->cinfo, COL_INFO, " %s V%u.%u (%s)",
4176 guids_resolve_guid_to_str(&if_id, pinfo->pool), if_ver, if_ver_minor,
4177 guids_resolve_guid_to_str(&trans_id, pinfo->pool));
4178
4179 if (ctx_tree) {
4180 proto_item_set_len(ctx_item, offset - ctx_offset);
4181 }
4182 }
4183
4184 /*
4185 * XXX - we should save the authentication type *if* we have
4186 * an authentication header, and associate it with an authentication
4187 * context, so subsequent PDUs can use that context.
4188 */
4189 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, &auth_info);
4190 }
4191
4192 static void
dissect_dcerpc_cn_bind_ack(tvbuff_t * tvb,gint offset,packet_info * pinfo,proto_tree * dcerpc_tree,e_dce_cn_common_hdr_t * hdr)4193 dissect_dcerpc_cn_bind_ack(tvbuff_t *tvb, gint offset, packet_info *pinfo,
4194 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
4195 {
4196 guint16 max_xmit, max_recv;
4197 guint16 sec_addr_len;
4198 guint8 num_results;
4199 guint i;
4200 guint16 result = 0;
4201 guint16 reason = 0;
4202 e_guid_t trans_id;
4203 guint32 trans_ver;
4204 dcerpc_auth_info auth_info;
4205 const char *uuid_name = NULL;
4206 const char *result_str = NULL;
4207
4208 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4209 hf_dcerpc_cn_max_xmit, &max_xmit);
4210
4211 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4212 hf_dcerpc_cn_max_recv, &max_recv);
4213
4214 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4215 hf_dcerpc_cn_assoc_group, NULL);
4216
4217 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4218 hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
4219 if (sec_addr_len != 0) {
4220 proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
4221 sec_addr_len, ENC_ASCII|ENC_NA);
4222 offset += sec_addr_len;
4223 }
4224
4225 if (offset % 4) {
4226 offset += 4 - offset % 4;
4227 }
4228
4229 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4230 hf_dcerpc_cn_num_results, &num_results);
4231
4232 /* padding */
4233 offset += 3;
4234
4235 col_append_fstr(pinfo->cinfo, COL_INFO, ", max_xmit: %u max_recv: %u, %u results:",
4236 max_xmit, max_recv, num_results);
4237
4238 for (i = 0; i < num_results; i++) {
4239 proto_tree *ctx_tree = NULL;
4240 proto_item *ctx_item = NULL;
4241
4242 if (dcerpc_tree) {
4243 ctx_tree = proto_tree_add_subtree_format(dcerpc_tree, tvb, offset, 24, ett_dcerpc_cn_ctx, &ctx_item, "Ctx Item[%u]:", i+1);
4244 }
4245
4246 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree,
4247 hdr->drep, hf_dcerpc_cn_ack_result,
4248 &result);
4249
4250 /* [MS-RPCE] 3.3.1.5.3 check if this Ctx Item is the response to a Bind Time Feature Negotiation request */
4251 if (result == 3) {
4252 proto_tree_add_bitmask(ctx_tree, tvb, offset,
4253 hf_dcerpc_cn_bind_trans_btfn,
4254 ett_dcerpc_cn_bind_trans_btfn,
4255 dcerpc_cn_bind_trans_btfn_fields,
4256 ENC_LITTLE_ENDIAN);
4257 offset += 2;
4258 } else if (result != 0) {
4259 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree,
4260 hdr->drep, hf_dcerpc_cn_ack_reason,
4261 &reason);
4262 } else {
4263 /*
4264 * The reason for rejection isn't meaningful, and often isn't
4265 * set, when the syntax was accepted.
4266 */
4267 offset += 2;
4268 }
4269
4270 result_str = val_to_str(result, p_cont_result_vals, "Unknown result (%u)");
4271
4272 if (ctx_tree) {
4273 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &trans_id);
4274 uuid_name = guids_get_uuid_name(&trans_id, pinfo->pool);
4275 if (! uuid_name) {
4276 uuid_name = guid_to_str(pinfo->pool, (e_guid_t *) &trans_id);
4277 }
4278 proto_tree_add_guid_format(ctx_tree, hf_dcerpc_cn_ack_trans_id, tvb,
4279 offset, 16, (e_guid_t *) &trans_id, "Transfer Syntax: %s",
4280 uuid_name);
4281 proto_item_append_text(ctx_item, " %s, %s", result_str, uuid_name);
4282 }
4283 offset += 16;
4284
4285 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, ctx_tree, hdr->drep,
4286 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
4287
4288 if (i > 0)
4289 col_append_fstr(pinfo->cinfo, COL_INFO, ",");
4290 col_append_fstr(pinfo->cinfo, COL_INFO, " %s", result_str);
4291 }
4292
4293 /*
4294 * XXX - do we need to do anything with the authentication level
4295 * we get back from this?
4296 */
4297 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, &auth_info);
4298 }
4299
4300 static void
dissect_dcerpc_cn_bind_nak(tvbuff_t * tvb,gint offset,packet_info * pinfo,proto_tree * dcerpc_tree,e_dce_cn_common_hdr_t * hdr)4301 dissect_dcerpc_cn_bind_nak(tvbuff_t *tvb, gint offset, packet_info *pinfo,
4302 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
4303 {
4304 guint16 reason;
4305 guint8 num_protocols;
4306 guint i;
4307
4308 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
4309 hdr->drep, hf_dcerpc_cn_reject_reason,
4310 &reason);
4311
4312 col_append_fstr(pinfo->cinfo, COL_INFO, " reason: %s",
4313 val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
4314
4315 if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
4316 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4317 hf_dcerpc_cn_num_protocols,
4318 &num_protocols);
4319
4320 for (i = 0; i < num_protocols; i++) {
4321 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
4322 hdr->drep, hf_dcerpc_cn_protocol_ver_major,
4323 NULL);
4324 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
4325 hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
4326 NULL);
4327 }
4328 }
4329 }
4330
4331 /* Return a string describing a DCE/RPC fragment as first, middle, or end
4332 fragment. */
4333
4334 #define PFC_FRAG_MASK 0x03
4335
4336 static const char *
fragment_type(guint8 flags)4337 fragment_type(guint8 flags)
4338 {
4339 static const char* t[4] = {
4340 "Mid",
4341 "1st",
4342 "Last",
4343 "Single"
4344 };
4345 return t[flags & PFC_FRAG_MASK];
4346 }
4347
4348 /* Dissect stub data (payload) of a DCERPC packet. */
4349
4350 static void
dissect_dcerpc_cn_stub(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * dcerpc_tree,proto_tree * tree,e_dce_cn_common_hdr_t * hdr,dcerpc_info * di,dcerpc_auth_info * auth_info,guint32 alloc_hint _U_,guint32 frame)4351 dissect_dcerpc_cn_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
4352 proto_tree *dcerpc_tree, proto_tree *tree,
4353 e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
4354 dcerpc_auth_info *auth_info, guint32 alloc_hint _U_,
4355 guint32 frame)
4356 {
4357 gint length, reported_length;
4358 gboolean save_fragmented;
4359 fragment_head *fd_head = NULL;
4360
4361 tvbuff_t *header_tvb = NULL, *trailer_tvb = NULL;
4362 tvbuff_t *payload_tvb, *decrypted_tvb = NULL;
4363 proto_item *pi;
4364 proto_item *parent_pi;
4365 proto_item *dcerpc_tree_item;
4366
4367 save_fragmented = pinfo->fragmented;
4368
4369 length = tvb_reported_length_remaining(tvb, offset);
4370 reported_length = tvb_reported_length_remaining(tvb, offset);
4371 if (reported_length < 0 ||
4372 (guint32)reported_length < auth_info->auth_size) {
4373 /* We don't even have enough bytes for the authentication
4374 stuff. */
4375 return;
4376 }
4377 reported_length -= auth_info->auth_size;
4378 if (length > reported_length)
4379 length = reported_length;
4380 header_tvb = tvb_new_subset_length_caplen(tvb, 0, offset, offset);
4381 payload_tvb = tvb_new_subset_length_caplen(tvb, offset, length, reported_length);
4382 trailer_tvb = auth_info->auth_hdr_tvb;
4383
4384 /* Decrypt the PDU if it is encrypted */
4385
4386 if (auth_info->auth_type &&
4387 (auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)) {
4388
4389 /* Start out assuming we won't succeed in decrypting. */
4390
4391 if (auth_info->auth_fns != NULL) {
4392 tvbuff_t *result;
4393
4394 result = decode_encrypted_data(header_tvb, payload_tvb, trailer_tvb,
4395 pinfo, hdr, auth_info);
4396 if (result) {
4397 proto_tree_add_item(dcerpc_tree, hf_dcerpc_encrypted_stub_data, payload_tvb, 0, -1, ENC_NA);
4398
4399 add_new_data_source(
4400 pinfo, result, "Decrypted stub data");
4401
4402 /* We succeeded. */
4403 decrypted_tvb = result;
4404 }
4405 }
4406 } else
4407 decrypted_tvb = payload_tvb;
4408
4409 /* if this packet is not fragmented, just dissect it and exit */
4410 if (PFC_NOT_FRAGMENTED(hdr)) {
4411 pinfo->fragmented = FALSE;
4412
4413 dcerpc_try_handoff(pinfo, tree, dcerpc_tree,
4414 ((decrypted_tvb != NULL) ? decrypted_tvb : payload_tvb),
4415 ((decrypted_tvb != NULL) ? TRUE : FALSE),
4416 hdr->drep, di, auth_info);
4417
4418 pinfo->fragmented = save_fragmented;
4419 return;
4420 }
4421
4422 /* The packet is fragmented. */
4423 pinfo->fragmented = TRUE;
4424
4425 /* debug output of essential fragment data. */
4426 /* leave it here for future debugging sessions */
4427 /*printf("DCE num:%u offset:%u frag_len:%u tvb_len:%u\n",
4428 pinfo->num, offset, hdr->frag_len, tvb_reported_length(decrypted_tvb));*/
4429
4430 /* if we are not doing reassembly and this is the first fragment
4431 then just dissect it and exit
4432 XXX - if we're not doing reassembly, can we decrypt an
4433 encrypted stub?
4434 */
4435 if ( (!dcerpc_reassemble) && (hdr->flags & PFC_FIRST_FRAG) ) {
4436
4437 dcerpc_try_handoff(pinfo, tree, dcerpc_tree,
4438 ((decrypted_tvb != NULL) ? decrypted_tvb : payload_tvb),
4439 ((decrypted_tvb != NULL) ? TRUE : FALSE),
4440 hdr->drep, di, auth_info);
4441
4442 expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment, "%s fragment", fragment_type(hdr->flags));
4443
4444 pinfo->fragmented = save_fragmented;
4445 return;
4446 }
4447
4448 /* if we have already seen this packet, see if it was reassembled
4449 and if so dissect the full pdu.
4450 then exit
4451 */
4452 if (pinfo->fd->visited) {
4453 fd_head = fragment_get_reassembled(&dcerpc_co_reassembly_table, frame);
4454 goto end_cn_stub;
4455 }
4456
4457 /* if we are not doing reassembly and it was neither a complete PDU
4458 nor the first fragment then there is nothing more we can do
4459 so we just have to exit
4460 */
4461 if ( !dcerpc_reassemble || (tvb_captured_length(tvb) != tvb_reported_length(tvb)) )
4462 goto end_cn_stub;
4463
4464 /* if we didn't get 'frame' we don't know where the PDU started and thus
4465 it is pointless to continue
4466 */
4467 if (!frame)
4468 goto end_cn_stub;
4469
4470 /* from now on we must attempt to reassemble the PDU
4471 */
4472
4473 /* if we get here we know it is the first time we see the packet
4474 and we also know it is only a fragment and not a full PDU,
4475 thus we must reassemble it.
4476 */
4477
4478 /* Do we have any non-encrypted data to reassemble? */
4479 if (decrypted_tvb == NULL) {
4480 /* No. We can't even try to reassemble. */
4481 goto end_cn_stub;
4482 }
4483
4484 /* defragmentation is a bit tricky, as there's no offset of the fragment
4485 * in the protocol data.
4486 *
4487 * just use fragment_add_seq_next() and hope that TCP/SMB segments coming
4488 * in with the correct sequence.
4489 */
4490 fd_head = fragment_add_seq_next(&dcerpc_co_reassembly_table,
4491 decrypted_tvb, 0, pinfo, frame, NULL,
4492 tvb_reported_length(decrypted_tvb),
4493 !(hdr->flags & PFC_LAST_FRAG) /* more_frags */);
4494
4495 end_cn_stub:
4496
4497 /* if reassembly is complete and this is the last fragment
4498 * (multiple fragments in one PDU are possible!)
4499 * dissect the full PDU
4500 */
4501 if (fd_head && (fd_head->flags & FD_DEFRAGMENTED) ) {
4502
4503 if ((pinfo->num == fd_head->reassembled_in) && (hdr->flags & PFC_LAST_FRAG) ) {
4504 tvbuff_t *next_tvb;
4505 proto_item *frag_tree_item;
4506
4507 next_tvb = tvb_new_chain((decrypted_tvb)?decrypted_tvb:payload_tvb,
4508 fd_head->tvb_data);
4509
4510 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
4511 show_fragment_tree(fd_head, &dcerpc_frag_items,
4512 tree, pinfo, next_tvb, &frag_tree_item);
4513 /* the toplevel fragment subtree is now behind all desegmented data,
4514 * move it right behind the DCE/RPC tree */
4515 dcerpc_tree_item = proto_tree_get_parent(dcerpc_tree);
4516 if (frag_tree_item && dcerpc_tree_item) {
4517 proto_tree_move_item(tree, dcerpc_tree_item, frag_tree_item);
4518 }
4519
4520 pinfo->fragmented = FALSE;
4521
4522 expert_add_info_format(pinfo, frag_tree_item, &ei_dcerpc_fragment_reassembled, "%s fragment, reassembled", fragment_type(hdr->flags));
4523
4524 dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb, TRUE, hdr->drep, di, auth_info);
4525
4526 } else {
4527 if (decrypted_tvb) {
4528 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
4529 decrypted_tvb, 0, 0, fd_head->reassembled_in);
4530 } else {
4531 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
4532 payload_tvb, 0, 0, fd_head->reassembled_in);
4533 }
4534 proto_item_set_generated(pi);
4535 parent_pi = proto_tree_get_parent(dcerpc_tree);
4536 if (parent_pi != NULL) {
4537 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
4538 }
4539 col_append_fstr(pinfo->cinfo, COL_INFO,
4540 " [DCE/RPC %s fragment, reas: #%u]", fragment_type(hdr->flags), fd_head->reassembled_in);
4541 expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment_reassembled, "%s fragment, reassembled in #%u", fragment_type(hdr->flags), fd_head->reassembled_in);
4542 }
4543 } else {
4544 /* Reassembly not complete - some fragments
4545 are missing. Just show the stub data. */
4546 expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment, "%s fragment", fragment_type(hdr->flags));
4547
4548 if (decrypted_tvb) {
4549 show_stub_data(pinfo, decrypted_tvb, 0, tree, auth_info, FALSE);
4550 } else {
4551 show_stub_data(pinfo, payload_tvb, 0, tree, auth_info, TRUE);
4552 }
4553 }
4554
4555 pinfo->fragmented = save_fragmented;
4556 }
4557
4558 static void
dissect_dcerpc_cn_rqst(tvbuff_t * tvb,gint offset,packet_info * pinfo,proto_tree * dcerpc_tree,proto_tree * tree,e_dce_cn_common_hdr_t * hdr)4559 dissect_dcerpc_cn_rqst(tvbuff_t *tvb, gint offset, packet_info *pinfo,
4560 proto_tree *dcerpc_tree, proto_tree *tree,
4561 e_dce_cn_common_hdr_t *hdr)
4562 {
4563 conversation_t *conv;
4564 guint16 ctx_id;
4565 guint16 opnum;
4566 e_guid_t obj_id = DCERPC_UUID_NULL;
4567 dcerpc_auth_info auth_info;
4568 guint32 alloc_hint;
4569 proto_item *pi;
4570 proto_item *parent_pi;
4571 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
4572
4573 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4574 hf_dcerpc_cn_alloc_hint, &alloc_hint);
4575
4576 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4577 hf_dcerpc_cn_ctx_id, &ctx_id);
4578 parent_pi = proto_tree_get_parent(dcerpc_tree);
4579 if (parent_pi != NULL) {
4580 proto_item_append_text(parent_pi, ", Ctx: %u", ctx_id);
4581 }
4582
4583 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4584 hf_dcerpc_opnum, &opnum);
4585
4586 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
4587 decode_data->dcectxid = ctx_id;
4588
4589 col_append_fstr(pinfo->cinfo, COL_INFO, ", opnum: %u, Ctx: %u",
4590 opnum, ctx_id);
4591
4592 if (hdr->flags & PFC_OBJECT_UUID) {
4593 dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &obj_id);
4594 if (dcerpc_tree) {
4595 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
4596 offset, 16, (e_guid_t *) &obj_id, "Object UUID: %s",
4597 guid_to_str(pinfo->pool, (e_guid_t *) &obj_id));
4598 }
4599 offset += 16;
4600 }
4601
4602 /*
4603 * XXX - what if this was set when the connection was set up,
4604 * and we just have a security context?
4605 */
4606 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, &auth_info);
4607
4608 conv = find_conversation_pinfo(pinfo, 0);
4609 if (!conv)
4610 show_stub_data(pinfo, tvb, offset, dcerpc_tree, &auth_info, TRUE);
4611 else {
4612 dcerpc_matched_key matched_key, *new_matched_key;
4613 dcerpc_call_value *value;
4614
4615 /* !!! we can NOT check visited here since this will interact
4616 badly with when SMB handles (i.e. calls the subdissector)
4617 and desegmented pdu's .
4618 Instead we check if this pdu is already in the matched table or not
4619 */
4620 matched_key.frame = pinfo->num;
4621 matched_key.call_id = hdr->call_id;
4622 value = (dcerpc_call_value *)wmem_map_lookup(dcerpc_matched, &matched_key);
4623 if (!value) {
4624 dcerpc_bind_key bind_key;
4625 dcerpc_bind_value *bind_value;
4626
4627 bind_key.conv = conv;
4628 bind_key.ctx_id = ctx_id;
4629 bind_key.transport_salt = dcerpc_get_transport_salt(pinfo);
4630
4631 if ((bind_value = (dcerpc_bind_value *)wmem_map_lookup(dcerpc_binds, &bind_key)) ) {
4632 if (!(hdr->flags&PFC_FIRST_FRAG)) {
4633 dcerpc_cn_call_key call_key;
4634 dcerpc_call_value *call_value;
4635
4636 call_key.conv = conv;
4637 call_key.call_id = hdr->call_id;
4638 call_key.transport_salt = dcerpc_get_transport_salt(pinfo);
4639 if ((call_value = (dcerpc_call_value *)wmem_map_lookup(dcerpc_cn_calls, &call_key))) {
4640 new_matched_key = wmem_new(wmem_file_scope(), dcerpc_matched_key);
4641 *new_matched_key = matched_key;
4642 wmem_map_insert(dcerpc_matched, new_matched_key, call_value);
4643 value = call_value;
4644 }
4645 } else {
4646 dcerpc_cn_call_key *call_key;
4647 dcerpc_call_value *call_value;
4648
4649 /* We found the binding and it is the first fragment
4650 (or a complete PDU) of a dcerpc pdu so just add
4651 the call to both the call table and the
4652 matched table
4653 */
4654 call_key = wmem_new(wmem_file_scope(), dcerpc_cn_call_key);
4655 call_key->conv = conv;
4656 call_key->call_id = hdr->call_id;
4657 call_key->transport_salt = dcerpc_get_transport_salt(pinfo);
4658
4659 /* if there is already a matching call in the table
4660 remove it so it is replaced with the new one */
4661 if (wmem_map_lookup(dcerpc_cn_calls, call_key)) {
4662 wmem_map_remove(dcerpc_cn_calls, call_key);
4663 }
4664
4665 call_value = wmem_new(wmem_file_scope(), dcerpc_call_value);
4666 call_value->uuid = bind_value->uuid;
4667 call_value->ver = bind_value->ver;
4668 call_value->object_uuid = obj_id;
4669 call_value->opnum = opnum;
4670 call_value->req_frame = pinfo->num;
4671 call_value->req_time = pinfo->abs_ts;
4672 call_value->rep_frame = 0;
4673 call_value->max_ptr = 0;
4674 call_value->se_data = NULL;
4675 call_value->private_data = NULL;
4676 call_value->pol = NULL;
4677 call_value->flags = 0;
4678 if (!memcmp(&bind_value->transport, &uuid_ndr64, sizeof(uuid_ndr64))) {
4679 call_value->flags |= DCERPC_IS_NDR64;
4680 }
4681
4682 wmem_map_insert(dcerpc_cn_calls, call_key, call_value);
4683
4684 new_matched_key = wmem_new(wmem_file_scope(), dcerpc_matched_key);
4685 *new_matched_key = matched_key;
4686 wmem_map_insert(dcerpc_matched, new_matched_key, call_value);
4687 value = call_value;
4688 }
4689 }
4690 }
4691
4692 if (value) {
4693 dcerpc_info *di;
4694
4695 di = wmem_new0(pinfo->pool, dcerpc_info);
4696 /* handoff this call */
4697 di->dcerpc_procedure_name = "";
4698 di->conv = conv;
4699 di->call_id = hdr->call_id;
4700 di->transport_salt = dcerpc_get_transport_salt(pinfo);
4701 di->ptype = PDU_REQ;
4702 di->call_data = value;
4703 di->hf_index = -1;
4704
4705 if (value->rep_frame != 0) {
4706 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
4707 tvb, 0, 0, value->rep_frame);
4708 proto_item_set_generated(pi);
4709 if (parent_pi != NULL) {
4710 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
4711 }
4712 }
4713
4714 dissect_dcerpc_cn_stub(tvb, offset, pinfo, dcerpc_tree, tree,
4715 hdr, di, &auth_info, alloc_hint,
4716 value->req_frame);
4717 } else {
4718 /* no bind information, simply show stub data */
4719 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);
4720 show_stub_data(pinfo, tvb, offset, dcerpc_tree, &auth_info, TRUE);
4721 }
4722 }
4723
4724 /*
4725 * Move the auth_info subtree to the end,
4726 * as it's also at the end of the pdu on the wire.
4727 */
4728 dissect_dcerpc_cn_auth_move(&auth_info, dcerpc_tree);
4729 }
4730
4731 static void
dissect_dcerpc_cn_resp(tvbuff_t * tvb,gint offset,packet_info * pinfo,proto_tree * dcerpc_tree,proto_tree * tree,e_dce_cn_common_hdr_t * hdr)4732 dissect_dcerpc_cn_resp(tvbuff_t *tvb, gint offset, packet_info *pinfo,
4733 proto_tree *dcerpc_tree, proto_tree *tree,
4734 e_dce_cn_common_hdr_t *hdr)
4735 {
4736 dcerpc_call_value *value = NULL;
4737 conversation_t *conv;
4738 guint16 ctx_id;
4739 dcerpc_auth_info auth_info;
4740 guint32 alloc_hint;
4741 proto_item *pi;
4742 proto_item *parent_pi;
4743 e_guid_t obj_id_null = DCERPC_UUID_NULL;
4744 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
4745
4746 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4747 hf_dcerpc_cn_alloc_hint, &alloc_hint);
4748
4749 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4750 hf_dcerpc_cn_ctx_id, &ctx_id);
4751 parent_pi = proto_tree_get_parent(dcerpc_tree);
4752 if (parent_pi != NULL) {
4753 proto_item_append_text(parent_pi, ", Ctx: %u", ctx_id);
4754 }
4755
4756 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
4757 decode_data->dcectxid = ctx_id;
4758
4759 col_append_fstr(pinfo->cinfo, COL_INFO, ", Ctx: %u", ctx_id);
4760
4761 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4762 hf_dcerpc_cn_cancel_count, NULL);
4763 /* padding */
4764 offset++;
4765
4766 /*
4767 * XXX - what if this was set when the connection was set up,
4768 * and we just have a security context?
4769 */
4770 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, &auth_info);
4771
4772 conv = find_conversation_pinfo(pinfo, 0);
4773
4774 if (!conv) {
4775 /* no point in creating one here, really */
4776 show_stub_data(pinfo, tvb, offset, dcerpc_tree, &auth_info, TRUE);
4777 } else {
4778 dcerpc_matched_key matched_key, *new_matched_key;
4779
4780 /* !!! we can NOT check visited here since this will interact
4781 badly with when SMB handles (i.e. calls the subdissector)
4782 and desegmented pdu's .
4783 Instead we check if this pdu is already in the matched table or not
4784 */
4785 matched_key.frame = pinfo->num;
4786 matched_key.call_id = hdr->call_id;
4787 value = (dcerpc_call_value *)wmem_map_lookup(dcerpc_matched, &matched_key);
4788 if (!value) {
4789 dcerpc_cn_call_key call_key;
4790 dcerpc_call_value *call_value;
4791
4792 call_key.conv = conv;
4793 call_key.call_id = hdr->call_id;
4794 call_key.transport_salt = dcerpc_get_transport_salt(pinfo);
4795
4796 if ((call_value = (dcerpc_call_value *)wmem_map_lookup(dcerpc_cn_calls, &call_key))) {
4797 /* extra sanity check, only match them if the reply
4798 came after the request */
4799 if (call_value->req_frame<pinfo->num) {
4800 new_matched_key = wmem_new(wmem_file_scope(), dcerpc_matched_key);
4801 *new_matched_key = matched_key;
4802 wmem_map_insert(dcerpc_matched, new_matched_key, call_value);
4803 value = call_value;
4804 if (call_value->rep_frame == 0) {
4805 call_value->rep_frame = pinfo->num;
4806 }
4807 }
4808 }
4809 }
4810
4811 if (value) {
4812 dcerpc_info *di;
4813
4814 di = wmem_new0(pinfo->pool, dcerpc_info);
4815 /* handoff this call */
4816 di->dcerpc_procedure_name = "";
4817 di->conv = conv;
4818 di->call_id = hdr->call_id;
4819 di->transport_salt = dcerpc_get_transport_salt(pinfo);
4820 di->ptype = PDU_RESP;
4821 di->call_data = value;
4822
4823 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
4824 proto_item_set_generated(pi);
4825
4826 /* (optional) "Object UUID" from request */
4827 if (dcerpc_tree && (memcmp(&value->object_uuid, &obj_id_null, sizeof(obj_id_null)) != 0)) {
4828 pi = proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
4829 offset, 0, (e_guid_t *) &value->object_uuid, "Object UUID: %s",
4830 guid_to_str(pinfo->pool, (e_guid_t *) &value->object_uuid));
4831 proto_item_set_generated(pi);
4832 }
4833
4834 /* request in */
4835 if (value->req_frame != 0) {
4836 nstime_t delta_ts;
4837 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4838 tvb, 0, 0, value->req_frame);
4839 proto_item_set_generated(pi);
4840 if (parent_pi != NULL) {
4841 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
4842 }
4843 nstime_delta(&delta_ts, &pinfo->abs_ts, &value->req_time);
4844 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
4845 proto_item_set_generated(pi);
4846 } else {
4847 proto_tree_add_expert(dcerpc_tree, pinfo, &ei_dcerpc_no_request_found, tvb, 0, 0);
4848 }
4849
4850 dissect_dcerpc_cn_stub(tvb, offset, pinfo, dcerpc_tree, tree,
4851 hdr, di, &auth_info, alloc_hint,
4852 value->rep_frame);
4853 } else {
4854 /* no bind information, simply show stub data */
4855 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);
4856 show_stub_data(pinfo, tvb, offset, dcerpc_tree, &auth_info, TRUE);
4857 }
4858 }
4859
4860 /*
4861 * Move the auth_info subtree to the end,
4862 * as it's also at the end of the pdu on the wire.
4863 */
4864 dissect_dcerpc_cn_auth_move(&auth_info, dcerpc_tree);
4865 }
4866
4867 static void
dissect_dcerpc_cn_fault(tvbuff_t * tvb,gint offset,packet_info * pinfo,proto_tree * dcerpc_tree,e_dce_cn_common_hdr_t * hdr)4868 dissect_dcerpc_cn_fault(tvbuff_t *tvb, gint offset, packet_info *pinfo,
4869 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
4870 {
4871 dcerpc_call_value *value = NULL;
4872 conversation_t *conv;
4873 guint16 ctx_id;
4874 guint32 status;
4875 guint32 alloc_hint;
4876 dcerpc_auth_info auth_info;
4877 gint length, reported_length;
4878 tvbuff_t *stub_tvb = NULL;
4879 proto_item *pi = NULL;
4880 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
4881
4882 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4883 hf_dcerpc_cn_alloc_hint, &alloc_hint);
4884
4885 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4886 hf_dcerpc_cn_ctx_id, &ctx_id);
4887
4888 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4889 hf_dcerpc_cn_cancel_count, NULL);
4890 proto_tree_add_bitmask(dcerpc_tree, tvb, offset,
4891 hf_dcerpc_cn_fault_flags,
4892 ett_dcerpc_fault_flags,
4893 dcerpc_cn_fault_flags_fields,
4894 DREP_ENC_INTEGER(hdr->drep));
4895 offset += 1;
4896
4897 #if 0
4898 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
4899 hf_dcerpc_cn_status, &status);
4900 #endif
4901 status = ((hdr->drep[0] & DREP_LITTLE_ENDIAN)
4902 ? tvb_get_letohl(tvb, offset)
4903 : tvb_get_ntohl(tvb, offset));
4904
4905 pi = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_status, tvb, offset, 4, DREP_ENC_INTEGER(hdr->drep));
4906 offset+=4;
4907
4908 expert_add_info_format(pinfo, pi, &ei_dcerpc_cn_status, "Fault: %s", val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
4909
4910 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
4911 decode_data->dcectxid = ctx_id;
4912
4913 col_append_fstr(pinfo->cinfo, COL_INFO,
4914 ", Ctx: %u, status: %s", ctx_id,
4915 val_to_str(status, reject_status_vals,
4916 "Unknown (0x%08x)"));
4917
4918 /* padding */
4919 proto_tree_add_item(dcerpc_tree, hf_dcerpc_reserved, tvb, offset, 4, ENC_NA);
4920 offset += 4;
4921
4922 /*
4923 * XXX - what if this was set when the connection was set up,
4924 * and we just have a security context?
4925 */
4926 dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, &auth_info);
4927
4928 length = tvb_captured_length_remaining(tvb, offset);
4929 reported_length = tvb_reported_length_remaining(tvb, offset);
4930 if (reported_length < 0 ||
4931 (guint32)reported_length < auth_info.auth_size) {
4932 /* We don't even have enough bytes for the authentication
4933 stuff. */
4934 return;
4935 }
4936 reported_length -= auth_info.auth_size;
4937 if (length > reported_length)
4938 length = reported_length;
4939 stub_tvb = tvb_new_subset_length_caplen(tvb, offset, length, reported_length);
4940
4941 conv = find_conversation_pinfo(pinfo, 0);
4942 if (!conv) {
4943 /* no point in creating one here, really */
4944 } else {
4945 dcerpc_matched_key matched_key, *new_matched_key;
4946
4947 /* !!! we can NOT check visited here since this will interact
4948 badly with when SMB handles (i.e. calls the subdissector)
4949 and desegmented pdu's .
4950 Instead we check if this pdu is already in the matched table or not
4951 */
4952 matched_key.frame = pinfo->num;
4953 matched_key.call_id = hdr->call_id;
4954 value = (dcerpc_call_value *)wmem_map_lookup(dcerpc_matched, &matched_key);
4955 if (!value) {
4956 dcerpc_cn_call_key call_key;
4957 dcerpc_call_value *call_value;
4958
4959 call_key.conv = conv;
4960 call_key.call_id = hdr->call_id;
4961 call_key.transport_salt = dcerpc_get_transport_salt(pinfo);
4962
4963 if ((call_value = (dcerpc_call_value *)wmem_map_lookup(dcerpc_cn_calls, &call_key))) {
4964 new_matched_key = wmem_new(wmem_file_scope(), dcerpc_matched_key);
4965 *new_matched_key = matched_key;
4966 wmem_map_insert(dcerpc_matched, new_matched_key, call_value);
4967
4968 value = call_value;
4969 if (call_value->rep_frame == 0) {
4970 call_value->rep_frame = pinfo->num;
4971 }
4972
4973 }
4974 }
4975
4976 if (value) {
4977 proto_tree *stub_tree = NULL;
4978 gint stub_length;
4979 dcerpc_info *di;
4980 proto_item *parent_pi;
4981
4982 di = wmem_new0(pinfo->pool, dcerpc_info);
4983 /* handoff this call */
4984 di->dcerpc_procedure_name = "";
4985 di->conv = conv;
4986 di->call_id = hdr->call_id;
4987 di->transport_salt = dcerpc_get_transport_salt(pinfo);
4988 di->ptype = PDU_FAULT;
4989 di->call_data = value;
4990
4991 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
4992 proto_item_set_generated(pi);
4993 if (value->req_frame != 0) {
4994 nstime_t delta_ts;
4995 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4996 tvb, 0, 0, value->req_frame);
4997 proto_item_set_generated(pi);
4998 parent_pi = proto_tree_get_parent(dcerpc_tree);
4999 if (parent_pi != NULL) {
5000 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
5001 }
5002 nstime_delta(&delta_ts, &pinfo->abs_ts, &value->req_time);
5003 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
5004 proto_item_set_generated(pi);
5005 } else {
5006 proto_tree_add_expert(dcerpc_tree, pinfo, &ei_dcerpc_no_request_found, tvb, 0, 0);
5007 }
5008
5009 length = tvb_reported_length_remaining(stub_tvb, 0);
5010 /* as we now create a tvb in dissect_dcerpc_cn() containing only the
5011 * stub_data, the following calculation is no longer valid:
5012 * stub_length = hdr->frag_len - offset - auth_info.auth_size;
5013 * simply use the remaining length of the tvb instead.
5014 * XXX - or better use the reported_length?!?
5015 */
5016 stub_length = length;
5017
5018 stub_tree = proto_tree_add_subtree_format(dcerpc_tree,
5019 stub_tvb, 0, stub_length,
5020 ett_dcerpc_fault_stub_data, NULL,
5021 "Fault stub data (%d byte%s)", stub_length,
5022 plurality(stub_length, "", "s"));
5023
5024 /* If we don't have reassembly enabled, or this packet contains
5025 the entire PDU, or if we don't have all the data in this
5026 fragment, just call the handoff directly if this is the
5027 first fragment or the PDU isn't fragmented. */
5028 if ( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
5029 !tvb_bytes_exist(stub_tvb, 0, stub_length) ) {
5030 if (hdr->flags&PFC_FIRST_FRAG) {
5031 /* First fragment, possibly the only fragment */
5032 /*
5033 * XXX - should there be a third routine for each
5034 * function in an RPC subdissector, to handle
5035 * fault responses? The DCE RPC 1.1 spec says
5036 * three's "stub data" here, which I infer means
5037 * that it's protocol-specific and call-specific.
5038 *
5039 * It should probably get passed the status code
5040 * as well, as that might be protocol-specific.
5041 */
5042 if (stub_length > 0) {
5043 proto_tree_add_item(stub_tree, hf_dcerpc_fault_stub_data, stub_tvb, 0, stub_length, ENC_NA);
5044 }
5045 } else {
5046 /* PDU is fragmented and this isn't the first fragment */
5047 if (stub_length > 0) {
5048 proto_tree_add_item(stub_tree, hf_dcerpc_fragment_data, stub_tvb, 0, stub_length, ENC_NA);
5049 }
5050 }
5051 } else {
5052 /* Reassembly is enabled, the PDU is fragmented, and
5053 we have all the data in the fragment; the first two
5054 of those mean we should attempt reassembly, and the
5055 third means we can attempt reassembly. */
5056 if (dcerpc_tree) {
5057 if (length > 0) {
5058 proto_tree_add_item(stub_tree, hf_dcerpc_fragment_data, stub_tvb, 0, stub_length, ENC_NA);
5059 }
5060 }
5061 if (hdr->flags&PFC_FIRST_FRAG) { /* FIRST fragment */
5062 if ( (!pinfo->fd->visited) && value->rep_frame ) {
5063 fragment_add_seq_next(&dcerpc_co_reassembly_table,
5064 stub_tvb, 0,
5065 pinfo, value->rep_frame, NULL,
5066 stub_length,
5067 TRUE);
5068 }
5069 } else if (hdr->flags&PFC_LAST_FRAG) { /* LAST fragment */
5070 if ( value->rep_frame ) {
5071 fragment_head *fd_head;
5072
5073 fd_head = fragment_add_seq_next(&dcerpc_co_reassembly_table,
5074 stub_tvb, 0,
5075 pinfo, value->rep_frame, NULL,
5076 stub_length,
5077 TRUE);
5078
5079 if (fd_head) {
5080 /* We completed reassembly */
5081 tvbuff_t *next_tvb;
5082 proto_item *frag_tree_item;
5083
5084 next_tvb = tvb_new_chain(stub_tvb, fd_head->tvb_data);
5085 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
5086 show_fragment_tree(fd_head, &dcerpc_frag_items,
5087 dcerpc_tree, pinfo, next_tvb, &frag_tree_item);
5088
5089 /*
5090 * XXX - should there be a third routine for each
5091 * function in an RPC subdissector, to handle
5092 * fault responses? The DCE RPC 1.1 spec says
5093 * three's "stub data" here, which I infer means
5094 * that it's protocol-specific and call-specific.
5095 *
5096 * It should probably get passed the status code
5097 * as well, as that might be protocol-specific.
5098 */
5099 if (dcerpc_tree) {
5100 if (length > 0) {
5101 proto_tree_add_item(dcerpc_tree, hf_dcerpc_stub_data, stub_tvb, 0, stub_length, ENC_NA);
5102 }
5103 }
5104 }
5105 }
5106 } else { /* MIDDLE fragment(s) */
5107 if ( (!pinfo->fd->visited) && value->rep_frame ) {
5108 fragment_add_seq_next(&dcerpc_co_reassembly_table,
5109 stub_tvb, 0,
5110 pinfo, value->rep_frame, NULL,
5111 stub_length,
5112 TRUE);
5113 }
5114 }
5115 }
5116 }
5117 }
5118
5119 /*
5120 * Move the auth_info subtree to the end,
5121 * as it's also at the end of the pdu on the wire.
5122 */
5123 dissect_dcerpc_cn_auth_move(&auth_info, dcerpc_tree);
5124 }
5125
5126 static void
dissect_dcerpc_cn_rts(tvbuff_t * tvb,gint offset,packet_info * pinfo,proto_tree * dcerpc_tree,e_dce_cn_common_hdr_t * hdr)5127 dissect_dcerpc_cn_rts(tvbuff_t *tvb, gint offset, packet_info *pinfo,
5128 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
5129 {
5130 proto_item *tf = NULL;
5131 proto_item *parent_pi = NULL;
5132 proto_tree *cn_rts_pdu_tree = NULL;
5133 guint16 rts_flags;
5134 guint16 commands_nb = 0;
5135 guint32 *cmd;
5136 guint32 i;
5137 const char *info_str = NULL;
5138 static int * const flags[] = {
5139 &hf_dcerpc_cn_rts_flags_ping,
5140 &hf_dcerpc_cn_rts_flags_other_cmd,
5141 &hf_dcerpc_cn_rts_flags_recycle_channel,
5142 &hf_dcerpc_cn_rts_flags_in_channel,
5143 &hf_dcerpc_cn_rts_flags_out_channel,
5144 &hf_dcerpc_cn_rts_flags_eof,
5145 NULL
5146 };
5147
5148 /* Dissect specific RTS header */
5149 rts_flags = dcerpc_tvb_get_ntohs(tvb, offset, hdr->drep);
5150 proto_tree_add_bitmask_value_with_flags(dcerpc_tree, tvb, offset, hf_dcerpc_cn_rts_flags,
5151 ett_dcerpc_cn_rts_flags, flags, rts_flags, BMT_NO_APPEND);
5152 offset += 2;
5153
5154 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
5155 hf_dcerpc_cn_rts_commands_nb, &commands_nb);
5156
5157 /* Create the RTS PDU tree - we do not yet know its name */
5158 cn_rts_pdu_tree = proto_tree_add_subtree_format(dcerpc_tree, tvb, offset, -1, ett_dcerpc_cn_rts_pdu, &tf, "RTS PDU: %u commands", commands_nb);
5159
5160 cmd = (guint32 *)wmem_alloc(pinfo->pool, sizeof (guint32) * (commands_nb + 1));
5161
5162 /* Dissect commands */
5163 for (i = 0; i < commands_nb; ++i) {
5164 proto_tree *cn_rts_command_tree = NULL;
5165 const guint32 command = dcerpc_tvb_get_ntohl(tvb, offset, hdr->drep);
5166 cmd[i] = command;
5167 tf = proto_tree_add_uint(cn_rts_pdu_tree, hf_dcerpc_cn_rts_command, tvb, offset, 4, command);
5168 cn_rts_command_tree = proto_item_add_subtree(tf, ett_dcerpc_cn_rts_command);
5169 offset += 4;
5170 switch (command) {
5171 case RTS_CMD_RECEIVEWINDOWSIZE:
5172 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_receivewindowsize, NULL);
5173 break;
5174 case RTS_CMD_FLOWCONTROLACK:
5175 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_fack_bytesreceived, NULL);
5176 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_fack_availablewindow, NULL);
5177 offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_fack_channelcookie, NULL);
5178 break;
5179 case RTS_CMD_CONNECTIONTIMEOUT:
5180 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_connectiontimeout, NULL);
5181 break;
5182 case RTS_CMD_COOKIE:
5183 offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_cookie, NULL);
5184 break;
5185 case RTS_CMD_CHANNELLIFETIME:
5186 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_channellifetime, NULL);
5187 break;
5188 case RTS_CMD_CLIENTKEEPALIVE:
5189 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_clientkeepalive, NULL);
5190 break;
5191 case RTS_CMD_VERSION:
5192 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_version, NULL);
5193 break;
5194 case RTS_CMD_EMPTY:
5195 break;
5196 case RTS_CMD_PADDING: {
5197 guint8 *padding;
5198 const guint32 conformance_count = dcerpc_tvb_get_ntohl(tvb, offset, hdr->drep);
5199 proto_tree_add_uint(cn_rts_command_tree, hf_dcerpc_cn_rts_command_conformancecount, tvb, offset, 4, conformance_count);
5200 offset += 4;
5201 padding = (guint8 *)tvb_memdup(pinfo->pool, tvb, offset, conformance_count);
5202 proto_tree_add_bytes(cn_rts_command_tree, hf_dcerpc_cn_rts_command_padding, tvb, offset, conformance_count, padding);
5203 offset += conformance_count;
5204 } break;
5205 case RTS_CMD_NEGATIVEANCE:
5206 break;
5207 case RTS_CMD_ANCE:
5208 break;
5209 case RTS_CMD_CLIENTADDRESS: {
5210 guint8 *padding;
5211 const guint32 addrtype = dcerpc_tvb_get_ntohl(tvb, offset, hdr->drep);
5212 proto_tree_add_uint(cn_rts_command_tree, hf_dcerpc_cn_rts_command_addrtype, tvb, offset, 4, addrtype);
5213 offset += 4;
5214 switch (addrtype) {
5215 case RTS_IPV4: {
5216 const guint32 addr4 = tvb_get_ipv4(tvb, offset);
5217 proto_tree_add_ipv4_format_value(cn_rts_command_tree, hf_dcerpc_cmd_client_ipv4, tvb, offset, 4, addr4, "%s", get_hostname(addr4));
5218 offset += 4;
5219 } break;
5220 case RTS_IPV6: {
5221 ws_in6_addr addr6;
5222 tvb_get_ipv6(tvb, offset, &addr6);
5223 proto_tree_add_ipv6_format_value(cn_rts_command_tree, hf_dcerpc_cmd_client_ipv6, tvb, offset, 16, &addr6, "%s", get_hostname6(&addr6));
5224 offset += 16;
5225 } break;
5226 }
5227 padding = (guint8 *)tvb_memdup(pinfo->pool, tvb, offset, 12);
5228 proto_tree_add_bytes(cn_rts_command_tree, hf_dcerpc_cn_rts_command_padding, tvb, offset, 12, padding);
5229 offset += 12;
5230 } break;
5231 case RTS_CMD_ASSOCIATIONGROUPID:
5232 offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_associationgroupid, NULL);
5233 break;
5234 case RTS_CMD_DESTINATION:
5235 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_forwarddestination, NULL);
5236 break;
5237 case RTS_CMD_PINGTRAFFICSENTNOTIFY:
5238 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_pingtrafficsentnotify, NULL);
5239 break;
5240 default:
5241 expert_add_info(pinfo, tf, &ei_dcerpc_cn_rts_command);
5242 break;
5243 }
5244 }
5245
5246 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RPCH");
5247
5248 /* Define which PDU Body we are dealing with */
5249 info_str = "unknown RTS PDU";
5250
5251 switch (rts_flags) {
5252 case RTS_FLAG_NONE:
5253 switch (commands_nb) {
5254 case 1:
5255 if (cmd[0] == 0x2) {
5256 info_str = "CONN/A3";
5257 } else if (cmd[0] == 0x3) {
5258 info_str = "IN_R1/A5,IN_R1/A6,IN_R2/A2,IN_R2/A5,OUT_R2/A4";
5259 } else if (cmd[0] == 0x7) {
5260 info_str = "IN_R1/B1";
5261 } else if (cmd[0] == 0x0) {
5262 info_str = "IN_R1/B2";
5263 } else if (cmd[0] == 0xD) {
5264 info_str = "IN_R2/A3,IN_R2/A4";
5265 } else if (cmd[0] == 0xA) {
5266 info_str = "OUT_R1/A9,OUT_R1/A10,OUT_R1/A11,OUT_R2/B1,OUT_R2/B2";
5267 }
5268 break;
5269 case 2:
5270 if ((cmd[0] == 0x0) && (cmd[1] == 0x6)) {
5271 info_str = "CONN/B3";
5272 } else if ((cmd[0] == 0xD) && (cmd[1] == 0xA)) {
5273 info_str = "OUT_R2/A5,OUT_R2/A6";
5274 }
5275 break;
5276 case 3:
5277 if ((cmd[0] == 0x6) && (cmd[1] == 0x0) && (cmd[2] == 0x2)) {
5278 info_str = "CONN/C1,CONN/C2";
5279 }
5280 break;
5281 case 4:
5282 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x0)) {
5283 info_str = "CONN/A1";
5284 } else if ((cmd[0] == 0xD) && (cmd[1] == 0x6) && (cmd[2] == 0x0) && (cmd[3] == 0x2)) {
5285 info_str = "IN_R1/A3,IN_R1/A4";
5286 }
5287 break;
5288 case 6:
5289 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x4) && (cmd[4] == 0x5) && (cmd[5] == 0xC)) {
5290 info_str = "CONN/B1";
5291 }
5292 break;
5293 default:
5294 break;
5295 }
5296 break;
5297 case RTS_FLAG_PING:
5298 switch (commands_nb) {
5299 case 0:
5300 info_str = "Ping";
5301 break;
5302 case 1:
5303 if ((cmd[0] == 0x7) || (cmd[0] == 0x8)) {
5304 info_str = "OUT_R2/C1";
5305 }
5306 break;
5307 default:
5308 break;
5309 }
5310 break;
5311 case RTS_FLAG_OTHER_CMD:
5312 switch (commands_nb) {
5313 case 1:
5314 if (cmd[0] == 0x5) {
5315 info_str = "Keep-Alive";
5316 } else if (cmd[0] == 0xE) {
5317 info_str = "PingTrafficSentNotify";
5318 } else if (cmd[0] == 0x1) {
5319 info_str = "FlowControlAck";
5320 }
5321 break;
5322 case 2:
5323 if ((cmd[0] == 0xD) && (cmd[1] == 0x1)) {
5324 info_str = "FlowControlAckWithDestination";
5325 }
5326 break;
5327 default:
5328 break;
5329 }
5330 break;
5331 case RTS_FLAG_RECYCLE_CHANNEL:
5332 switch (commands_nb) {
5333 case 1:
5334 if (cmd[0] == 0xD) {
5335 info_str = "OUT_R1/A1,OUT_R1/A2,OUT_R2/A1,OUT_R2/A2";
5336 }
5337 break;
5338 case 4:
5339 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3)) {
5340 info_str = "IN_R1/A1,IN_R2/A1";
5341 }
5342 break;
5343 case 5:
5344 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3) && (cmd[4] == 0x0)) {
5345 info_str = "OUT_R1/A3,OUT_R2/A3";
5346 }
5347 break;
5348 default:
5349 break;
5350 }
5351 break;
5352 case RTS_FLAG_IN_CHANNEL|RTS_FLAG_RECYCLE_CHANNEL:
5353 switch (commands_nb) {
5354 case 6:
5355 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3) && (cmd[4] == 0x0) && (cmd[5] == 0x2)) {
5356 info_str = "IN_R1/A2";
5357 }
5358 break;
5359 default:
5360 break;
5361 }
5362 break;
5363 case RTS_FLAG_IN_CHANNEL:
5364 switch (commands_nb) {
5365 case 7:
5366 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x0) && (cmd[4] == 0x2) && (cmd[5] == 0xC) && (cmd[6] == 0xB)) {
5367 info_str = "CONN/B2";
5368 }
5369 break;
5370 default:
5371 break;
5372 }
5373 break;
5374 case RTS_FLAG_OUT_CHANNEL|RTS_FLAG_RECYCLE_CHANNEL:
5375 switch (commands_nb) {
5376 case 7:
5377 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x3) && (cmd[4] == 0x4) && (cmd[5] == 0) && (cmd[6] == 0x2)) {
5378 info_str = "OUT_R1/A4";
5379 }
5380 break;
5381 default:
5382 break;
5383 }
5384 break;
5385 case RTS_FLAG_OUT_CHANNEL:
5386 switch (commands_nb) {
5387 case 2:
5388 if ((cmd[0] == 0xD) && (cmd[1] == 0x3)) {
5389 info_str = "OUT_R1/A7,OUT_R1/A8,OUT_R2/A8";
5390 }
5391 break;
5392 case 3:
5393 if ((cmd[0] == 0xD) && (cmd[1] == 0x6) && (cmd[2] == 0x2)) {
5394 info_str = "OUT_R1/A5,OUT_R1/A6";
5395 } else if ((cmd[0] == 0xD) && (cmd[1] == 0x3) && (cmd[2] == 0x6)) {
5396 info_str = "OUT_R2/A7";
5397 }
5398 break;
5399 case 5:
5400 if ((cmd[0] == 0x6) && (cmd[1] == 0x3) && (cmd[2] == 0x3) && (cmd[3] == 0x4) && (cmd[4] == 0x0)) {
5401 info_str = "CONN/A2";
5402 }
5403 break;
5404 default:
5405 break;
5406 }
5407 break;
5408 case RTS_FLAG_EOF:
5409 switch (commands_nb) {
5410 case 1:
5411 if (cmd[0] == 0xA) {
5412 info_str = "OUT_R2/B3";
5413 }
5414 break;
5415 default:
5416 break;
5417 }
5418 break;
5419 case RTS_FLAG_ECHO:
5420 switch (commands_nb) {
5421 case 0:
5422 info_str = "Echo";
5423 break;
5424 default:
5425 break;
5426 }
5427 break;
5428 default:
5429 break;
5430 }
5431
5432 col_add_fstr(pinfo->cinfo, COL_INFO, "%s, ", info_str);
5433 col_set_fence(pinfo->cinfo,COL_INFO);
5434
5435 parent_pi = proto_tree_get_parent(dcerpc_tree);
5436 if (parent_pi != NULL) {
5437 proto_item_append_text(parent_pi, ", %s", info_str);
5438 }
5439 }
5440
5441 static gboolean
is_dcerpc(tvbuff_t * tvb,int offset,packet_info * pinfo _U_)5442 is_dcerpc(tvbuff_t *tvb, int offset, packet_info *pinfo _U_)
5443 {
5444 guint8 rpc_ver;
5445 guint8 rpc_ver_minor;
5446 guint8 ptype;
5447 guint8 drep[4];
5448
5449 if (!tvb_bytes_exist(tvb, offset, sizeof(e_dce_cn_common_hdr_t)))
5450 return FALSE; /* not enough information to check */
5451
5452 rpc_ver = tvb_get_guint8(tvb, offset++);
5453 if (rpc_ver != 5)
5454 return FALSE;
5455 rpc_ver_minor = tvb_get_guint8(tvb, offset++);
5456 if ((rpc_ver_minor != 0) && (rpc_ver_minor != 1))
5457 return FALSE;
5458 ptype = tvb_get_guint8(tvb, offset++);
5459 if (ptype > PDU_RTS)
5460 return FALSE;
5461 /* Skip flags, nothing good to check */
5462 offset++;
5463
5464 tvb_memcpy(tvb, (guint8 *)drep, offset, sizeof (drep));
5465 if (drep[0]&0xee)
5466 return FALSE;
5467 if (drep[1] > DCE_RPC_DREP_FP_IBM)
5468 return FALSE;
5469
5470 return TRUE;
5471 }
5472
5473 /*
5474 * DCERPC dissector for connection oriented calls.
5475 */
5476 static gboolean
dissect_dcerpc_cn(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * tree,gboolean can_desegment,int * pkt_len)5477 dissect_dcerpc_cn(tvbuff_t *tvb, int offset, packet_info *pinfo,
5478 proto_tree *tree, gboolean can_desegment, int *pkt_len)
5479 {
5480 static const guint8 nulls[4] = { 0 };
5481 int start_offset;
5482 int padding = 0;
5483 int subtvb_len = 0;
5484 proto_item *ti = NULL;
5485 proto_item *tf = NULL;
5486 proto_tree *dcerpc_tree = NULL;
5487 e_dce_cn_common_hdr_t hdr;
5488 dcerpc_auth_info auth_info;
5489 tvbuff_t *fragment_tvb;
5490 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
5491 static int * const hdr_flags[] = {
5492 &hf_dcerpc_cn_flags_object,
5493 &hf_dcerpc_cn_flags_maybe,
5494 &hf_dcerpc_cn_flags_dne,
5495 &hf_dcerpc_cn_flags_mpx,
5496 &hf_dcerpc_cn_flags_reserved,
5497 &hf_dcerpc_cn_flags_cancel_pending,
5498 &hf_dcerpc_cn_flags_last_frag,
5499 &hf_dcerpc_cn_flags_first_frag,
5500 NULL
5501 };
5502
5503 /*
5504 * when done over nbt, dcerpc requests are padded with 4 bytes of null
5505 * data for some reason.
5506 *
5507 * XXX - if that's always the case, the right way to do this would
5508 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
5509 * the 4 bytes of null padding, and make that the dissector
5510 * used for "netbios".
5511 */
5512 if (tvb_memeql(tvb, offset, nulls, 4) == 0) {
5513
5514 /*
5515 * Skip the padding.
5516 */
5517 offset += 4;
5518 padding += 4;
5519 }
5520 /*
5521 * Check if this looks like a C/O DCERPC call
5522 */
5523 if (!is_dcerpc(tvb, offset, pinfo))
5524 return FALSE;
5525
5526 start_offset = offset;
5527 hdr.rpc_ver = tvb_get_guint8(tvb, offset++);
5528 hdr.rpc_ver_minor = tvb_get_guint8(tvb, offset++);
5529 hdr.ptype = tvb_get_guint8(tvb, offset++);
5530
5531 hdr.flags = tvb_get_guint8(tvb, offset++);
5532 tvb_memcpy(tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
5533 offset += (int)sizeof (hdr.drep);
5534
5535 hdr.frag_len = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5536 offset += 2;
5537 hdr.auth_len = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
5538 offset += 2;
5539 hdr.call_id = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
5540 /*offset += 4;*/
5541
5542 if (decode_data->dcectxid == 0) {
5543 col_append_fstr(pinfo->cinfo, COL_DCE_CALL, "%u", hdr.call_id);
5544 } else {
5545 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
5546 * prepend a delimiter */
5547 col_append_fstr(pinfo->cinfo, COL_DCE_CALL, "#%u", hdr.call_id);
5548 }
5549
5550 if (can_desegment && pinfo->can_desegment
5551 && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
5552 pinfo->desegment_offset = start_offset;
5553 pinfo->desegment_len = hdr.frag_len - tvb_reported_length_remaining(tvb, start_offset);
5554 *pkt_len = 0; /* desegmentation required */
5555 return TRUE;
5556 }
5557
5558 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCERPC");
5559
5560 if (decode_data->dcectxid != 0) {
5561 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
5562 * append a delimiter and set a column fence */
5563 col_append_str(pinfo->cinfo, COL_INFO, " # ");
5564 col_set_fence(pinfo->cinfo,COL_INFO);
5565 }
5566 col_add_fstr(pinfo->cinfo, COL_INFO, "%s: call_id: %u",
5567 pckt_vals[hdr.ptype].strptr, hdr.call_id);
5568
5569 if (decode_data->dcectxid != 0) {
5570 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU */
5571 expert_add_info(pinfo, NULL, &ei_dcerpc_fragment_multiple);
5572 }
5573
5574 offset = start_offset;
5575 tvb_ensure_bytes_exist(tvb, offset, 16);
5576 if (tree) {
5577 ti = proto_tree_add_item(tree, proto_dcerpc, tvb, offset, hdr.frag_len, ENC_NA);
5578 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
5579 }
5580
5581 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
5582 offset++;
5583
5584 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset, 1, hdr.rpc_ver_minor);
5585 offset++;
5586
5587 tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
5588 offset++;
5589
5590 #if 0 /* XXX - too much "output noise", removed for now */
5591 if (hdr.ptype == PDU_BIND || hdr.ptype == PDU_ALTER ||
5592 hdr.ptype == PDU_BIND_ACK || hdr.ptype == PDU_ALTER_ACK)
5593 expert_add_info_format(pinfo, tf, &ei_dcerpc_context_change, "Context change: %s", val_to_str(hdr.ptype, pckt_vals, "(0x%x)"));
5594 #endif
5595 if (hdr.ptype == PDU_BIND_NAK)
5596 expert_add_info(pinfo, tf, &ei_dcerpc_bind_not_acknowledged);
5597
5598 if (tree) {
5599 proto_item_append_text(ti, " %s, Fragment: %s",
5600 val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"),
5601 fragment_type(hdr.flags));
5602 }
5603
5604 proto_tree_add_bitmask_value_with_flags(dcerpc_tree, tvb, offset, hf_dcerpc_cn_flags,
5605 ett_dcerpc_cn_flags, hdr_flags, hdr.flags, BMT_NO_APPEND);
5606 offset++;
5607
5608 col_append_fstr(pinfo->cinfo, COL_INFO, ", Fragment: %s", fragment_type(hdr.flags));
5609
5610 proto_tree_add_dcerpc_drep(dcerpc_tree, tvb, offset, hdr.drep, (int)sizeof (hdr.drep));
5611 offset += (int)sizeof (hdr.drep);
5612
5613 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
5614 offset += 2;
5615
5616 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
5617 offset += 2;
5618
5619 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
5620 offset += 4;
5621
5622 if (ti) {
5623 proto_item_append_text(ti, ", FragLen: %u, Call: %u", hdr.frag_len, hdr.call_id);
5624 }
5625
5626 /*
5627 * None of the stuff done above should throw an exception, because
5628 * we would have rejected this as "not DCE RPC" if we didn't have all
5629 * of it. (XXX - perhaps we should request reassembly if we have
5630 * enough of the header to consider it DCE RPC but not enough to
5631 * get the fragment length; in that case the stuff still wouldn't
5632 * throw an exception.)
5633 *
5634 * The rest of the stuff might, so return the PDU length to our caller.
5635 * XXX - should we construct a tvbuff containing only the PDU and
5636 * use that? Or should we have separate "is this a DCE RPC PDU",
5637 * "how long is it", and "dissect it" routines - which might let us
5638 * do most of the work in "tcp_dissect_pdus()"?
5639 */
5640 if (pkt_len != NULL)
5641 *pkt_len = hdr.frag_len + padding;
5642
5643 /* The remaining bytes in the current tvb might contain multiple
5644 * DCE/RPC fragments, so create a new tvb subset for this fragment.
5645 * Only limit the end of the fragment, but not the offset start,
5646 * as the authentication function dissect_dcerpc_cn_auth() will fail
5647 * (and other functions might fail as well) computing the right start
5648 * offset otherwise.
5649 */
5650 subtvb_len = MIN(hdr.frag_len, tvb_reported_length(tvb));
5651 fragment_tvb = tvb_new_subset_length_caplen(tvb, start_offset,
5652 subtvb_len /* length */,
5653 hdr.frag_len /* reported_length */);
5654
5655 /*
5656 * Packet type specific stuff is next.
5657 */
5658 switch (hdr.ptype) {
5659 case PDU_BIND:
5660 case PDU_ALTER:
5661 dissect_dcerpc_cn_bind(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
5662 break;
5663
5664 case PDU_BIND_ACK:
5665 case PDU_ALTER_ACK:
5666 dissect_dcerpc_cn_bind_ack(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
5667 break;
5668
5669 case PDU_AUTH3:
5670 /*
5671 * Nothing after the common header other than credentials.
5672 */
5673 dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr,
5674 &auth_info);
5675 break;
5676
5677 case PDU_REQ:
5678 dissect_dcerpc_cn_rqst(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, tree, &hdr);
5679 break;
5680
5681 case PDU_RESP:
5682 dissect_dcerpc_cn_resp(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, tree, &hdr);
5683 break;
5684
5685 case PDU_FAULT:
5686 dissect_dcerpc_cn_fault(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
5687 break;
5688
5689 case PDU_BIND_NAK:
5690 dissect_dcerpc_cn_bind_nak(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
5691 break;
5692
5693 case PDU_CO_CANCEL:
5694 case PDU_ORPHANED:
5695 /*
5696 * Nothing after the common header other than an authentication
5697 * verifier.
5698 */
5699 dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr,
5700 &auth_info);
5701 break;
5702
5703 case PDU_SHUTDOWN:
5704 /*
5705 * Nothing after the common header, not even an authentication
5706 * verifier.
5707 */
5708 break;
5709 case PDU_RTS:
5710 dissect_dcerpc_cn_rts(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr);
5711 break;
5712
5713 default:
5714 /* might as well dissect the auth info */
5715 dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr,
5716 &auth_info);
5717 break;
5718 }
5719 return TRUE;
5720 }
5721
5722 /*
5723 * DCERPC dissector for connection oriented calls over packet-oriented
5724 * transports
5725 */
5726 static gboolean
dissect_dcerpc_cn_pk(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)5727 dissect_dcerpc_cn_pk(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5728 {
5729 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
5730
5731 /*
5732 * Only one PDU per transport packet, and only one transport
5733 * packet per PDU.
5734 */
5735 decode_data->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
5736 if (!dissect_dcerpc_cn(tvb, 0, pinfo, tree, FALSE, NULL)) {
5737 /*
5738 * It wasn't a DCERPC PDU.
5739 */
5740 return FALSE;
5741 } else {
5742 /*
5743 * It was.
5744 */
5745 return TRUE;
5746 }
5747 }
5748
5749 /*
5750 * DCERPC dissector for connection oriented calls over byte-stream
5751 * transports.
5752 * we need to distinguish here between SMB and non-TCP (more in the future?)
5753 * to be able to know what kind of private_data structure to expect.
5754 */
5755 static gboolean
dissect_dcerpc_cn_bs_body(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree)5756 dissect_dcerpc_cn_bs_body(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
5757 {
5758 volatile int offset = 0;
5759 int pdu_len = 0;
5760 volatile int dcerpc_pdus = 0;
5761 volatile gboolean ret = FALSE;
5762
5763 /*
5764 * There may be multiple PDUs per transport packet; keep
5765 * processing them.
5766 */
5767 while (tvb_reported_length_remaining(tvb, offset) != 0) {
5768 TRY {
5769 pdu_len = 0;
5770 if (dissect_dcerpc_cn(tvb, offset, pinfo, tree,
5771 dcerpc_cn_desegment, &pdu_len)) {
5772 dcerpc_pdus++;
5773 }
5774 } CATCH_NONFATAL_ERRORS {
5775 /*
5776 * Somebody threw an exception that means that there
5777 * was a problem dissecting the payload; that means
5778 * that a dissector was found, so we don't need to
5779 * dissect the payload as data or update the protocol
5780 * or info columns.
5781 *
5782 * Just show the exception and then continue dissecting
5783 * PDUs.
5784 */
5785 show_exception(tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
5786 /*
5787 * Presumably it looked enough like a DCE RPC PDU that we
5788 * dissected enough of it to throw an exception.
5789 */
5790 dcerpc_pdus++;
5791 } ENDTRY;
5792
5793 if (dcerpc_pdus == 0) {
5794 gboolean try_desegment = FALSE;
5795 if (dcerpc_cn_desegment && pinfo->can_desegment &&
5796 !tvb_bytes_exist(tvb, offset, sizeof(e_dce_cn_common_hdr_t))) {
5797 /* look for a previous occurrence of the DCE-RPC protocol */
5798 wmem_list_frame_t *cur;
5799 cur = wmem_list_frame_prev(wmem_list_tail(pinfo->layers));
5800 while (cur != NULL) {
5801 if (proto_dcerpc == (gint)GPOINTER_TO_UINT(wmem_list_frame_data(cur))) {
5802 try_desegment = TRUE;
5803 break;
5804 }
5805 cur = wmem_list_frame_prev(cur);
5806 }
5807 }
5808
5809 if (try_desegment) {
5810 /* It didn't look like DCE-RPC but we already had one DCE-RPC
5811 * layer in this packet and what we have is short. Assume that
5812 * it was just too short to tell and ask the TCP layer for more
5813 * data. */
5814 pinfo->desegment_offset = offset;
5815 pinfo->desegment_len = (guint32)(sizeof(e_dce_cn_common_hdr_t) - tvb_reported_length_remaining(tvb, offset));
5816 } else {
5817 /* Really not DCE-RPC */
5818 break;
5819 }
5820 }
5821
5822 /*
5823 * Well, we've seen at least one DCERPC PDU.
5824 */
5825 ret = TRUE;
5826
5827 /* if we had more than one Req/Resp in this PDU change the protocol column */
5828 /* this will formerly contain the last interface name, which may not be the same for all Req/Resp */
5829 if (dcerpc_pdus >= 2)
5830 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "%u*DCERPC", dcerpc_pdus);
5831
5832 if (pdu_len == 0) {
5833 /*
5834 * Desegmentation required - bail now, but give the user a hint that desegmentation might be done later.
5835 */
5836 proto_tree_add_uint_format(tree, hf_dcerpc_cn_deseg_req, tvb, offset,
5837 0,
5838 tvb_reported_length_remaining(tvb, offset),
5839 "[DCE RPC: %u byte%s left, desegmentation might follow]",
5840 tvb_reported_length_remaining(tvb, offset),
5841 plurality(tvb_reported_length_remaining(tvb, offset), "", "s"));
5842 break;
5843 }
5844
5845 /*
5846 * Step to the next PDU.
5847 */
5848 offset += pdu_len;
5849 }
5850 return ret;
5851 }
5852
5853 static gboolean
dissect_dcerpc_cn_bs(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)5854 dissect_dcerpc_cn_bs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5855 {
5856 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
5857
5858 decode_data->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
5859 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
5860 }
5861
5862 static guint
get_dcerpc_pdu_len(packet_info * pinfo _U_,tvbuff_t * tvb,int offset _U_,void * data _U_)5863 get_dcerpc_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb,
5864 int offset _U_, void *data _U_)
5865 {
5866 guint8 drep[4];
5867 guint16 frag_len;
5868
5869 /* XXX: why does htis not take offset into account? */
5870 tvb_memcpy(tvb, (guint8 *)drep, 4, sizeof(drep));
5871 frag_len = dcerpc_tvb_get_ntohs(tvb, 8, drep);
5872
5873 return frag_len;
5874 }
5875
5876 static int
dissect_dcerpc_pdu(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)5877 dissect_dcerpc_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
5878 {
5879 int pdu_len = 0;
5880 dissect_dcerpc_cn(tvb, 0, pinfo, tree,
5881 /* Desegment is already handled by TCP, don't confuse it */
5882 FALSE,
5883 &pdu_len);
5884 return pdu_len;
5885 }
5886
5887 static gboolean
dissect_dcerpc_tcp_heur(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)5888 dissect_dcerpc_tcp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
5889 {
5890 dcerpc_decode_as_data* decode_data;
5891
5892 if (!is_dcerpc(tvb, 0, pinfo))
5893 return 0;
5894
5895 decode_data = dcerpc_get_decode_data(pinfo);
5896 decode_data->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
5897
5898 tcp_dissect_pdus(tvb, pinfo, tree, dcerpc_cn_desegment, 10, get_dcerpc_pdu_len, dissect_dcerpc_pdu, data);
5899 return TRUE;
5900 }
5901
5902 static int
dissect_dcerpc_tcp(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)5903 dissect_dcerpc_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
5904 {
5905 dcerpc_decode_as_data* decode_data;
5906
5907 decode_data = dcerpc_get_decode_data(pinfo);
5908 decode_data->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
5909
5910 tcp_dissect_pdus(tvb, pinfo, tree, dcerpc_cn_desegment, 10, get_dcerpc_pdu_len, dissect_dcerpc_pdu, data);
5911 return tvb_captured_length(tvb);
5912 }
5913
5914 static gboolean
dissect_dcerpc_cn_smbpipe(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)5915 dissect_dcerpc_cn_smbpipe(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5916 {
5917 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
5918
5919 decode_data->dcetransporttype = DCE_CN_TRANSPORT_SMBPIPE;
5920 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
5921 }
5922
5923 static gboolean
dissect_dcerpc_cn_smb2(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)5924 dissect_dcerpc_cn_smb2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5925 {
5926 dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
5927
5928 decode_data->dcetransporttype = DCE_CN_TRANSPORT_SMBPIPE;
5929 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
5930 }
5931
5932
5933
5934 static void
dissect_dcerpc_dg_auth(tvbuff_t * tvb,int offset,proto_tree * dcerpc_tree,e_dce_dg_common_hdr_t * hdr,int * auth_level_p)5935 dissect_dcerpc_dg_auth(tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
5936 e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
5937 {
5938 proto_tree *auth_tree = NULL;
5939 guint8 protection_level;
5940
5941 /*
5942 * Initially set "*auth_level_p" to -1 to indicate that we haven't
5943 * yet seen any authentication level information.
5944 */
5945 if (auth_level_p != NULL)
5946 *auth_level_p = -1;
5947
5948 /*
5949 * The authentication information is at the *end* of the PDU; in
5950 * request and response PDUs, the request and response stub data
5951 * come before it.
5952 *
5953 * If the full packet is here, and there's data past the end of the
5954 * packet body, then dissect the auth info.
5955 */
5956 offset += hdr->frag_len;
5957 if (tvb_reported_length_remaining(tvb, offset) > 0) {
5958 switch (hdr->auth_proto) {
5959
5960 case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
5961 auth_tree = proto_tree_add_subtree(dcerpc_tree, tvb, offset, -1, ett_dcerpc_krb5_auth_verf, NULL, "Kerberos authentication verifier");
5962 protection_level = tvb_get_guint8(tvb, offset);
5963 if (auth_level_p != NULL)
5964 *auth_level_p = protection_level;
5965 proto_tree_add_uint(auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
5966 offset++;
5967 proto_tree_add_item(auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, ENC_BIG_ENDIAN);
5968 offset++;
5969 if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
5970 offset += 6; /* 6 bytes of padding */
5971 else
5972 offset += 2; /* 2 bytes of padding */
5973 proto_tree_add_item(auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, ENC_NA);
5974 /*offset += 16;*/
5975 break;
5976
5977 default:
5978 proto_tree_add_item(dcerpc_tree, hf_dcerpc_authentication_verifier, tvb, offset, -1, ENC_NA);
5979 break;
5980 }
5981 }
5982 }
5983
5984 static void
dissect_dcerpc_dg_cancel_ack(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * dcerpc_tree,e_dce_dg_common_hdr_t * hdr)5985 dissect_dcerpc_dg_cancel_ack(tvbuff_t *tvb, int offset, packet_info *pinfo,
5986 proto_tree *dcerpc_tree,
5987 e_dce_dg_common_hdr_t *hdr)
5988 {
5989 guint32 version;
5990
5991 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
5992 hdr->drep, hf_dcerpc_dg_cancel_vers,
5993 &version);
5994
5995 switch (version) {
5996
5997 case 0:
5998 /* The only version we know about */
5999 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
6000 hdr->drep, hf_dcerpc_dg_cancel_id,
6001 NULL);
6002 /*offset = */dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
6003 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
6004 NULL);
6005 break;
6006 }
6007 }
6008
6009 static void
dissect_dcerpc_dg_cancel(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * dcerpc_tree,e_dce_dg_common_hdr_t * hdr)6010 dissect_dcerpc_dg_cancel(tvbuff_t *tvb, int offset, packet_info *pinfo,
6011 proto_tree *dcerpc_tree,
6012 e_dce_dg_common_hdr_t *hdr)
6013 {
6014 guint32 version;
6015
6016 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
6017 hdr->drep, hf_dcerpc_dg_cancel_vers,
6018 &version);
6019
6020 switch (version) {
6021
6022 case 0:
6023 /* The only version we know about */
6024 /*offset = */dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
6025 hdr->drep, hf_dcerpc_dg_cancel_id,
6026 NULL);
6027 /* XXX - are NDR Booleans 32 bits? */
6028
6029 /* XXX - the RPC reference in chapter: "the cancel PDU" doesn't mention
6030 the accepting_cancels field (it's only in the cancel_ack PDU)! */
6031 /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
6032 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
6033 NULL);*/
6034 break;
6035 }
6036 }
6037
6038 static void
dissect_dcerpc_dg_fack(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * dcerpc_tree,e_dce_dg_common_hdr_t * hdr)6039 dissect_dcerpc_dg_fack(tvbuff_t *tvb, int offset, packet_info *pinfo,
6040 proto_tree *dcerpc_tree,
6041 e_dce_dg_common_hdr_t *hdr)
6042 {
6043 guint8 version;
6044 guint16 serial_num;
6045 guint16 selack_len;
6046 guint i;
6047
6048 offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree,
6049 hdr->drep, hf_dcerpc_dg_fack_vers,
6050 &version);
6051 /* padding */
6052 offset++;
6053
6054 switch (version) {
6055
6056 case 0: /* The only version documented in the DCE RPC 1.1 spec */
6057 case 1: /* This appears to be the same */
6058 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
6059 hdr->drep, hf_dcerpc_dg_fack_window_size,
6060 NULL);
6061 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
6062 hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
6063 NULL);
6064 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
6065 hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
6066 NULL);
6067 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
6068 hdr->drep, hf_dcerpc_dg_fack_serial_num,
6069 &serial_num);
6070 col_append_fstr(pinfo->cinfo, COL_INFO, " serial: %u",
6071 serial_num);
6072 offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree,
6073 hdr->drep, hf_dcerpc_dg_fack_selack_len,
6074 &selack_len);
6075 for (i = 0; i < selack_len; i++) {
6076 offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
6077 hdr->drep, hf_dcerpc_dg_fack_selack,
6078 NULL);
6079 }
6080
6081 break;
6082 }
6083 }
6084
6085 static void
dissect_dcerpc_dg_reject_fault(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * dcerpc_tree,e_dce_dg_common_hdr_t * hdr)6086 dissect_dcerpc_dg_reject_fault(tvbuff_t *tvb, int offset, packet_info *pinfo,
6087 proto_tree *dcerpc_tree,
6088 e_dce_dg_common_hdr_t *hdr)
6089 {
6090 guint32 status;
6091
6092 /*offset = */dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree,
6093 hdr->drep, hf_dcerpc_dg_status,
6094 &status);
6095
6096 col_append_fstr (pinfo->cinfo, COL_INFO,
6097 ": status: %s",
6098 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
6099 }
6100
6101 static void
dissect_dcerpc_dg_stub(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * dcerpc_tree,proto_tree * tree,e_dce_dg_common_hdr_t * hdr,dcerpc_info * di)6102 dissect_dcerpc_dg_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
6103 proto_tree *dcerpc_tree, proto_tree *tree,
6104 e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
6105 {
6106 int length, reported_length, stub_length;
6107 gboolean save_fragmented;
6108 fragment_head *fd_head;
6109 tvbuff_t *next_tvb;
6110 proto_item *pi;
6111 proto_item *parent_pi;
6112
6113 col_append_fstr(pinfo->cinfo, COL_INFO, " opnum: %u len: %u",
6114 di->call_data->opnum, hdr->frag_len );
6115
6116 length = tvb_reported_length_remaining(tvb, offset);
6117 reported_length = tvb_reported_length_remaining(tvb, offset);
6118 stub_length = hdr->frag_len;
6119 if (length > stub_length)
6120 length = stub_length;
6121 if (reported_length > stub_length)
6122 reported_length = stub_length;
6123
6124 save_fragmented = pinfo->fragmented;
6125
6126 /* If we don't have reassembly enabled, or this packet contains
6127 the entire PDU, or if this is a short frame (or a frame
6128 not reassembled at a lower layer) that doesn't include all
6129 the data in the fragment, just call the handoff directly if
6130 this is the first fragment or the PDU isn't fragmented. */
6131 if ( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
6132 !tvb_bytes_exist(tvb, offset, stub_length) ) {
6133 if (hdr->frag_num == 0) {
6134
6135
6136 /* First fragment, possibly the only fragment */
6137
6138 /*
6139 * XXX - authentication info?
6140 */
6141 pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
6142 next_tvb = tvb_new_subset_length_caplen(tvb, offset, length,
6143 reported_length);
6144 dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb, TRUE, hdr->drep, di, NULL);
6145 } else {
6146 /* PDU is fragmented and this isn't the first fragment */
6147 if (length > 0) {
6148 proto_tree_add_item(dcerpc_tree, hf_dcerpc_fragment_data, tvb, offset, stub_length, ENC_NA);
6149 }
6150 }
6151 } else {
6152 /* Reassembly is enabled, the PDU is fragmented, and
6153 we have all the data in the fragment; the first two
6154 of those mean we should attempt reassembly, and the
6155 third means we can attempt reassembly. */
6156 if (length > 0) {
6157 proto_tree_add_item(dcerpc_tree, hf_dcerpc_fragment_data, tvb, offset, stub_length, ENC_NA);
6158 }
6159
6160 fd_head = fragment_add_seq(&dcerpc_cl_reassembly_table,
6161 tvb, offset,
6162 pinfo, hdr->seqnum, (void *)hdr,
6163 hdr->frag_num, stub_length,
6164 !(hdr->flags1 & PFCL1_LASTFRAG), 0);
6165 if (fd_head != NULL) {
6166 /* We completed reassembly... */
6167 if (pinfo->num == fd_head->reassembled_in) {
6168 /* ...and this is the reassembled RPC PDU */
6169 next_tvb = tvb_new_chain(tvb, fd_head->tvb_data);
6170 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
6171 show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
6172 tree, pinfo, next_tvb, &pi);
6173
6174 /*
6175 * XXX - authentication info?
6176 */
6177 pinfo->fragmented = FALSE;
6178 dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb, TRUE, hdr->drep, di, NULL);
6179 } else {
6180 /* ...and this isn't the reassembled RPC PDU */
6181 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
6182 tvb, 0, 0, fd_head->reassembled_in);
6183 proto_item_set_generated(pi);
6184 parent_pi = proto_tree_get_parent(dcerpc_tree);
6185 if (parent_pi != NULL) {
6186 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
6187 }
6188 col_append_fstr(pinfo->cinfo, COL_INFO,
6189 " [DCE/RPC fragment, reas: #%u]", fd_head->reassembled_in);
6190 }
6191 }
6192 }
6193 pinfo->fragmented = save_fragmented;
6194 }
6195
6196 static void
dissect_dcerpc_dg_rqst(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * dcerpc_tree,proto_tree * tree,e_dce_dg_common_hdr_t * hdr,conversation_t * conv)6197 dissect_dcerpc_dg_rqst(tvbuff_t *tvb, int offset, packet_info *pinfo,
6198 proto_tree *dcerpc_tree, proto_tree *tree,
6199 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
6200 {
6201 dcerpc_info *di;
6202 dcerpc_call_value *value;
6203 dcerpc_matched_key matched_key, *new_matched_key;
6204 proto_item *pi;
6205 proto_item *parent_pi;
6206
6207 if (!(pinfo->fd->visited)) {
6208 dcerpc_call_value *call_value;
6209 dcerpc_dg_call_key *call_key;
6210
6211 call_key = wmem_new(wmem_file_scope(), dcerpc_dg_call_key);
6212 call_key->conv = conv;
6213 call_key->seqnum = hdr->seqnum;
6214 call_key->act_id = hdr->act_id;
6215
6216 call_value = wmem_new(wmem_file_scope(), dcerpc_call_value);
6217 call_value->uuid = hdr->if_id;
6218 call_value->ver = hdr->if_ver;
6219 call_value->object_uuid = hdr->obj_id;
6220 call_value->opnum = hdr->opnum;
6221 call_value->req_frame = pinfo->num;
6222 call_value->req_time = pinfo->abs_ts;
6223 call_value->rep_frame = 0;
6224 call_value->max_ptr = 0;
6225 call_value->se_data = NULL;
6226 call_value->private_data = NULL;
6227 call_value->pol = NULL;
6228 /* NDR64 is not available on dg transports ?*/
6229 call_value->flags = 0;
6230
6231 wmem_map_insert(dcerpc_dg_calls, call_key, call_value);
6232
6233 new_matched_key = wmem_new(wmem_file_scope(), dcerpc_matched_key);
6234 new_matched_key->frame = pinfo->num;
6235 new_matched_key->call_id = hdr->seqnum;
6236 wmem_map_insert(dcerpc_matched, new_matched_key, call_value);
6237 }
6238
6239 matched_key.frame = pinfo->num;
6240 matched_key.call_id = hdr->seqnum;
6241 value = (dcerpc_call_value *)wmem_map_lookup(dcerpc_matched, &matched_key);
6242 if (!value) {
6243 value = wmem_new(pinfo->pool, dcerpc_call_value);
6244 value->uuid = hdr->if_id;
6245 value->ver = hdr->if_ver;
6246 value->object_uuid = hdr->obj_id;
6247 value->opnum = hdr->opnum;
6248 value->req_frame = pinfo->num;
6249 value->rep_frame = 0;
6250 value->max_ptr = 0;
6251 value->se_data = NULL;
6252 value->private_data = NULL;
6253 }
6254
6255 di = wmem_new0(pinfo->pool, dcerpc_info);
6256 di->dcerpc_procedure_name = "";
6257 di->conv = conv;
6258 di->call_id = hdr->seqnum;
6259 di->transport_salt = -1;
6260 di->ptype = PDU_REQ;
6261 di->call_data = value;
6262
6263 if (value->rep_frame != 0) {
6264 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
6265 tvb, 0, 0, value->rep_frame);
6266 proto_item_set_generated(pi);
6267 parent_pi = proto_tree_get_parent(dcerpc_tree);
6268 if (parent_pi != NULL) {
6269 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
6270 }
6271 }
6272 dissect_dcerpc_dg_stub(tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
6273 }
6274
6275 static void
dissect_dcerpc_dg_resp(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * dcerpc_tree,proto_tree * tree,e_dce_dg_common_hdr_t * hdr,conversation_t * conv)6276 dissect_dcerpc_dg_resp(tvbuff_t *tvb, int offset, packet_info *pinfo,
6277 proto_tree *dcerpc_tree, proto_tree *tree,
6278 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
6279 {
6280 dcerpc_info *di;
6281 dcerpc_call_value *value;
6282 dcerpc_matched_key matched_key, *new_matched_key;
6283 proto_item *pi;
6284 proto_item *parent_pi;
6285
6286 if (!(pinfo->fd->visited)) {
6287 dcerpc_call_value *call_value;
6288 dcerpc_dg_call_key call_key;
6289
6290 call_key.conv = conv;
6291 call_key.seqnum = hdr->seqnum;
6292 call_key.act_id = hdr->act_id;
6293
6294 if ((call_value = (dcerpc_call_value *)wmem_map_lookup(dcerpc_dg_calls, &call_key))) {
6295 new_matched_key = wmem_new(wmem_file_scope(), dcerpc_matched_key);
6296 new_matched_key->frame = pinfo->num;
6297 new_matched_key->call_id = hdr->seqnum;
6298 wmem_map_insert(dcerpc_matched, new_matched_key, call_value);
6299 if (call_value->rep_frame == 0) {
6300 call_value->rep_frame = pinfo->num;
6301 }
6302 }
6303 }
6304
6305 matched_key.frame = pinfo->num;
6306 matched_key.call_id = hdr->seqnum;
6307 value = (dcerpc_call_value *)wmem_map_lookup(dcerpc_matched, &matched_key);
6308 if (!value) {
6309 value = wmem_new0(pinfo->pool, dcerpc_call_value);
6310 value->uuid = hdr->if_id;
6311 value->ver = hdr->if_ver;
6312 value->object_uuid = hdr->obj_id;
6313 value->opnum = hdr->opnum;
6314 value->rep_frame = pinfo->num;
6315 }
6316
6317 di = wmem_new0(pinfo->pool, dcerpc_info);
6318 di->dcerpc_procedure_name = "";
6319 di->conv = conv;
6320 di->transport_salt = -1;
6321 di->ptype = PDU_RESP;
6322 di->call_data = value;
6323
6324 if (value->req_frame != 0) {
6325 nstime_t delta_ts;
6326 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
6327 tvb, 0, 0, value->req_frame);
6328 proto_item_set_generated(pi);
6329 parent_pi = proto_tree_get_parent(dcerpc_tree);
6330 if (parent_pi != NULL) {
6331 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
6332 }
6333 nstime_delta(&delta_ts, &pinfo->abs_ts, &value->req_time);
6334 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
6335 proto_item_set_generated(pi);
6336 } else {
6337 proto_tree_add_expert(dcerpc_tree, pinfo, &ei_dcerpc_no_request_found, tvb, 0, 0);
6338 }
6339 dissect_dcerpc_dg_stub(tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
6340 }
6341
6342 static void
dissect_dcerpc_dg_ping_ack(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * dcerpc_tree,e_dce_dg_common_hdr_t * hdr,conversation_t * conv)6343 dissect_dcerpc_dg_ping_ack(tvbuff_t *tvb, int offset, packet_info *pinfo,
6344 proto_tree *dcerpc_tree,
6345 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
6346 {
6347 proto_item *parent_pi;
6348 /* if (!(pinfo->fd->visited)) {*/
6349 dcerpc_call_value *call_value;
6350 dcerpc_dg_call_key call_key;
6351
6352 call_key.conv = conv;
6353 call_key.seqnum = hdr->seqnum;
6354 call_key.act_id = hdr->act_id;
6355
6356 if ((call_value = (dcerpc_call_value *)wmem_map_lookup(dcerpc_dg_calls, &call_key))) {
6357 proto_item *pi;
6358 nstime_t delta_ts;
6359
6360 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
6361 tvb, 0, 0, call_value->req_frame);
6362 proto_item_set_generated(pi);
6363 parent_pi = proto_tree_get_parent(dcerpc_tree);
6364 if (parent_pi != NULL) {
6365 proto_item_append_text(parent_pi, ", [Req: #%u]", call_value->req_frame);
6366 }
6367
6368 col_append_fstr(pinfo->cinfo, COL_INFO, " [req: #%u]", call_value->req_frame);
6369
6370 nstime_delta(&delta_ts, &pinfo->abs_ts, &call_value->req_time);
6371 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
6372 proto_item_set_generated(pi);
6373 /* }*/
6374 }
6375 }
6376
6377 /*
6378 * DCERPC dissector for connectionless calls
6379 */
6380 static gboolean
dissect_dcerpc_dg(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)6381 dissect_dcerpc_dg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
6382 {
6383 proto_item *ti = NULL;
6384 proto_tree *dcerpc_tree = NULL;
6385 e_dce_dg_common_hdr_t hdr;
6386 int offset = 0;
6387 conversation_t *conv;
6388 int auth_level;
6389 char *uuid_str;
6390 const char *uuid_name = NULL;
6391 static int * const hdr_flags1[] = {
6392 &hf_dcerpc_dg_flags1_rsrvd_80,
6393 &hf_dcerpc_dg_flags1_broadcast,
6394 &hf_dcerpc_dg_flags1_idempotent,
6395 &hf_dcerpc_dg_flags1_maybe,
6396 &hf_dcerpc_dg_flags1_nofack,
6397 &hf_dcerpc_dg_flags1_frag,
6398 &hf_dcerpc_dg_flags1_last_frag,
6399 &hf_dcerpc_dg_flags1_rsrvd_01,
6400 NULL
6401 };
6402
6403 static int * const hdr_flags2[] = {
6404 &hf_dcerpc_dg_flags2_rsrvd_80,
6405 &hf_dcerpc_dg_flags2_rsrvd_40,
6406 &hf_dcerpc_dg_flags2_rsrvd_20,
6407 &hf_dcerpc_dg_flags2_rsrvd_10,
6408 &hf_dcerpc_dg_flags2_rsrvd_08,
6409 &hf_dcerpc_dg_flags2_rsrvd_04,
6410 &hf_dcerpc_dg_flags2_cancel_pending,
6411 &hf_dcerpc_dg_flags2_rsrvd_01,
6412 NULL
6413 };
6414
6415 /*
6416 * Check if this looks like a CL DCERPC call. All dg packets
6417 * have an 80 byte header on them. Which starts with
6418 * version (4), pkt_type.
6419 */
6420 if (tvb_reported_length(tvb) < sizeof (hdr)) {
6421 return FALSE;
6422 }
6423
6424 /* Version must be 4 */
6425 hdr.rpc_ver = tvb_get_guint8(tvb, offset++);
6426 if (hdr.rpc_ver != 4)
6427 return FALSE;
6428
6429 /* Type must be <= PDU_CANCEL_ACK or it's not connectionless DCE/RPC */
6430 hdr.ptype = tvb_get_guint8(tvb, offset++);
6431 if (hdr.ptype > PDU_CANCEL_ACK)
6432 return FALSE;
6433
6434 /* flags1 has bit 1 and 8 as reserved for implementations, with no
6435 indication that they must be set to 0, so we don't check them.
6436 */
6437 hdr.flags1 = tvb_get_guint8(tvb, offset++);
6438
6439 /* flags2 has bit 1 reserved for implementations, bit 2 used,
6440 and the other bits reserved for future use and specified
6441 as "must be set to 0", so if any of the other bits are set
6442 it is probably not DCE/RPC.
6443 */
6444 hdr.flags2 = tvb_get_guint8(tvb, offset++);
6445 if (hdr.flags2&0xfc)
6446 return FALSE;
6447
6448 tvb_memcpy(tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
6449 offset += (int)sizeof (hdr.drep);
6450 if (hdr.drep[0]&0xee)
6451 return FALSE;
6452 if (hdr.drep[1] > DCE_RPC_DREP_FP_IBM)
6453 return FALSE;
6454
6455 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCERPC");
6456 col_add_str(pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
6457
6458 hdr.serial_hi = tvb_get_guint8(tvb, offset++);
6459 dcerpc_tvb_get_uuid(tvb, offset, hdr.drep, &hdr.obj_id);
6460 offset += 16;
6461 dcerpc_tvb_get_uuid(tvb, offset, hdr.drep, &hdr.if_id);
6462 offset += 16;
6463 dcerpc_tvb_get_uuid(tvb, offset, hdr.drep, &hdr.act_id);
6464 offset += 16;
6465 hdr.server_boot = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
6466 offset += 4;
6467 hdr.if_ver = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
6468 offset += 4;
6469 hdr.seqnum = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
6470 offset += 4;
6471 hdr.opnum = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
6472 offset += 2;
6473 hdr.ihint = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
6474 offset += 2;
6475 hdr.ahint = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
6476 offset += 2;
6477 hdr.frag_len = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
6478 offset += 2;
6479 hdr.frag_num = dcerpc_tvb_get_ntohs(tvb, offset, hdr.drep);
6480 offset += 2;
6481 hdr.auth_proto = tvb_get_guint8(tvb, offset++);
6482 hdr.serial_lo = tvb_get_guint8(tvb, offset++);
6483
6484 if (tree) {
6485 ti = proto_tree_add_item(tree, proto_dcerpc, tvb, 0, -1, ENC_NA);
6486 if (ti) {
6487 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
6488 proto_item_append_text(ti, " %s, Seq: %u, Serial: %u, Frag: %u, FragLen: %u",
6489 val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"),
6490 hdr.seqnum, hdr.serial_hi*256+hdr.serial_lo,
6491 hdr.frag_num, hdr.frag_len);
6492 }
6493 }
6494 offset = 0;
6495
6496 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
6497 offset++;
6498
6499 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
6500 offset++;
6501
6502 proto_tree_add_bitmask_value(dcerpc_tree, tvb, offset, hf_dcerpc_dg_flags1,
6503 ett_dcerpc_dg_flags1, hdr_flags1, hdr.flags1);
6504 offset++;
6505
6506 proto_tree_add_bitmask_value(dcerpc_tree, tvb, offset, hf_dcerpc_dg_flags2,
6507 ett_dcerpc_dg_flags2, hdr_flags2, hdr.flags2);
6508 offset++;
6509
6510 if (tree) {
6511 proto_tree_add_dcerpc_drep(dcerpc_tree, tvb, offset, hdr.drep, (int)sizeof (hdr.drep));
6512 }
6513 offset += (int)sizeof (hdr.drep);
6514
6515 if (tree)
6516 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
6517 offset++;
6518
6519 if (tree) {
6520 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
6521 offset, 16, (e_guid_t *) &hdr.obj_id, "Object UUID: %s",
6522 guid_to_str(pinfo->pool, (e_guid_t *) &hdr.obj_id));
6523 }
6524 offset += 16;
6525
6526 if (tree) {
6527 uuid_str = guid_to_str(pinfo->pool, (e_guid_t*)&hdr.if_id);
6528 uuid_name = guids_get_uuid_name(&hdr.if_id, pinfo->pool);
6529 if (uuid_name) {
6530 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
6531 offset, 16, (e_guid_t *) &hdr.if_id, "Interface: %s UUID: %s", uuid_name, uuid_str);
6532 } else {
6533 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
6534 offset, 16, (e_guid_t *) &hdr.if_id, "Interface UUID: %s", uuid_str);
6535 }
6536 }
6537 offset += 16;
6538
6539 if (tree) {
6540 proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
6541 offset, 16, (e_guid_t *) &hdr.act_id, "Activity: %s",
6542 guid_to_str(pinfo->pool, (e_guid_t *) &hdr.act_id));
6543 }
6544 offset += 16;
6545
6546 if (tree) {
6547 nstime_t server_boot;
6548
6549 server_boot.secs = hdr.server_boot;
6550 server_boot.nsecs = 0;
6551
6552 if (hdr.server_boot == 0)
6553 proto_tree_add_time_format_value(dcerpc_tree, hf_dcerpc_dg_server_boot,
6554 tvb, offset, 4, &server_boot,
6555 "Unknown (0)");
6556 else
6557 proto_tree_add_time(dcerpc_tree, hf_dcerpc_dg_server_boot,
6558 tvb, offset, 4, &server_boot);
6559 }
6560 offset += 4;
6561
6562 if (tree)
6563 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
6564 offset += 4;
6565
6566 if (tree)
6567 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
6568 col_append_fstr(pinfo->cinfo, COL_INFO, ": seq: %u", hdr.seqnum);
6569 col_append_fstr(pinfo->cinfo, COL_DCE_CALL, "%u", hdr.seqnum);
6570 offset += 4;
6571
6572 if (tree)
6573 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
6574 offset += 2;
6575
6576 if (tree)
6577 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
6578 offset += 2;
6579
6580 if (tree)
6581 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
6582 offset += 2;
6583
6584 if (tree)
6585 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
6586 offset += 2;
6587
6588 if (tree)
6589 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
6590 if (hdr.flags1 & PFCL1_FRAG) {
6591 /* Fragmented - put the fragment number into the Info column */
6592 col_append_fstr(pinfo->cinfo, COL_INFO, " frag: %u",
6593 hdr.frag_num);
6594 }
6595 offset += 2;
6596
6597 if (tree)
6598 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
6599 offset++;
6600
6601 if (tree)
6602 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
6603 if (hdr.flags1 & PFCL1_FRAG) {
6604 /* Fragmented - put the serial number into the Info column */
6605 col_append_fstr(pinfo->cinfo, COL_INFO, " serial: %u",
6606 (hdr.serial_hi << 8) | hdr.serial_lo);
6607 }
6608 offset++;
6609
6610 if (tree) {
6611 /*
6612 * XXX - for Kerberos, we get a protection level; if it's
6613 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
6614 * stub data.
6615 */
6616 dissect_dcerpc_dg_auth(tvb, offset, dcerpc_tree, &hdr,
6617 &auth_level);
6618 }
6619
6620 /*
6621 * keeping track of the conversation shouldn't really be necessary
6622 * for connectionless packets, because everything we need to know
6623 * to dissect is in the header for each packet. Unfortunately,
6624 * Microsoft's implementation is buggy and often puts the
6625 * completely wrong if_id in the header. go figure. So, keep
6626 * track of the seqnum and use that if possible. Note: that's not
6627 * completely correct. It should really be done based on both the
6628 * activity_id and seqnum. I haven't seen anywhere that it would
6629 * make a difference, but for future reference...
6630 */
6631 conv = find_or_create_conversation(pinfo);
6632
6633 /*
6634 * Packet type specific stuff is next.
6635 */
6636
6637 switch (hdr.ptype) {
6638
6639 case PDU_CANCEL_ACK:
6640 /* Body is optional */
6641 /* XXX - we assume "frag_len" is the length of the body */
6642 if (hdr.frag_len != 0)
6643 dissect_dcerpc_dg_cancel_ack(tvb, offset, pinfo, dcerpc_tree, &hdr);
6644 break;
6645
6646 case PDU_CL_CANCEL:
6647 /*
6648 * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
6649 * but in at least one capture none of the Cl_cancel PDUs had a
6650 * body.
6651 */
6652 /* XXX - we assume "frag_len" is the length of the body */
6653 if (hdr.frag_len != 0)
6654 dissect_dcerpc_dg_cancel(tvb, offset, pinfo, dcerpc_tree, &hdr);
6655 break;
6656
6657 case PDU_NOCALL:
6658 /* Body is optional; if present, it's the same as PDU_FACK */
6659 /* XXX - we assume "frag_len" is the length of the body */
6660 if (hdr.frag_len != 0)
6661 dissect_dcerpc_dg_fack(tvb, offset, pinfo, dcerpc_tree, &hdr);
6662 break;
6663
6664 case PDU_FACK:
6665 /* Body is optional */
6666 /* XXX - we assume "frag_len" is the length of the body */
6667 if (hdr.frag_len != 0)
6668 dissect_dcerpc_dg_fack(tvb, offset, pinfo, dcerpc_tree, &hdr);
6669 break;
6670
6671 case PDU_REJECT:
6672 case PDU_FAULT:
6673 dissect_dcerpc_dg_reject_fault(tvb, offset, pinfo, dcerpc_tree, &hdr);
6674 break;
6675
6676 case PDU_REQ:
6677 dissect_dcerpc_dg_rqst(tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
6678 break;
6679
6680 case PDU_RESP:
6681 dissect_dcerpc_dg_resp(tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
6682 break;
6683
6684 /* these requests have no body */
6685 case PDU_ACK:
6686 case PDU_PING:
6687 dissect_dcerpc_dg_ping_ack(tvb, offset, pinfo, dcerpc_tree, &hdr, conv);
6688 break;
6689 case PDU_WORKING:
6690 default:
6691 break;
6692 }
6693
6694 return TRUE;
6695 }
6696
6697 static void
dcerpc_auth_subdissector_list_free(gpointer p,gpointer user_data _U_)6698 dcerpc_auth_subdissector_list_free(gpointer p, gpointer user_data _U_)
6699 {
6700 g_free(p);
6701 }
6702
6703 static void
dcerpc_shutdown(void)6704 dcerpc_shutdown(void)
6705 {
6706 g_slist_foreach(dcerpc_auth_subdissector_list, dcerpc_auth_subdissector_list_free, NULL);
6707 g_slist_free(dcerpc_auth_subdissector_list);
6708 g_hash_table_destroy(dcerpc_uuids);
6709 tvb_free(tvb_trailer_signature);
6710 }
6711
6712 void
proto_register_dcerpc(void)6713 proto_register_dcerpc(void)
6714 {
6715 static hf_register_info hf[] = {
6716 { &hf_dcerpc_request_in,
6717 { "Request in frame", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE,
6718 NULL, 0, "This packet is a response to the packet with this number", HFILL }},
6719 { &hf_dcerpc_response_in,
6720 { "Response in frame", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
6721 NULL, 0, "This packet will be responded in the packet with this number", HFILL }},
6722 { &hf_dcerpc_referent_id32,
6723 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
6724 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
6725 { &hf_dcerpc_referent_id64,
6726 { "Referent ID", "dcerpc.referent_id64", FT_UINT64, BASE_HEX,
6727 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
6728 { &hf_dcerpc_ver,
6729 { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6730 { &hf_dcerpc_ver_minor,
6731 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6732 { &hf_dcerpc_packet_type,
6733 { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS(pckt_vals), 0x0, NULL, HFILL }},
6734 { &hf_dcerpc_cn_flags,
6735 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6736 { &hf_dcerpc_cn_flags_first_frag,
6737 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_FIRST_FRAG, NULL, HFILL }},
6738 { &hf_dcerpc_cn_flags_last_frag,
6739 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_LAST_FRAG, NULL, HFILL }},
6740 { &hf_dcerpc_cn_flags_cancel_pending,
6741 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_PENDING_CANCEL, NULL, HFILL }},
6742 { &hf_dcerpc_cn_flags_reserved,
6743 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_RESERVED_1, NULL, HFILL }},
6744 { &hf_dcerpc_cn_flags_mpx,
6745 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_CONC_MPX, NULL, HFILL }},
6746 { &hf_dcerpc_cn_flags_dne,
6747 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_DID_NOT_EXECUTE, NULL, HFILL }},
6748 { &hf_dcerpc_cn_flags_maybe,
6749 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_MAYBE, NULL, HFILL }},
6750 { &hf_dcerpc_cn_flags_object,
6751 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFC_OBJECT_UUID, NULL, HFILL }},
6752 { &hf_dcerpc_drep,
6753 { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6754 { &hf_dcerpc_drep_byteorder,
6755 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS(drep_byteorder_vals), 0x0, NULL, HFILL }},
6756 { &hf_dcerpc_ndr_padding,
6757 { "NDR-Padding", "dcerpc.ndr_padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6758 { &hf_dcerpc_drep_character,
6759 { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS(drep_character_vals), 0x0, NULL, HFILL }},
6760 { &hf_dcerpc_drep_fp,
6761 { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS(drep_fp_vals), 0x0, NULL, HFILL }},
6762 { &hf_dcerpc_cn_frag_len,
6763 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6764 { &hf_dcerpc_cn_auth_len,
6765 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6766 { &hf_dcerpc_cn_call_id,
6767 { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6768 { &hf_dcerpc_cn_max_xmit,
6769 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6770 { &hf_dcerpc_cn_max_recv,
6771 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6772 { &hf_dcerpc_cn_assoc_group,
6773 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6774 { &hf_dcerpc_cn_num_ctx_items,
6775 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6776 { &hf_dcerpc_cn_ctx_item,
6777 { "Ctx Item", "dcerpc.cn_ctx_item", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6778 { &hf_dcerpc_cn_ctx_id,
6779 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6780 { &hf_dcerpc_cn_num_trans_items,
6781 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6782 { &hf_dcerpc_cn_bind_abstract_syntax,
6783 { "Abstract Syntax", "dcerpc.cn_bind_abstract_syntax", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6784 { &hf_dcerpc_cn_bind_if_id,
6785 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6786 { &hf_dcerpc_cn_bind_if_ver,
6787 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6788 { &hf_dcerpc_cn_bind_if_ver_minor,
6789 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6790 { &hf_dcerpc_cn_bind_trans_syntax,
6791 { "Transfer Syntax", "dcerpc.cn_bind_trans", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6792 { &hf_dcerpc_cn_bind_trans_id,
6793 { "ID", "dcerpc.cn_bind_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6794 { &hf_dcerpc_cn_bind_trans_ver,
6795 { "ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6796 { &hf_dcerpc_cn_bind_trans_btfn, /* [MS-RPCE] 2.2.2.14 */
6797 {"Bind Time Features", "dcerpc.cn_bind_trans_btfn", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
6798 { &hf_dcerpc_cn_bind_trans_btfn_01,
6799 { "Security Context Multiplexing Supported", "dcerpc.cn_bind_trans_btfn.01", FT_BOOLEAN, 16, NULL, 0x01, NULL, HFILL }},
6800 { &hf_dcerpc_cn_bind_trans_btfn_02,
6801 { "Keep Connection On Orphan Supported", "dcerpc.cn_bind_trans_btfn.02", FT_BOOLEAN, 16, NULL, 0x02, NULL, HFILL }},
6802 { &hf_dcerpc_cn_alloc_hint,
6803 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6804 { &hf_dcerpc_cn_sec_addr_len,
6805 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6806 { &hf_dcerpc_cn_sec_addr,
6807 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6808 { &hf_dcerpc_cn_num_results,
6809 { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6810 { &hf_dcerpc_cn_ack_result,
6811 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, NULL, HFILL }},
6812 { &hf_dcerpc_cn_ack_reason,
6813 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, NULL, HFILL }},
6814 { &hf_dcerpc_cn_ack_trans_id,
6815 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6816 { &hf_dcerpc_cn_ack_trans_ver,
6817 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6818 { &hf_dcerpc_cn_reject_reason,
6819 { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, NULL, HFILL }},
6820 { &hf_dcerpc_cn_num_protocols,
6821 { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6822 { &hf_dcerpc_cn_protocol_ver_major,
6823 { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6824 { &hf_dcerpc_cn_protocol_ver_minor,
6825 { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6826 { &hf_dcerpc_cn_cancel_count,
6827 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6828 { &hf_dcerpc_cn_fault_flags,
6829 { "Fault flags", "dcerpc.cn_fault_flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6830 { &hf_dcerpc_cn_fault_flags_extended_error_info,
6831 { "Extended error information present", "dcerpc.cn_fault_flags.extended_error", FT_BOOLEAN, 8, NULL, 0x1, NULL, HFILL }},
6832 { &hf_dcerpc_cn_status,
6833 { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, NULL, HFILL }},
6834 { &hf_dcerpc_cn_deseg_req,
6835 { "Desegmentation Required", "dcerpc.cn_deseg_req", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6836 { &hf_dcerpc_auth_type,
6837 { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS(authn_protocol_vals), 0x0, NULL, HFILL }},
6838 { &hf_dcerpc_auth_level,
6839 { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, NULL, HFILL }},
6840 { &hf_dcerpc_auth_pad_len,
6841 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6842 { &hf_dcerpc_auth_rsrvd,
6843 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6844 { &hf_dcerpc_auth_ctx_id,
6845 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6846 { &hf_dcerpc_dg_flags1,
6847 { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6848 { &hf_dcerpc_dg_flags1_rsrvd_01,
6849 { "Reserved for implementation", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_RESERVED_01, NULL, HFILL }},
6850 { &hf_dcerpc_dg_flags1_last_frag,
6851 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_LASTFRAG, NULL, HFILL }},
6852 { &hf_dcerpc_dg_flags1_frag,
6853 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_FRAG, NULL, HFILL }},
6854 { &hf_dcerpc_dg_flags1_nofack,
6855 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_NOFACK, NULL, HFILL }},
6856 { &hf_dcerpc_dg_flags1_maybe,
6857 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_MAYBE, NULL, HFILL }},
6858 { &hf_dcerpc_dg_flags1_idempotent,
6859 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_IDEMPOTENT, NULL, HFILL }},
6860 { &hf_dcerpc_dg_flags1_broadcast,
6861 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_BROADCAST, NULL, HFILL }},
6862 { &hf_dcerpc_dg_flags1_rsrvd_80,
6863 { "Reserved for implementation", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL1_RESERVED_80, NULL, HFILL }},
6864 { &hf_dcerpc_dg_flags2,
6865 { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6866 { &hf_dcerpc_dg_flags2_rsrvd_01,
6867 { "Reserved for implementation", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_01, NULL, HFILL }},
6868 { &hf_dcerpc_dg_flags2_cancel_pending,
6869 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_CANCEL_PENDING, NULL, HFILL }},
6870 { &hf_dcerpc_dg_flags2_rsrvd_04,
6871 { "Reserved for future use (MBZ)", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_04, NULL, HFILL }},
6872 { &hf_dcerpc_dg_flags2_rsrvd_08,
6873 { "Reserved for future use (MBZ)", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_08, NULL, HFILL }},
6874 { &hf_dcerpc_dg_flags2_rsrvd_10,
6875 { "Reserved for future use (MBZ)", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_10, NULL, HFILL }},
6876 { &hf_dcerpc_dg_flags2_rsrvd_20,
6877 { "Reserved for future use (MBZ)", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_20, NULL, HFILL }},
6878 { &hf_dcerpc_dg_flags2_rsrvd_40,
6879 { "Reserved for future use (MBZ)", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_40, NULL, HFILL }},
6880 { &hf_dcerpc_dg_flags2_rsrvd_80,
6881 { "Reserved for future use (MBZ)", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS(&tfs_set_notset), PFCL2_RESERVED_80, NULL, HFILL }},
6882 { &hf_dcerpc_dg_serial_lo,
6883 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6884 { &hf_dcerpc_dg_serial_hi,
6885 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6886 { &hf_dcerpc_dg_ahint,
6887 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6888 { &hf_dcerpc_dg_ihint,
6889 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6890 { &hf_dcerpc_dg_frag_len,
6891 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6892 { &hf_dcerpc_dg_frag_num,
6893 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6894 { &hf_dcerpc_dg_auth_proto,
6895 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS(authn_protocol_vals), 0x0, NULL, HFILL }},
6896 { &hf_dcerpc_dg_seqnum,
6897 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6898 { &hf_dcerpc_dg_server_boot,
6899 { "Server boot time", "dcerpc.dg_server_boot", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0, NULL, HFILL }},
6900 { &hf_dcerpc_dg_if_ver,
6901 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6902 { &hf_dcerpc_krb5_av_prot_level,
6903 { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, NULL, HFILL }},
6904 { &hf_dcerpc_krb5_av_key_vers_num,
6905 { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6906 { &hf_dcerpc_krb5_av_key_auth_verifier,
6907 { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6908 { &hf_dcerpc_obj_id,
6909 { "Object", "dcerpc.obj_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6910 { &hf_dcerpc_dg_if_id,
6911 { "Interface", "dcerpc.dg_if_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6912 { &hf_dcerpc_dg_act_id,
6913 { "Activity", "dcerpc.dg_act_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6914 { &hf_dcerpc_opnum,
6915 { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6916
6917 { &hf_dcerpc_dg_cancel_vers,
6918 { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6919
6920 { &hf_dcerpc_dg_cancel_id,
6921 { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6922
6923 { &hf_dcerpc_dg_server_accepting_cancels,
6924 { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6925
6926 { &hf_dcerpc_dg_fack_vers,
6927 { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6928
6929 { &hf_dcerpc_dg_fack_window_size,
6930 { "Window Size", "dcerpc.fack_window_size", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6931
6932 { &hf_dcerpc_dg_fack_max_tsdu,
6933 { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6934
6935 { &hf_dcerpc_dg_fack_max_frag_size,
6936 { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6937
6938 { &hf_dcerpc_dg_fack_serial_num,
6939 { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6940
6941 { &hf_dcerpc_dg_fack_selack_len,
6942 { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6943
6944 { &hf_dcerpc_dg_fack_selack,
6945 { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
6946
6947 { &hf_dcerpc_dg_status,
6948 { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, NULL, HFILL }},
6949
6950 { &hf_dcerpc_array_max_count,
6951 { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
6952
6953 { &hf_dcerpc_array_offset,
6954 { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
6955
6956 { &hf_dcerpc_array_actual_count,
6957 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
6958
6959 { &hf_dcerpc_op,
6960 { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
6961
6962 { &hf_dcerpc_null_pointer,
6963 { "NULL Pointer", "dcerpc.null_pointer", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
6964
6965 { &hf_dcerpc_fragments,
6966 { "Reassembled DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
6967 NULL, 0x0, "DCE/RPC Fragments", HFILL }},
6968
6969 { &hf_dcerpc_fragment,
6970 { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM, BASE_NONE,
6971 NULL, 0x0, NULL, HFILL }},
6972
6973 { &hf_dcerpc_fragment_overlap,
6974 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE,
6975 NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
6976
6977 { &hf_dcerpc_fragment_overlap_conflict,
6978 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE,
6979 NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
6980
6981 { &hf_dcerpc_fragment_multiple_tails,
6982 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE,
6983 NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
6984
6985 { &hf_dcerpc_fragment_too_long_fragment,
6986 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE,
6987 NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
6988
6989 { &hf_dcerpc_fragment_error,
6990 { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE,
6991 NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
6992
6993 { &hf_dcerpc_fragment_count,
6994 { "Fragment count", "dcerpc.fragment.count", FT_UINT32, BASE_DEC,
6995 NULL, 0x0, NULL, HFILL }},
6996
6997 { &hf_dcerpc_time,
6998 { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE,
6999 NULL, 0, "Time between Request and Response for DCE-RPC calls", HFILL }},
7000
7001 { &hf_dcerpc_reassembled_in,
7002 { "Reassembled PDU in frame", "dcerpc.reassembled_in", FT_FRAMENUM, BASE_NONE,
7003 NULL, 0x0, "The DCE/RPC PDU is completely reassembled in the packet with this number", HFILL }},
7004
7005 { &hf_dcerpc_reassembled_length,
7006 { "Reassembled DCE/RPC length", "dcerpc.reassembled.length", FT_UINT32, BASE_DEC,
7007 NULL, 0x0, "The total length of the reassembled payload", HFILL }},
7008
7009 { &hf_dcerpc_unknown_if_id,
7010 { "Unknown DCERPC interface id", "dcerpc.unknown_if_id", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7011
7012 { &hf_dcerpc_cn_rts_flags,
7013 { "RTS Flags", "dcerpc.cn_rts_flags", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
7014 { &hf_dcerpc_cn_rts_flags_ping,
7015 { "Ping", "dcerpc.cn_rts.flags.ping", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_PING, NULL, HFILL }},
7016 { &hf_dcerpc_cn_rts_flags_other_cmd,
7017 { "Other Cmd", "dcerpc.cn_rts_flags.other_cmd", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_OTHER_CMD, NULL, HFILL }},
7018 { &hf_dcerpc_cn_rts_flags_recycle_channel,
7019 { "Recycle Channel", "dcerpc.cn_rts_flags.recycle_channel", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_RECYCLE_CHANNEL, NULL, HFILL }},
7020 { &hf_dcerpc_cn_rts_flags_in_channel,
7021 { "In Channel", "dcerpc.cn_rts_flags.in_channel", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_IN_CHANNEL, NULL, HFILL }},
7022 { &hf_dcerpc_cn_rts_flags_out_channel,
7023 { "Out Channel", "dcerpc.cn_rts_flags.out_channel", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_OUT_CHANNEL, NULL, HFILL }},
7024 { &hf_dcerpc_cn_rts_flags_eof,
7025 { "EOF", "dcerpc.cn_rts_flags.eof", FT_BOOLEAN, 8, TFS(&tfs_set_notset), RTS_FLAG_EOF, NULL, HFILL }},
7026 { &hf_dcerpc_cn_rts_commands_nb,
7027 { "RTS Number of Commands", "dcerpc.cn_rts_commands_nb", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7028 { &hf_dcerpc_cn_rts_command,
7029 { "RTS Command", "dcerpc.cn_rts_command", FT_UINT32, BASE_HEX, VALS(rts_command_vals), 0x0, NULL, HFILL }},
7030 { &hf_dcerpc_cn_rts_command_receivewindowsize,
7031 {"Receive Window Size", "dcerpc.cn_rts_command.receivewindowsize", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
7032 { &hf_dcerpc_cn_rts_command_fack_bytesreceived,
7033 {"Bytes Received", "dcerpc.cn_rts_command.fack.bytesreceived", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
7034 { &hf_dcerpc_cn_rts_command_fack_availablewindow,
7035 {"Available Window", "dcerpc.cn_rts_command.fack.availablewindow", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
7036 { &hf_dcerpc_cn_rts_command_fack_channelcookie,
7037 {"Channel Cookie", "dcerpc.cn_rts_command.fack.channelcookie", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7038 { &hf_dcerpc_cn_rts_command_connectiontimeout,
7039 {"Connection Timeout", "dcerpc.cn_rts_command.connectiontimeout", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7040 { &hf_dcerpc_cn_rts_command_cookie,
7041 {"Cookie", "dcerpc.cn_rts_command.cookie", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7042 { &hf_dcerpc_cn_rts_command_channellifetime,
7043 {"Channel Lifetime", "dcerpc.cn_rts_command.channellifetime", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
7044 { &hf_dcerpc_cn_rts_command_clientkeepalive,
7045 {"Client Keepalive", "dcerpc.cn_rts_command.clientkeepalive", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
7046 { &hf_dcerpc_cn_rts_command_version,
7047 {"Version", "dcerpc.cn_rts_command.version", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
7048 { &hf_dcerpc_cn_rts_command_conformancecount,
7049 {"Conformance Count", "dcerpc.cn_rts_command.padding.conformancecount", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
7050 { &hf_dcerpc_cn_rts_command_padding,
7051 { "Padding", "dcerpc.cn_rts_command.padding.padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
7052 { &hf_dcerpc_cn_rts_command_addrtype,
7053 { "Address Type", "dcerpc.cn_rts_command.addrtype", FT_UINT32, BASE_DEC, VALS(rts_addresstype_vals), 0x0, NULL, HFILL }},
7054 { &hf_dcerpc_cn_rts_command_associationgroupid,
7055 {"Association Group ID", "dcerpc.cn_rts_command.associationgroupid", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7056 { &hf_dcerpc_cn_rts_command_forwarddestination,
7057 {"Forward Destination", "dcerpc.cn_rts_command.forwarddestination", FT_UINT32, BASE_DEC, VALS(rts_forward_destination_vals), 0x0, NULL, HFILL }},
7058 { &hf_dcerpc_cn_rts_command_pingtrafficsentnotify,
7059 {"Ping Traffic Sent Notify", "dcerpc.cn_rts_command.pingtrafficsentnotify", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
7060 { &hf_dcerpc_sec_vt_signature,
7061 {"SEC_VT_SIGNATURE", "dcerpc.rpc_sec_vt.signature", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7062 { &hf_dcerpc_sec_vt_command_end,
7063 {"SEC_VT_COMMAND_END", "dcerpc.rpc_sec_vt.command.end", FT_BOOLEAN, 16, NULL, 0x4000, NULL, HFILL }},
7064 { &hf_dcerpc_sec_vt_command_must,
7065 {"SEC_VT_MUST_PROCESS_COMMAND", "dcerpc.rpc_sec_vt.command.must_process", FT_BOOLEAN, 16, NULL, 0x8000, NULL, HFILL }},
7066 { &hf_dcerpc_sec_vt_command_cmd,
7067 {"Cmd", "dcerpc.rpc_sec_vt.command.cmd", FT_UINT16, BASE_HEX, VALS(sec_vt_command_cmd_vals), 0x3fff, NULL, HFILL }},
7068 { &hf_dcerpc_sec_vt_command,
7069 {"Command", "dcerpc.rpc_sec_vt.command", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
7070 { &hf_dcerpc_sec_vt_command_length,
7071 {"Length", "dcerpc.rpc_sec_vt.command.length", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL}},
7072 { &hf_dcerpc_sec_vt_bitmask,
7073 {"rpc_sec_vt_bitmask", "dcerpc.rpc_sec_vt.bitmask", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
7074 { &hf_dcerpc_sec_vt_bitmask_sign,
7075 {"CLIENT_SUPPORT_HEADER_SIGNING", "dcerpc.rpc_sec_vt.bitmask.sign", FT_BOOLEAN, 32, NULL, 0x1, NULL, HFILL }},
7076 { &hf_dcerpc_sec_vt_pcontext_uuid,
7077 {"UUID", "dcerpc.rpc_sec_vt.pcontext.interface.uuid", FT_GUID, BASE_NONE, NULL, 0, NULL, HFILL }},
7078 { &hf_dcerpc_sec_vt_pcontext_ver,
7079 {"Version", "dcerpc.rpc_sec_vt.pcontext.interface.ver", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
7080 { &hf_dcerpc_reserved,
7081 {"Reserved", "dcerpc.reserved", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
7082 { &hf_dcerpc_unknown,
7083 {"Unknown", "dcerpc.unknown", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
7084 { &hf_dcerpc_missalign,
7085 {"missalign", "dcerpc.missalign", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
7086 /* Generated from convert_proto_tree_add_text.pl */
7087 { &hf_dcerpc_duplicate_ptr, { "duplicate PTR", "dcerpc.duplicate_ptr", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7088 { &hf_dcerpc_encrypted_stub_data, { "Encrypted stub data", "dcerpc.encrypted_stub_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7089 { &hf_dcerpc_decrypted_stub_data, { "Decrypted stub data", "dcerpc.decrypted_stub_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7090 { &hf_dcerpc_payload_stub_data, { "Payload stub data", "dcerpc.payload_stub_data", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7091 { &hf_dcerpc_stub_data_with_sec_vt, { "Stub data with rpc_sec_verification_trailer", "dcerpc.stub_data_with_sec_vt", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7092 { &hf_dcerpc_stub_data, { "Stub data", "dcerpc.stub_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7093 { &hf_dcerpc_auth_padding, { "Auth Padding", "dcerpc.auth_padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7094 { &hf_dcerpc_auth_info, { "Auth Info", "dcerpc.auth_info", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7095 { &hf_dcerpc_auth_credentials, { "Auth Credentials", "dcerpc.auth_credentials", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7096 { &hf_dcerpc_fault_stub_data, { "Fault stub data", "dcerpc.fault_stub_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7097 { &hf_dcerpc_fragment_data, { "Fragment data", "dcerpc.fragment_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7098 { &hf_dcerpc_cmd_client_ipv4, { "RTS Client address", "dcerpc.cmd_client_ipv4", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7099 { &hf_dcerpc_cmd_client_ipv6, { "RTS Client address", "dcerpc.cmd_client_ipv6", FT_IPv6, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7100 { &hf_dcerpc_authentication_verifier, { "Authentication verifier", "dcerpc.authentication_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
7101 };
7102 static gint *ett[] = {
7103 &ett_dcerpc,
7104 &ett_dcerpc_cn_flags,
7105 &ett_dcerpc_cn_ctx,
7106 &ett_dcerpc_cn_iface,
7107 &ett_dcerpc_cn_trans_syntax,
7108 &ett_dcerpc_cn_trans_btfn,
7109 &ett_dcerpc_cn_bind_trans_btfn,
7110 &ett_dcerpc_cn_rts_flags,
7111 &ett_dcerpc_cn_rts_command,
7112 &ett_dcerpc_cn_rts_pdu,
7113 &ett_dcerpc_drep,
7114 &ett_dcerpc_dg_flags1,
7115 &ett_dcerpc_dg_flags2,
7116 &ett_dcerpc_pointer_data,
7117 &ett_dcerpc_string,
7118 &ett_dcerpc_fragments,
7119 &ett_dcerpc_fragment,
7120 &ett_dcerpc_krb5_auth_verf,
7121 &ett_dcerpc_auth_info,
7122 &ett_dcerpc_verification_trailer,
7123 &ett_dcerpc_sec_vt_command,
7124 &ett_dcerpc_sec_vt_bitmask,
7125 &ett_dcerpc_sec_vt_pcontext,
7126 &ett_dcerpc_sec_vt_header,
7127 &ett_dcerpc_complete_stub_data,
7128 &ett_dcerpc_fault_flags,
7129 &ett_dcerpc_fault_stub_data,
7130 };
7131
7132 static ei_register_info ei[] = {
7133 { &ei_dcerpc_fragment, { "dcerpc.fragment.reassemble", PI_REASSEMBLE, PI_CHAT, "Fragment", EXPFILL }},
7134 { &ei_dcerpc_fragment_reassembled, { "dcerpc.fragment_reassembled", PI_REASSEMBLE, PI_CHAT, "Fragment, reassembled", EXPFILL }},
7135 { &ei_dcerpc_cn_ctx_id_no_bind, { "dcerpc.cn_ctx_id.no_bind", PI_UNDECODED, PI_NOTE, "No bind info for interface Context ID", EXPFILL }},
7136 { &ei_dcerpc_no_request_found, { "dcerpc.no_request_found", PI_SEQUENCE, PI_NOTE, "No request to this DCE/RPC call found", EXPFILL }},
7137 { &ei_dcerpc_cn_status, { "dcerpc.cn_status.expert", PI_RESPONSE_CODE, PI_NOTE, "Fault", EXPFILL }},
7138 { &ei_dcerpc_fragment_multiple, { "dcerpc.fragment_multiple", PI_SEQUENCE, PI_CHAT, "Multiple DCE/RPC fragments/PDU's in one packet", EXPFILL }},
7139 #if 0 /* XXX - too much "output noise", removed for now */
7140 { &ei_dcerpc_context_change, { "dcerpc.context_change", PI_SEQUENCE, PI_CHAT, "Context change", EXPFILL }},
7141 #endif
7142 { &ei_dcerpc_bind_not_acknowledged, { "dcerpc.bind_not_acknowledged", PI_SEQUENCE, PI_WARN, "Bind not acknowledged", EXPFILL }},
7143 { &ei_dcerpc_verifier_unavailable, { "dcerpc.verifier_unavailable", PI_UNDECODED, PI_WARN, "Verifier unavailable", EXPFILL }},
7144 { &ei_dcerpc_invalid_pdu_authentication_attempt, { "dcerpc.invalid_pdu_authentication_attempt", PI_UNDECODED, PI_WARN, "Invalid authentication attempt", EXPFILL }},
7145 /* Generated from convert_proto_tree_add_text.pl */
7146 { &ei_dcerpc_long_frame, { "dcerpc.long_frame", PI_PROTOCOL, PI_WARN, "Long frame", EXPFILL }},
7147 { &ei_dcerpc_cn_rts_command, { "dcerpc.cn_rts_command.unknown", PI_PROTOCOL, PI_WARN, "unknown RTS command number", EXPFILL }},
7148 { &ei_dcerpc_not_implemented, { "dcerpc.not_implemented", PI_UNDECODED, PI_WARN, "dissection not implemented", EXPFILL }},
7149 };
7150
7151 /* Decode As handling */
7152 static build_valid_func dcerpc_da_build_value[1] = {dcerpc_value};
7153 static decode_as_value_t dcerpc_da_values = {dcerpc_prompt, 1, dcerpc_da_build_value};
7154 static decode_as_t dcerpc_da = {"dcerpc", "dcerpc.uuid",
7155 1, 0, &dcerpc_da_values, NULL, NULL,
7156 dcerpc_populate_list, decode_dcerpc_binding_reset, dcerpc_decode_as_change, dcerpc_decode_as_free};
7157
7158 module_t *dcerpc_module;
7159 expert_module_t* expert_dcerpc;
7160
7161 proto_dcerpc = proto_register_protocol("Distributed Computing Environment / Remote Procedure Call (DCE/RPC)", "DCERPC", "dcerpc");
7162 proto_register_field_array(proto_dcerpc, hf, array_length(hf));
7163 proto_register_subtree_array(ett, array_length(ett));
7164 expert_dcerpc = expert_register_protocol(proto_dcerpc);
7165 expert_register_field_array(expert_dcerpc, ei, array_length(ei));
7166
7167 uuid_dissector_table = register_dissector_table("dcerpc.uuid", "DCE/RPC UUIDs", proto_dcerpc, FT_GUID, BASE_HEX);
7168
7169 /* structures and data for BIND */
7170 dcerpc_binds = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), dcerpc_bind_hash, dcerpc_bind_equal);
7171
7172 dcerpc_auths = wmem_map_new_autoreset(wmem_epan_scope(),
7173 wmem_file_scope(),
7174 dcerpc_auth_context_hash,
7175 dcerpc_auth_context_equal);
7176
7177 /* structures and data for CALL */
7178 dcerpc_cn_calls = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), dcerpc_cn_call_hash, dcerpc_cn_call_equal);
7179 dcerpc_dg_calls = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), dcerpc_dg_call_hash, dcerpc_dg_call_equal);
7180
7181 /* structure and data for MATCHED */
7182 dcerpc_matched = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), dcerpc_matched_hash, dcerpc_matched_equal);
7183
7184 register_init_routine(decode_dcerpc_inject_bindings);
7185
7186 dcerpc_module = prefs_register_protocol(proto_dcerpc, NULL);
7187 prefs_register_bool_preference(dcerpc_module,
7188 "desegment_dcerpc",
7189 "Reassemble DCE/RPC messages spanning multiple TCP segments",
7190 "Whether the DCE/RPC dissector should reassemble messages"
7191 " spanning multiple TCP segments."
7192 " To use this option, you must also enable"
7193 " \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
7194 &dcerpc_cn_desegment);
7195 prefs_register_bool_preference(dcerpc_module,
7196 "reassemble_dcerpc",
7197 "Reassemble DCE/RPC fragments",
7198 "Whether the DCE/RPC dissector should reassemble fragmented DCE/RPC PDUs",
7199 &dcerpc_reassemble);
7200
7201 /*
7202 * XXX - addresses_ports_reassembly_table_functions?
7203 * Or can a single connection-oriented DCE RPC session persist
7204 * over multiple transport layer connections?
7205 */
7206 reassembly_table_register(&dcerpc_co_reassembly_table,
7207 &addresses_reassembly_table_functions);
7208 reassembly_table_register(&dcerpc_cl_reassembly_table,
7209 &dcerpc_cl_reassembly_table_functions);
7210
7211 dcerpc_uuids = g_hash_table_new_full(dcerpc_uuid_hash, dcerpc_uuid_equal, g_free, g_free);
7212 dcerpc_tap = register_tap("dcerpc");
7213
7214 register_decode_as(&dcerpc_da);
7215
7216 register_srt_table(proto_dcerpc, NULL, 1, dcerpcstat_packet, dcerpcstat_init, dcerpcstat_param);
7217
7218 tvb_trailer_signature = tvb_new_real_data(TRAILER_SIGNATURE,
7219 sizeof(TRAILER_SIGNATURE),
7220 sizeof(TRAILER_SIGNATURE));
7221
7222 register_shutdown_routine(dcerpc_shutdown);
7223 }
7224
7225 void
proto_reg_handoff_dcerpc(void)7226 proto_reg_handoff_dcerpc(void)
7227 {
7228 dissector_handle_t dcerpc_tcp_handle;
7229
7230 heur_dissector_add("tcp", dissect_dcerpc_tcp_heur, "DCE/RPC over TCP", "dcerpc_tcp", proto_dcerpc, HEURISTIC_ENABLE);
7231 heur_dissector_add("netbios", dissect_dcerpc_cn_pk, "DCE/RPC over NetBios", "dcerpc_netbios", proto_dcerpc, HEURISTIC_ENABLE);
7232 heur_dissector_add("udp", dissect_dcerpc_dg, "DCE/RPC over UDP", "dcerpc_udp", proto_dcerpc, HEURISTIC_ENABLE);
7233 heur_dissector_add("smb_transact", dissect_dcerpc_cn_smbpipe, "DCE/RPC over SMB", "dcerpc_smb_transact", proto_dcerpc, HEURISTIC_ENABLE);
7234 heur_dissector_add("smb2_pipe_subdissectors", dissect_dcerpc_cn_smb2, "DCE/RPC over SMB2", "dcerpc_smb2", proto_dcerpc, HEURISTIC_ENABLE);
7235 heur_dissector_add("http", dissect_dcerpc_cn_bs, "DCE/RPC over HTTP", "dcerpc_http", proto_dcerpc, HEURISTIC_ENABLE);
7236 dcerpc_smb_init(proto_dcerpc);
7237
7238 dcerpc_tcp_handle = create_dissector_handle(dissect_dcerpc_tcp, proto_dcerpc);
7239 dissector_add_for_decode_as("tcp.port", dcerpc_tcp_handle);
7240
7241 guids_add_uuid(&uuid_data_repr_proto, "32bit NDR");
7242 guids_add_uuid(&uuid_ndr64, "64bit NDR");
7243 guids_add_uuid(&uuid_asyncemsmdb, "async MAPI");
7244 }
7245
7246 /*
7247 * Editor modelines - https://www.wireshark.org/tools/modelines.html
7248 *
7249 * Local variables:
7250 * c-basic-offset: 4
7251 * tab-width: 8
7252 * indent-tabs-mode: nil
7253 * End:
7254 *
7255 * vi: set shiftwidth=4 tabstop=8 expandtab:
7256 * :indentSize=4:tabSize=8:noTabs=true:
7257 */
7258