2 * Routines for DCERPC packet disassembly
3 * Copyright 2001, Todd Sabin <tas@webspan.net>
4 * Copyright 2003, Tim Potter <tpot@samba.org>
8 * Ethereal - Network traffic analyzer
9 * By Gerald Combs <gerald@ethereal.com>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 /* The DCE RPC specification can be found at:
28 * http://www.opengroup.org/dce/
39 #include <epan/packet.h>
40 #include <epan/dissectors/packet-dcerpc.h>
41 #include <epan/conversation.h>
42 #include <epan/prefs.h>
43 #include <epan/reassemble.h>
45 #include <epan/emem.h>
46 #include <epan/dissectors/packet-frame.h>
47 #include <epan/dissectors/packet-dcerpc-nt.h>
48 #include <epan/expert.h>
51 #define MIN(x,y) ((x)<(y))?(x):(y)
54 static int dcerpc_tap = -1;
57 static const value_string pckt_vals[] = {
58 { PDU_REQ, "Request"},
60 { PDU_RESP, "Response"},
61 { PDU_FAULT, "Fault"},
62 { PDU_WORKING, "Working"},
63 { PDU_NOCALL, "Nocall"},
64 { PDU_REJECT, "Reject"},
66 { PDU_CL_CANCEL, "Cl_cancel"},
68 { PDU_CANCEL_ACK, "Cancel_ack"},
70 { PDU_BIND_ACK, "Bind_ack"},
71 { PDU_BIND_NAK, "Bind_nak"},
72 { PDU_ALTER, "Alter_context"},
73 { PDU_ALTER_ACK, "Alter_context_resp"},
74 { PDU_AUTH3, "AUTH3"},
75 { PDU_SHUTDOWN, "Shutdown"},
76 { PDU_CO_CANCEL, "Co_cancel"},
77 { PDU_ORPHANED, "Orphaned"},
81 static const value_string drep_byteorder_vals[] = {
83 { 1, "Little-endian" },
87 static const value_string drep_character_vals[] = {
93 #define DCE_RPC_DREP_FP_IEEE 0
94 #define DCE_RPC_DREP_FP_VAX 1
95 #define DCE_RPC_DREP_FP_CRAY 2
96 #define DCE_RPC_DREP_FP_IBM 3
98 static const value_string drep_fp_vals[] = {
99 { DCE_RPC_DREP_FP_IEEE, "IEEE" },
100 { DCE_RPC_DREP_FP_VAX, "VAX" },
101 { DCE_RPC_DREP_FP_CRAY, "Cray" },
102 { DCE_RPC_DREP_FP_IBM, "IBM" },
107 * Authentication services.
109 static const value_string authn_protocol_vals[] = {
110 { DCE_C_RPC_AUTHN_PROTOCOL_NONE, "None" },
111 { DCE_C_RPC_AUTHN_PROTOCOL_KRB5, "Kerberos 5" },
112 { DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO, "SPNEGO" },
113 { DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP, "NTLMSSP" },
114 { DCE_C_RPC_AUTHN_PROTOCOL_GSS_SCHANNEL, "SCHANNEL SSP" },
115 { DCE_C_RPC_AUTHN_PROTOCOL_GSS_KERBEROS, "Kerberos SSP" },
116 { DCE_C_RPC_AUTHN_PROTOCOL_DPA,
117 "Distributed Password Authentication SSP"},
118 { DCE_C_RPC_AUTHN_PROTOCOL_MSN, "MSN SSP"},
119 { DCE_C_RPC_AUTHN_PROTOCOL_DIGEST, "Digest SSP"},
120 { DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN,"NETLOGON Secure Channel" },
121 { DCE_C_RPC_AUTHN_PROTOCOL_MQ, "MSMQ SSP"},
128 static const value_string authn_level_vals[] = {
129 { DCE_C_AUTHN_LEVEL_NONE, "None" },
130 { DCE_C_AUTHN_LEVEL_CONNECT, "Connect" },
131 { DCE_C_AUTHN_LEVEL_CALL, "Call" },
132 { DCE_C_AUTHN_LEVEL_PKT, "Packet" },
133 { DCE_C_AUTHN_LEVEL_PKT_INTEGRITY, "Packet integrity" },
134 { DCE_C_AUTHN_LEVEL_PKT_PRIVACY, "Packet privacy" },
139 * Flag bits in first flag field in connectionless PDU header.
141 #define PFCL1_RESERVED_01 0x01 /* Reserved for use by implementations */
142 #define PFCL1_LASTFRAG 0x02 /* If set, the PDU is the last
143 * fragment of a multi-PDU
145 #define PFCL1_FRAG 0x04 /* If set, the PDU is a fragment of
146 a multi-PDU transmission */
147 #define PFCL1_NOFACK 0x08 /* If set, the receiver is not
148 * requested to send a `fack' PDU
149 * for the fragment */
150 #define PFCL1_MAYBE 0x10 /* If set, the PDU is for a `maybe'
152 #define PFCL1_IDEMPOTENT 0x20 /* If set, the PDU is for an idempotent
154 #define PFCL1_BROADCAST 0x40 /* If set, the PDU is for a broadcast
156 #define PFCL1_RESERVED_80 0x80 /* Reserved for use by implementations */
159 * Flag bits in second flag field in connectionless PDU header.
161 #define PFCL2_RESERVED_01 0x01 /* Reserved for use by implementations */
162 #define PFCL2_CANCEL_PENDING 0x02 /* Cancel pending at the call end */
163 #define PFCL2_RESERVED_04 0x04 /* Reserved for future use */
164 #define PFCL2_RESERVED_08 0x08 /* Reserved for future use */
165 #define PFCL2_RESERVED_10 0x10 /* Reserved for future use */
166 #define PFCL2_RESERVED_20 0x20 /* Reserved for future use */
167 #define PFCL2_RESERVED_40 0x40 /* Reserved for future use */
168 #define PFCL2_RESERVED_80 0x80 /* Reserved for future use */
171 * Flag bits in connection-oriented PDU header.
173 #define PFC_FIRST_FRAG 0x01 /* First fragment */
174 #define PFC_LAST_FRAG 0x02 /* Last fragment */
175 #define PFC_PENDING_CANCEL 0x04 /* Cancel was pending at sender */
176 #define PFC_RESERVED_1 0x08
177 #define PFC_CONC_MPX 0x10 /* suports concurrent multiplexing
178 * of a single connection. */
179 #define PFC_DID_NOT_EXECUTE 0x20 /* only meaningful on `fault' packet;
180 * if true, guaranteed call did not
182 #define PFC_MAYBE 0x40 /* `maybe' call semantics requested */
183 #define PFC_OBJECT_UUID 0x80 /* if true, a non-nil object UUID
184 * was specified in the handle, and
185 * is present in the optional object
186 * field. If false, the object field
190 * Tests whether a connection-oriented PDU is fragmented; returns TRUE if
191 * it's not fragmented (i.e., this is both the first *and* last fragment),
192 * and FALSE otherwise.
194 #define PFC_NOT_FRAGMENTED(hdr) \
195 ((hdr->flags&(PFC_FIRST_FRAG|PFC_LAST_FRAG))==(PFC_FIRST_FRAG|PFC_LAST_FRAG))
198 * Presentation context negotiation result.
200 static const value_string p_cont_result_vals[] = {
202 { 1, "User rejection" },
203 { 2, "Provider rejection" },
208 * Presentation context negotiation rejection reasons.
210 static const value_string p_provider_reason_vals[] = {
211 { 0, "Reason not specified" },
212 { 1, "Abstract syntax not supported" },
213 { 2, "Proposed transfer syntaxes not supported" },
214 { 3, "Local limit exceeded" },
221 #define REASON_NOT_SPECIFIED 0
222 #define TEMPORARY_CONGESTION 1
223 #define LOCAL_LIMIT_EXCEEDED 2
224 #define CALLED_PADDR_UNKNOWN 3 /* not used */
225 #define PROTOCOL_VERSION_NOT_SUPPORTED 4
226 #define DEFAULT_CONTEXT_NOT_SUPPORTED 5 /* not used */
227 #define USER_DATA_NOT_READABLE 6 /* not used */
228 #define NO_PSAP_AVAILABLE 7 /* not used */
229 #define AUTH_TYPE_NOT_RECOGNIZED 8
230 #define INVALID_CHECKSUM 9
232 static const value_string reject_reason_vals[] = {
233 { REASON_NOT_SPECIFIED, "Reason not specified" },
234 { TEMPORARY_CONGESTION, "Temporary congestion" },
235 { LOCAL_LIMIT_EXCEEDED, "Local limit exceeded" },
236 { CALLED_PADDR_UNKNOWN, "Called paddr unknown" },
237 { PROTOCOL_VERSION_NOT_SUPPORTED, "Protocol version not supported" },
238 { DEFAULT_CONTEXT_NOT_SUPPORTED, "Default context not supported" },
239 { USER_DATA_NOT_READABLE, "User data not readable" },
240 { NO_PSAP_AVAILABLE, "No PSAP available" },
241 { AUTH_TYPE_NOT_RECOGNIZED, "Authentication type not recognized" },
242 { INVALID_CHECKSUM, "Invalid checksum" },
247 * Reject status codes.
249 static const value_string reject_status_vals[] = {
250 { 0, "Stub-defined exception" },
251 { 0x00000001, "nca_s_fault_other" },
252 { 0x00000005, "nca_s_fault_access_denied" },
253 { 0x000006f7, "nca_s_fault_ndr" },
254 { 0x000006d8, "nca_s_fault_cant_perform" },
255 { 0x1c000001, "nca_s_fault_int_div_by_zero" },
256 { 0x1c000002, "nca_s_fault_addr_error" },
257 { 0x1c000003, "nca_s_fault_fp_div_zero" },
258 { 0x1c000004, "nca_s_fault_fp_underflow" },
259 { 0x1c000005, "nca_s_fault_fp_overflow" },
260 { 0x1c000006, "nca_s_fault_invalid_tag" },
261 { 0x1c000007, "nca_s_fault_invalid_bound" },
262 { 0x1c000008, "nca_rpc_version_mismatch" },
263 { 0x1c000009, "nca_unspec_reject" },
264 { 0x1c00000a, "nca_s_bad_actid" },
265 { 0x1c00000b, "nca_who_are_you_failed" },
266 { 0x1c00000c, "nca_manager_not_entered" },
267 { 0x1c00000d, "nca_s_fault_cancel" },
268 { 0x1c00000e, "nca_s_fault_ill_inst" },
269 { 0x1c00000f, "nca_s_fault_fp_error" },
270 { 0x1c000010, "nca_s_fault_int_overflow" },
271 { 0x1c000014, "nca_s_fault_pipe_empty" },
272 { 0x1c000015, "nca_s_fault_pipe_closed" },
273 { 0x1c000016, "nca_s_fault_pipe_order" },
274 { 0x1c000017, "nca_s_fault_pipe_discipline" },
275 { 0x1c000018, "nca_s_fault_pipe_comm_error" },
276 { 0x1c000019, "nca_s_fault_pipe_memory" },
277 { 0x1c00001a, "nca_s_fault_context_mismatch" },
278 { 0x1c00001b, "nca_s_fault_remote_no_memory" },
279 { 0x1c00001c, "nca_invalid_pres_context_id" },
280 { 0x1c00001d, "nca_unsupported_authn_level" },
281 { 0x1c00001f, "nca_invalid_checksum" },
282 { 0x1c000020, "nca_invalid_crc" },
283 { 0x1c000021, "ncs_s_fault_user_defined" },
284 { 0x1c000022, "nca_s_fault_tx_open_failed" },
285 { 0x1c000023, "nca_s_fault_codeset_conv_error" },
286 { 0x1c000024, "nca_s_fault_object_not_found" },
287 { 0x1c000025, "nca_s_fault_no_client_stub" },
288 { 0x1c010002, "nca_op_rng_error" },
289 { 0x1c010003, "nca_unk_if"},
290 { 0x1c010006, "nca_wrong_boot_time" },
291 { 0x1c010009, "nca_s_you_crashed" },
292 { 0x1c01000b, "nca_proto_error" },
293 { 0x1c010013, "nca_out_args_too_big" },
294 { 0x1c010014, "nca_server_too_busy" },
295 { 0x1c010017, "nca_unsupported_type" },
296 /* MS Windows specific values
297 * see: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/system_error_codes__1700-3999_.asp
298 * and: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/seccrypto/security/common_hresult_values.asp
299 * and: http://www.megos.ch/support/doserrors.txt
301 * XXX - we might need a way to dynamically add entries here, as higher layer protocols use these values too,
302 * at least MS protocols (like DCOM) do it that way ... */
303 { 0x80004001, "E_NOTIMPL" },
304 { 0x80004003, "E_POINTER" },
305 { 0x80004004, "E_ABORT" },
306 { 0x80010105, "RPC_E_SERVERFAULT" },
307 { 0x80010108, "RPC_E_DISCONNECTED" },
308 { 0x80010113, "RPC_E_INVALID_IPID" },
309 { 0x80020006, "DISP_E_UNKNOWNNAME" },
310 { 0x8004CB00, "CBA_E_MALFORMED" },
311 { 0x8004CB01, "CBA_E_UNKNOWNOBJECT" },
312 { 0x8004CB09, "CBA_E_INVALIDCOOKIE" },
313 { 0x8004CB0B, "CBA_E_QOSTYPEUNSUPPORTED" },
314 { 0x8004CB0C, "CBA_E_QOSVALUEUNSUPPORTED" },
315 { 0x8004CB0F, "CBA_E_NOTAPPLICABLE" },
316 { 0x8004CB12, "CBA_E_LIMITVIOLATION" },
317 { 0x8007000E, "E_OUTOFMEMORY" },
318 { 0x80070057, "E_INVALIDARG" },
319 { 0x800706d1, "RPC_S_PROCNUM_OUT_OF_RANGE" },
324 /* we need to keep track of what transport were used, ie what handle we came
325 * in through so we know what kind of pinfo->dce_smb_fid was passed to us.
327 /* Value of -1 is reserved for "not DCE packet" in packet_info.dcetransporttype. */
328 #define DCE_TRANSPORT_UNKNOWN 0
329 #define DCE_CN_TRANSPORT_SMBPIPE 1
332 static int proto_dcerpc = -1;
335 static int hf_dcerpc_request_in = -1;
336 static int hf_dcerpc_time = -1;
337 static int hf_dcerpc_response_in = -1;
338 static int hf_dcerpc_ver = -1;
339 static int hf_dcerpc_ver_minor = -1;
340 static int hf_dcerpc_packet_type = -1;
341 static int hf_dcerpc_cn_flags = -1;
342 static int hf_dcerpc_cn_flags_first_frag = -1;
343 static int hf_dcerpc_cn_flags_last_frag = -1;
344 static int hf_dcerpc_cn_flags_cancel_pending = -1;
345 static int hf_dcerpc_cn_flags_reserved = -1;
346 static int hf_dcerpc_cn_flags_mpx = -1;
347 static int hf_dcerpc_cn_flags_dne = -1;
348 static int hf_dcerpc_cn_flags_maybe = -1;
349 static int hf_dcerpc_cn_flags_object = -1;
350 static int hf_dcerpc_drep = -1;
351 static int hf_dcerpc_drep_byteorder = -1;
352 static int hf_dcerpc_drep_character = -1;
353 static int hf_dcerpc_drep_fp = -1;
354 static int hf_dcerpc_cn_frag_len = -1;
355 static int hf_dcerpc_cn_auth_len = -1;
356 static int hf_dcerpc_cn_call_id = -1;
357 static int hf_dcerpc_cn_max_xmit = -1;
358 static int hf_dcerpc_cn_max_recv = -1;
359 static int hf_dcerpc_cn_assoc_group = -1;
360 static int hf_dcerpc_cn_num_ctx_items = -1;
361 static int hf_dcerpc_cn_ctx_id = -1;
362 static int hf_dcerpc_cn_num_trans_items = -1;
363 static int hf_dcerpc_cn_bind_if_id = -1;
364 static int hf_dcerpc_cn_bind_if_ver = -1;
365 static int hf_dcerpc_cn_bind_if_ver_minor = -1;
366 static int hf_dcerpc_cn_bind_trans_id = -1;
367 static int hf_dcerpc_cn_bind_trans_ver = -1;
368 static int hf_dcerpc_cn_alloc_hint = -1;
369 static int hf_dcerpc_cn_sec_addr_len = -1;
370 static int hf_dcerpc_cn_sec_addr = -1;
371 static int hf_dcerpc_cn_num_results = -1;
372 static int hf_dcerpc_cn_ack_result = -1;
373 static int hf_dcerpc_cn_ack_reason = -1;
374 static int hf_dcerpc_cn_ack_trans_id = -1;
375 static int hf_dcerpc_cn_ack_trans_ver = -1;
376 static int hf_dcerpc_cn_reject_reason = -1;
377 static int hf_dcerpc_cn_num_protocols = -1;
378 static int hf_dcerpc_cn_protocol_ver_major = -1;
379 static int hf_dcerpc_cn_protocol_ver_minor = -1;
380 static int hf_dcerpc_cn_cancel_count = -1;
381 static int hf_dcerpc_cn_status = -1;
382 static int hf_dcerpc_cn_deseg_req = -1;
383 static int hf_dcerpc_auth_type = -1;
384 static int hf_dcerpc_auth_level = -1;
385 static int hf_dcerpc_auth_pad_len = -1;
386 static int hf_dcerpc_auth_rsrvd = -1;
387 static int hf_dcerpc_auth_ctx_id = -1;
388 static int hf_dcerpc_dg_flags1 = -1;
389 static int hf_dcerpc_dg_flags1_rsrvd_01 = -1;
390 static int hf_dcerpc_dg_flags1_last_frag = -1;
391 static int hf_dcerpc_dg_flags1_frag = -1;
392 static int hf_dcerpc_dg_flags1_nofack = -1;
393 static int hf_dcerpc_dg_flags1_maybe = -1;
394 static int hf_dcerpc_dg_flags1_idempotent = -1;
395 static int hf_dcerpc_dg_flags1_broadcast = -1;
396 static int hf_dcerpc_dg_flags1_rsrvd_80 = -1;
397 static int hf_dcerpc_dg_flags2 = -1;
398 static int hf_dcerpc_dg_flags2_rsrvd_01 = -1;
399 static int hf_dcerpc_dg_flags2_cancel_pending = -1;
400 static int hf_dcerpc_dg_flags2_rsrvd_04 = -1;
401 static int hf_dcerpc_dg_flags2_rsrvd_08 = -1;
402 static int hf_dcerpc_dg_flags2_rsrvd_10 = -1;
403 static int hf_dcerpc_dg_flags2_rsrvd_20 = -1;
404 static int hf_dcerpc_dg_flags2_rsrvd_40 = -1;
405 static int hf_dcerpc_dg_flags2_rsrvd_80 = -1;
406 static int hf_dcerpc_dg_serial_hi = -1;
407 static int hf_dcerpc_obj_id = -1;
408 static int hf_dcerpc_dg_if_id = -1;
409 static int hf_dcerpc_dg_act_id = -1;
410 static int hf_dcerpc_dg_serial_lo = -1;
411 static int hf_dcerpc_dg_ahint = -1;
412 static int hf_dcerpc_dg_ihint = -1;
413 static int hf_dcerpc_dg_frag_len = -1;
414 static int hf_dcerpc_dg_frag_num = -1;
415 static int hf_dcerpc_dg_auth_proto = -1;
416 static int hf_dcerpc_opnum = -1;
417 static int hf_dcerpc_dg_seqnum = -1;
418 static int hf_dcerpc_dg_server_boot = -1;
419 static int hf_dcerpc_dg_if_ver = -1;
420 static int hf_dcerpc_krb5_av_prot_level = -1;
421 static int hf_dcerpc_krb5_av_key_vers_num = -1;
422 static int hf_dcerpc_krb5_av_key_auth_verifier = -1;
423 static int hf_dcerpc_dg_cancel_vers = -1;
424 static int hf_dcerpc_dg_cancel_id = -1;
425 static int hf_dcerpc_dg_server_accepting_cancels = -1;
426 static int hf_dcerpc_dg_fack_vers = -1;
427 static int hf_dcerpc_dg_fack_window_size = -1;
428 static int hf_dcerpc_dg_fack_max_tsdu = -1;
429 static int hf_dcerpc_dg_fack_max_frag_size = -1;
430 static int hf_dcerpc_dg_fack_serial_num = -1;
431 static int hf_dcerpc_dg_fack_selack_len = -1;
432 static int hf_dcerpc_dg_fack_selack = -1;
433 static int hf_dcerpc_dg_status = -1;
434 static int hf_dcerpc_array_max_count = -1;
435 static int hf_dcerpc_array_offset = -1;
436 static int hf_dcerpc_array_actual_count = -1;
437 static int hf_dcerpc_array_buffer = -1;
438 static int hf_dcerpc_op = -1;
439 static int hf_dcerpc_referent_id = -1;
440 static int hf_dcerpc_fragments = -1;
441 static int hf_dcerpc_fragment = -1;
442 static int hf_dcerpc_fragment_overlap = -1;
443 static int hf_dcerpc_fragment_overlap_conflict = -1;
444 static int hf_dcerpc_fragment_multiple_tails = -1;
445 static int hf_dcerpc_fragment_too_long_fragment = -1;
446 static int hf_dcerpc_fragment_error = -1;
447 static int hf_dcerpc_reassembled_in = -1;
448 static int hf_dcerpc_unknown_if_id = -1;
450 static gint ett_dcerpc = -1;
451 static gint ett_dcerpc_cn_flags = -1;
452 static gint ett_dcerpc_cn_ctx = -1;
453 static gint ett_dcerpc_cn_iface = -1;
454 static gint ett_dcerpc_drep = -1;
455 static gint ett_dcerpc_dg_flags1 = -1;
456 static gint ett_dcerpc_dg_flags2 = -1;
457 static gint ett_dcerpc_pointer_data = -1;
458 static gint ett_dcerpc_string = -1;
459 static gint ett_dcerpc_fragments = -1;
460 static gint ett_dcerpc_fragment = -1;
461 static gint ett_dcerpc_krb5_auth_verf = -1;
463 static const fragment_items dcerpc_frag_items = {
464 &ett_dcerpc_fragments,
465 &ett_dcerpc_fragment,
467 &hf_dcerpc_fragments,
469 &hf_dcerpc_fragment_overlap,
470 &hf_dcerpc_fragment_overlap_conflict,
471 &hf_dcerpc_fragment_multiple_tails,
472 &hf_dcerpc_fragment_too_long_fragment,
473 &hf_dcerpc_fragment_error,
479 /* list of hooks to be called when init_protocols is done */
480 GHookList dcerpc_hooks_init_protos;
483 int ResolveWin32UUID(e_uuid_t if_id, char *UUID_NAME, int UUID_NAME_MAX_LEN)
485 char REG_UUID_NAME[MAX_PATH];
487 DWORD UUID_MAX_SIZE = MAX_PATH;
488 char REG_UUID_STR[MAX_PATH];
490 if(UUID_NAME_MAX_LEN < 2)
492 REG_UUID_NAME[0] = '\0';
493 g_snprintf(REG_UUID_STR, MAX_PATH, "SOFTWARE\\Classes\\Interface\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
494 if_id.Data1, if_id.Data2, if_id.Data3,
495 if_id.Data4[0], if_id.Data4[1],
496 if_id.Data4[2], if_id.Data4[3],
497 if_id.Data4[4], if_id.Data4[5],
498 if_id.Data4[6], if_id.Data4[7]);
499 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCSTR)REG_UUID_STR, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
501 if (RegQueryValueEx(hKey, NULL, NULL, NULL, (LPBYTE)REG_UUID_NAME, &UUID_MAX_SIZE) == ERROR_SUCCESS && UUID_MAX_SIZE <= MAX_PATH)
503 g_snprintf(UUID_NAME, UUID_NAME_MAX_LEN, "%s", REG_UUID_NAME);
505 return strlen(REG_UUID_NAME);
509 return 0; /* we didn't find anything anyhow. Please don't use the string! */
517 static dcerpc_info di[20];
518 static int di_counter=0;
524 return &di[di_counter];
527 /* try to desegment big DCE/RPC packets over TCP? */
528 static gboolean dcerpc_cn_desegment = TRUE;
530 /* reassemble DCE/RPC fragments */
531 /* reassembly of cl dcerpc fragments will not work for the case where ONE frame
532 might contain multiple dcerpc fragments for different PDUs.
533 this case would be so unusual/weird so if you got captures like that:
536 reassembly of co dcerpc fragments will not work for the case where TCP/SMB frames
537 are coming in out of sequence, but that will hurt in a lot of other places as well.
539 static gboolean dcerpc_reassemble = TRUE;
540 static GHashTable *dcerpc_co_fragment_table = NULL;
541 static GHashTable *dcerpc_co_reassemble_table = NULL;
542 static GHashTable *dcerpc_cl_reassemble_table = NULL;
545 dcerpc_reassemble_init(void)
547 fragment_table_init(&dcerpc_co_fragment_table);
548 reassembled_table_init(&dcerpc_co_reassemble_table);
549 dcerpc_fragment_table_init(&dcerpc_cl_reassemble_table);
553 * Authentication subdissectors. Used to dissect authentication blobs in
554 * DCERPC binds, requests and responses.
557 typedef struct _dcerpc_auth_subdissector {
560 dcerpc_auth_subdissector_fns auth_fns;
561 } dcerpc_auth_subdissector;
563 static GSList *dcerpc_auth_subdissector_list;
565 static dcerpc_auth_subdissector_fns *get_auth_subdissector_fns(
566 guint8 auth_level, guint8 auth_type)
571 for (i = 0; (data = g_slist_nth_data(dcerpc_auth_subdissector_list, i)); i++) {
572 dcerpc_auth_subdissector *asd = (dcerpc_auth_subdissector *)data;
574 if (asd->auth_level == auth_level &&
575 asd->auth_type == auth_type)
576 return &asd->auth_fns;
582 void register_dcerpc_auth_subdissector(guint8 auth_level, guint8 auth_type,
583 dcerpc_auth_subdissector_fns *fns)
585 dcerpc_auth_subdissector *d;
587 if (get_auth_subdissector_fns(auth_level, auth_type))
590 d = (dcerpc_auth_subdissector *)g_malloc(sizeof(dcerpc_auth_subdissector));
592 d->auth_level = auth_level;
593 d->auth_type = auth_type;
594 memcpy(&d->auth_fns, fns, sizeof(dcerpc_auth_subdissector_fns));
596 dcerpc_auth_subdissector_list = g_slist_append(dcerpc_auth_subdissector_list, d);
599 /* Hand off verifier data to a registered dissector */
601 static void dissect_auth_verf(tvbuff_t *auth_tvb, packet_info *pinfo,
603 dcerpc_auth_subdissector_fns *auth_fns,
604 e_dce_cn_common_hdr_t *hdr,
605 dcerpc_auth_info *auth_info)
607 dcerpc_dissect_fnct_t *volatile fn = NULL;
609 switch (hdr->ptype) {
612 fn = auth_fns->bind_fn;
616 fn = auth_fns->bind_ack_fn;
619 fn = auth_fns->auth3_fn;
622 fn = auth_fns->req_verf_fn;
625 fn = auth_fns->resp_verf_fn;
628 /* Don't know how to handle authentication data in this
632 g_warning("attempt to dissect %s pdu authentication data",
633 val_to_str(hdr->ptype, pckt_vals, "Unknown (%u)"));
638 fn(auth_tvb, 0, pinfo, tree, hdr->drep);
640 tvb_ensure_bytes_exist(auth_tvb, 0, hdr->auth_len);
641 proto_tree_add_text(tree, auth_tvb, 0, hdr->auth_len,
643 val_to_str(auth_info->auth_type,
649 /* Hand off payload data to a registered dissector */
651 static tvbuff_t *decode_encrypted_data(tvbuff_t *data_tvb,
654 dcerpc_auth_subdissector_fns *auth_fns,
656 dcerpc_auth_info *auth_info)
658 dcerpc_decode_data_fnct_t *fn;
661 fn = auth_fns->req_data_fn;
663 fn = auth_fns->resp_data_fn;
666 return fn(data_tvb, auth_tvb, 0, pinfo, auth_info);
675 /* the registered subdissectors */
676 GHashTable *dcerpc_uuids=NULL;
679 dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2)
681 const dcerpc_uuid_key *key1 = (const dcerpc_uuid_key *)k1;
682 const dcerpc_uuid_key *key2 = (const dcerpc_uuid_key *)k2;
683 return ((memcmp (&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
684 && (key1->ver == key2->ver));
688 dcerpc_uuid_hash (gconstpointer k)
690 const dcerpc_uuid_key *key = (const dcerpc_uuid_key *)k;
691 /* This isn't perfect, but the Data1 part of these is almost always
693 return key->uuid.Data1;
697 dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver,
698 dcerpc_sub_dissector *procs, int opnum_hf)
700 dcerpc_uuid_key *key = g_malloc (sizeof (*key));
701 dcerpc_uuid_value *value = g_malloc (sizeof (*value));
702 header_field_info *hf_info;
707 value->proto = find_protocol_by_id(proto);
708 value->proto_id = proto;
710 value->name = proto_get_protocol_short_name (value->proto);
711 value->procs = procs;
712 value->opnum_hf = opnum_hf;
714 g_hash_table_insert (dcerpc_uuids, key, value);
716 hf_info = proto_registrar_get_nth(opnum_hf);
717 hf_info->strings = value_string_from_subdissectors(procs);
721 /* try to get registered name for this uuid */
722 const gchar *dcerpc_get_uuid_name(e_uuid_t *uuid, guint16 ver)
725 dcerpc_uuid_value *sub_proto;
728 /* try to get registered uuid "name" of if_id */
732 if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) != NULL
733 && proto_is_protocol_enabled(sub_proto->proto)) {
735 return sub_proto->name;
742 /* Function to find the name of a registered protocol
743 * or NULL if the protocol/version is not known to ethereal.
746 dcerpc_get_proto_name(e_uuid_t *uuid, guint16 ver)
749 dcerpc_uuid_value *sub_proto;
753 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
756 return sub_proto->name;
759 /* Function to find the opnum hf-field of a registered protocol
760 * or -1 if the protocol/version is not known to ethereal.
763 dcerpc_get_proto_hf_opnum(e_uuid_t *uuid, guint16 ver)
766 dcerpc_uuid_value *sub_proto;
770 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
773 return sub_proto->opnum_hf;
776 /* Create a value_string consisting of DCERPC opnum and name from a
777 subdissector array. */
779 value_string *value_string_from_subdissectors(dcerpc_sub_dissector *sd)
781 value_string *vs = NULL;
785 for (i = 0; sd[i].name; i++) {
787 vs[i].value = sd[i].num;
788 vs[i].strptr = sd[i].name;
794 vs = g_malloc((num_sd + 1) * sizeof(value_string));
798 vs[num_sd].value = 0;
799 vs[num_sd].strptr = NULL;
804 /* Function to find the subdissector table of a registered protocol
805 * or NULL if the protocol/version is not known to ethereal.
807 dcerpc_sub_dissector *
808 dcerpc_get_proto_sub_dissector(e_uuid_t *uuid, guint16 ver)
811 dcerpc_uuid_value *sub_proto;
815 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
818 return sub_proto->procs;
823 * To keep track of ctx_id mappings.
825 * Everytime we see a bind call we update this table.
826 * Note that we always specify a SMB FID. For non-SMB transports this
829 static GHashTable *dcerpc_binds=NULL;
831 typedef struct _dcerpc_bind_key {
832 conversation_t *conv;
837 typedef struct _dcerpc_bind_value {
843 dcerpc_bind_equal (gconstpointer k1, gconstpointer k2)
845 const dcerpc_bind_key *key1 = (const dcerpc_bind_key *)k1;
846 const dcerpc_bind_key *key2 = (const dcerpc_bind_key *)k2;
847 return (key1->conv == key2->conv
848 && key1->ctx_id == key2->ctx_id
849 && key1->smb_fid == key2->smb_fid);
853 dcerpc_bind_hash (gconstpointer k)
855 const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
858 hash=GPOINTER_TO_UINT(key->conv) + key->ctx_id + key->smb_fid;
864 * To keep track of callid mappings. Should really use some generic
865 * conversation support instead.
867 static GHashTable *dcerpc_cn_calls=NULL;
868 static GHashTable *dcerpc_dg_calls=NULL;
870 typedef struct _dcerpc_cn_call_key {
871 conversation_t *conv;
874 } dcerpc_cn_call_key;
876 typedef struct _dcerpc_dg_call_key {
877 conversation_t *conv;
880 } dcerpc_dg_call_key;
884 dcerpc_cn_call_equal (gconstpointer k1, gconstpointer k2)
886 const dcerpc_cn_call_key *key1 = (const dcerpc_cn_call_key *)k1;
887 const dcerpc_cn_call_key *key2 = (const dcerpc_cn_call_key *)k2;
888 return (key1->conv == key2->conv
889 && key1->call_id == key2->call_id
890 && key1->smb_fid == key2->smb_fid);
894 dcerpc_dg_call_equal (gconstpointer k1, gconstpointer k2)
896 const dcerpc_dg_call_key *key1 = (const dcerpc_dg_call_key *)k1;
897 const dcerpc_dg_call_key *key2 = (const dcerpc_dg_call_key *)k2;
898 return (key1->conv == key2->conv
899 && key1->seqnum == key2->seqnum
900 && (memcmp (&key1->act_id, &key2->act_id, sizeof (e_uuid_t)) == 0));
904 dcerpc_cn_call_hash (gconstpointer k)
906 const dcerpc_cn_call_key *key = (const dcerpc_cn_call_key *)k;
907 return GPOINTER_TO_UINT(key->conv) + key->call_id + key->smb_fid;
911 dcerpc_dg_call_hash (gconstpointer k)
913 const dcerpc_dg_call_key *key = (const dcerpc_dg_call_key *)k;
914 return (GPOINTER_TO_UINT(key->conv) + key->seqnum + key->act_id.Data1
915 + (key->act_id.Data2 << 16) + key->act_id.Data3
916 + (key->act_id.Data4[0] << 24) + (key->act_id.Data4[1] << 16)
917 + (key->act_id.Data4[2] << 8) + (key->act_id.Data4[3] << 0)
918 + (key->act_id.Data4[4] << 24) + (key->act_id.Data4[5] << 16)
919 + (key->act_id.Data4[6] << 8) + (key->act_id.Data4[7] << 0));
922 /* to keep track of matched calls/responses
923 this one uses the same value struct as calls, but the key is the frame id
924 and call id; there can be more than one call in a frame.
926 XXX - why not just use the same keys as are used for calls?
929 static GHashTable *dcerpc_matched=NULL;
931 typedef struct _dcerpc_matched_key {
934 } dcerpc_matched_key;
937 dcerpc_matched_equal (gconstpointer k1, gconstpointer k2)
939 const dcerpc_matched_key *key1 = (const dcerpc_matched_key *)k1;
940 const dcerpc_matched_key *key2 = (const dcerpc_matched_key *)k2;
941 return (key1->frame == key2->frame
942 && key1->call_id == key2->call_id);
946 dcerpc_matched_hash (gconstpointer k)
948 const dcerpc_matched_key *key = (const dcerpc_matched_key *)k;
955 * Utility functions. Modeled after packet-rpc.c
959 dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
960 proto_tree *tree, guint8 *drep,
961 int hfindex, guint8 *pdata)
965 data = tvb_get_guint8 (tvb, offset);
967 proto_tree_add_item (tree, hfindex, tvb, offset, 1, (drep[0] & 0x10));
975 dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
976 proto_tree *tree, guint8 *drep,
977 int hfindex, guint16 *pdata)
981 data = ((drep[0] & 0x10)
982 ? tvb_get_letohs (tvb, offset)
983 : tvb_get_ntohs (tvb, offset));
986 proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10));
994 dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
995 proto_tree *tree, guint8 *drep,
996 int hfindex, guint32 *pdata)
1000 data = ((drep[0] & 0x10)
1001 ? tvb_get_letohl (tvb, offset)
1002 : tvb_get_ntohl (tvb, offset));
1005 proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10));
1012 /* handles 32 bit unix time_t */
1014 dissect_dcerpc_time_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1015 proto_tree *tree, guint8 *drep,
1016 int hfindex, guint32 *pdata)
1021 data = ((drep[0] & 0x10)
1022 ? tvb_get_letohl (tvb, offset)
1023 : tvb_get_ntohl (tvb, offset));
1028 if(data==0xffffffff){
1029 /* special case, no time specified */
1030 proto_tree_add_time_format(tree, hfindex, tvb, offset, 4, &tv, "%s: No time specified", proto_registrar_get_nth(hfindex)->name);
1032 proto_tree_add_time (tree, hfindex, tvb, offset, 4, &tv);
1042 dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1043 proto_tree *tree, guint8 *drep,
1044 int hfindex, guint64 *pdata)
1048 data = ((drep[0] & 0x10)
1049 ? tvb_get_letoh64 (tvb, offset)
1050 : tvb_get_ntoh64 (tvb, offset));
1053 proto_tree_add_item(tree, hfindex, tvb, offset, 8, (drep[0] & 0x10));
1062 dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1063 proto_tree *tree, guint8 *drep,
1064 int hfindex, gfloat *pdata)
1070 case(DCE_RPC_DREP_FP_IEEE):
1071 data = ((drep[0] & 0x10)
1072 ? tvb_get_letohieee_float(tvb, offset)
1073 : tvb_get_ntohieee_float(tvb, offset));
1075 proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
1078 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
1079 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1080 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
1082 /* ToBeDone: non IEEE floating formats */
1083 /* Set data to a negative infinity value */
1086 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep[1]);
1096 dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1097 proto_tree *tree, guint8 *drep,
1098 int hfindex, gdouble *pdata)
1104 case(DCE_RPC_DREP_FP_IEEE):
1105 data = ((drep[0] & 0x10)
1106 ? tvb_get_letohieee_double(tvb, offset)
1107 : tvb_get_ntohieee_double(tvb, offset));
1109 proto_tree_add_double(tree, hfindex, tvb, offset, 8, data);
1112 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
1113 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1114 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
1116 /* ToBeDone: non IEEE double formats */
1117 /* Set data to a negative infinity value */
1118 data = -G_MAXDOUBLE;
1120 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep[1]);
1130 dissect_dcerpc_uuid_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1131 proto_tree *tree, char *drep,
1132 int hfindex, e_uuid_t *pdata)
1135 header_field_info* hfi;
1141 dcerpc_tvb_get_uuid (tvb, offset, drep, &uuid);
1143 /* get name of protocol field to prepend it later */
1144 hfi = proto_registrar_get_nth(hfindex);
1147 /* XXX - get the name won't work correct, as we don't know the version of this uuid (if it has one) */
1148 /* look for a registered uuid name */
1149 uuid_name = dcerpc_get_uuid_name(&uuid, 0);
1152 /* we know the name of this uuid */
1153 proto_tree_add_string_format (tree, hfindex, tvb, offset, 16, "",
1154 "%s: %s (%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x)",
1155 hfi->name, uuid_name,
1156 uuid.Data1, uuid.Data2, uuid.Data3,
1157 uuid.Data4[0], uuid.Data4[1],
1158 uuid.Data4[2], uuid.Data4[3],
1159 uuid.Data4[4], uuid.Data4[5],
1160 uuid.Data4[6], uuid.Data4[7]);
1163 /* GUID have changed from FT_STRING to FT_GUID
1164 but we havent changed all dissectors yet.
1166 if(hfi->type==FT_GUID){
1167 proto_tree_add_item(tree, hfindex, tvb, offset, 16, (drep[0] & 0x10));
1169 /* we don't know the name of this uuid */
1170 proto_tree_add_string_format (tree, hfindex, tvb, offset, 16, "",
1171 "%s: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1173 uuid.Data1, uuid.Data2, uuid.Data3,
1174 uuid.Data4[0], uuid.Data4[1],
1175 uuid.Data4[2], uuid.Data4[3],
1176 uuid.Data4[4], uuid.Data4[5],
1177 uuid.Data4[6], uuid.Data4[7]);
1191 * a couple simpler things
1194 dcerpc_tvb_get_ntohs (tvbuff_t *tvb, gint offset, guint8 *drep)
1196 if (drep[0] & 0x10) {
1197 return tvb_get_letohs (tvb, offset);
1199 return tvb_get_ntohs (tvb, offset);
1204 dcerpc_tvb_get_ntohl (tvbuff_t *tvb, gint offset, guint8 *drep)
1206 if (drep[0] & 0x10) {
1207 return tvb_get_letohl (tvb, offset);
1209 return tvb_get_ntohl (tvb, offset);
1214 dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, guint8 *drep, e_uuid_t *uuid)
1217 uuid->Data1 = dcerpc_tvb_get_ntohl (tvb, offset, drep);
1218 uuid->Data2 = dcerpc_tvb_get_ntohs (tvb, offset+4, drep);
1219 uuid->Data3 = dcerpc_tvb_get_ntohs (tvb, offset+6, drep);
1221 for (i=0; i<sizeof (uuid->Data4); i++) {
1222 uuid->Data4[i] = tvb_get_guint8 (tvb, offset+8+i);
1229 /* function to dissect a unidimensional conformant array */
1231 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1232 proto_tree *tree, guint8 *drep,
1233 dcerpc_dissect_fnct_t *fnct)
1239 di=pinfo->private_data;
1240 if(di->conformant_run){
1241 /* conformant run, just dissect the max_count header */
1243 di->conformant_run=0;
1244 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1245 hf_dcerpc_array_max_count, &di->array_max_count);
1246 di->array_max_count_offset=offset-4;
1247 di->conformant_run=1;
1248 di->conformant_eaten=offset-old_offset;
1250 /* we don't remember where in the bytestream this field was */
1251 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1253 /* real run, dissect the elements */
1254 for(i=0;i<di->array_max_count;i++){
1255 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1261 /* function to dissect a unidimensional conformant and varying array */
1263 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1264 proto_tree *tree, guint8 *drep,
1265 dcerpc_dissect_fnct_t *fnct)
1271 di=pinfo->private_data;
1272 if(di->conformant_run){
1273 /* conformant run, just dissect the max_count header */
1275 di->conformant_run=0;
1276 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1277 hf_dcerpc_array_max_count, &di->array_max_count);
1278 di->array_max_count_offset=offset-4;
1279 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1280 hf_dcerpc_array_offset, &di->array_offset);
1281 di->array_offset_offset=offset-4;
1282 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1283 hf_dcerpc_array_actual_count, &di->array_actual_count);
1284 di->array_actual_count_offset=offset-4;
1285 di->conformant_run=1;
1286 di->conformant_eaten=offset-old_offset;
1288 /* we dont dont remember where in the bytestream these fields were */
1289 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1290 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
1291 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
1293 /* real run, dissect the elements */
1294 for(i=0;i<di->array_actual_count;i++){
1295 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1301 /* function to dissect a unidimensional varying array */
1303 dissect_ndr_uvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1304 proto_tree *tree, guint8 *drep,
1305 dcerpc_dissect_fnct_t *fnct)
1311 di=pinfo->private_data;
1312 if(di->conformant_run){
1313 /* conformant run, just dissect the max_count header */
1315 di->conformant_run=0;
1316 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1317 hf_dcerpc_array_offset, &di->array_offset);
1318 di->array_offset_offset=offset-4;
1319 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1320 hf_dcerpc_array_actual_count, &di->array_actual_count);
1321 di->array_actual_count_offset=offset-4;
1322 di->conformant_run=1;
1323 di->conformant_eaten=offset-old_offset;
1325 /* we dont dont remember where in the bytestream these fields were */
1326 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
1327 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
1329 /* real run, dissect the elements */
1330 for(i=0;i<di->array_actual_count;i++){
1331 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1338 /* Dissect an string of bytes. This corresponds to
1339 IDL of the form '[string] byte *foo'.
1341 It can also be used for a conformant varying array of bytes if
1342 the contents of the array should be shown as a big blob, rather
1343 than showing each byte as an individual element.
1345 XXX - which of those is really the IDL type for, for example,
1346 the encrypted data in some MAPI packets? (Microsoft haven't
1349 XXX - does this need to do all the conformant array stuff that
1350 "dissect_ndr_ucvarray()" does? These are presumably for strings
1351 that are conformant and varying - they're stored like conformant
1352 varying arrays of bytes. */
1354 dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo,
1355 proto_tree *tree, guint8 *drep)
1360 di=pinfo->private_data;
1361 if(di->conformant_run){
1362 /* just a run to handle conformant arrays, no scalars to dissect */
1366 /* NDR array header */
1368 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1369 hf_dcerpc_array_max_count, NULL);
1371 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1372 hf_dcerpc_array_offset, NULL);
1374 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1375 hf_dcerpc_array_actual_count, &len);
1378 tvb_ensure_bytes_exist(tvb, offset, len);
1379 proto_tree_add_item(tree, hf_dcerpc_array_buffer,
1380 tvb, offset, len, drep[0] & 0x10);
1388 /* For dissecting arrays that are to be interpreted as strings. */
1390 /* Dissect an NDR conformant varying string of elements.
1391 The length of each element is given by the 'size_is' parameter;
1392 the elements are assumed to be characters or wide characters.
1394 XXX - does this need to do all the conformant array stuff that
1395 "dissect_ndr_ucvarray()" does? */
1397 dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1398 proto_tree *tree, guint8 *drep, int size_is,
1399 int hfindex, gboolean add_subtree, char **data)
1402 proto_item *string_item;
1403 proto_tree *string_tree;
1404 guint32 len, buffer_len;
1406 header_field_info *hfinfo;
1408 di=pinfo->private_data;
1409 if(di->conformant_run){
1410 /* just a run to handle conformant arrays, no scalars to dissect */
1415 string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1416 proto_registrar_get_name(hfindex));
1417 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1423 /* NDR array header */
1425 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1426 hf_dcerpc_array_max_count, NULL);
1428 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1429 hf_dcerpc_array_offset, NULL);
1431 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1432 hf_dcerpc_array_actual_count, &len);
1434 buffer_len = size_is * len;
1437 if (offset % size_is)
1438 offset += size_is - (offset % size_is);
1440 if (size_is == sizeof(guint16)) {
1441 /* XXX - use drep to determine the byte order? */
1442 s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
1444 * XXX - we don't support a string type with Unicode
1445 * characters, so if this is a string item, we make
1446 * its value be the "fake Unicode" string.
1448 if (tree && buffer_len) {
1449 hfinfo = proto_registrar_get_nth(hfindex);
1450 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1451 if (hfinfo->type == FT_STRING) {
1452 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1455 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1456 buffer_len, drep[0] & 0x10);
1461 * "tvb_get_string()" throws an exception if the entire string
1462 * isn't in the tvbuff. If the length is bogus, this should
1463 * keep us from trying to allocate an immensely large buffer.
1464 * (It won't help if the length is *valid* but immensely large,
1465 * but that's another matter; in any case, that would happen only
1466 * if we had an immensely large tvbuff....)
1468 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1469 s = tvb_get_string(tvb, offset, buffer_len);
1470 if (tree && buffer_len)
1471 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1472 buffer_len, drep[0] & 0x10);
1475 if (string_item != NULL)
1476 proto_item_append_text(string_item, ": %s", s);
1483 offset += buffer_len;
1485 proto_item_set_end(string_item, tvb, offset);
1490 /* Dissect an conformant varying string of chars.
1491 This corresponds to IDL of the form '[string] char *foo'.
1493 XXX - at least according to the DCE RPC 1.1 spec, a string has
1494 a null terminator, which isn't necessary as a terminator for
1495 the transfer language (as there's a length), but is presumably
1496 there for the benefit of null-terminated-string languages
1497 such as C. Is this ever used for purely counted strings?
1498 (Not that it matters if it is.) */
1500 dissect_ndr_char_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1501 proto_tree *tree, guint8 *drep)
1504 di=pinfo->private_data;
1506 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1507 sizeof(guint8), di->hf_index,
1511 /* Dissect a conformant varying string of wchars (wide characters).
1512 This corresponds to IDL of the form '[string] wchar *foo'
1514 XXX - at least according to the DCE RPC 1.1 spec, a string has
1515 a null terminator, which isn't necessary as a terminator for
1516 the transfer language (as there's a length), but is presumably
1517 there for the benefit of null-terminated-string languages
1518 such as C. Is this ever used for purely counted strings?
1519 (Not that it matters if it is.) */
1521 dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1522 proto_tree *tree, guint8 *drep)
1525 di=pinfo->private_data;
1527 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1528 sizeof(guint16), di->hf_index,
1532 /* Dissect an NDR varying string of elements.
1533 The length of each element is given by the 'size_is' parameter;
1534 the elements are assumed to be characters or wide characters.
1537 dissect_ndr_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1538 proto_tree *tree, guint8 *drep, int size_is,
1539 int hfindex, gboolean add_subtree, char **data)
1542 proto_item *string_item;
1543 proto_tree *string_tree;
1544 guint32 len, buffer_len;
1546 header_field_info *hfinfo;
1548 di=pinfo->private_data;
1549 if(di->conformant_run){
1550 /* just a run to handle conformant arrays, no scalars to dissect */
1555 string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1556 proto_registrar_get_name(hfindex));
1557 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1563 /* NDR array header */
1564 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1565 hf_dcerpc_array_offset, NULL);
1567 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1568 hf_dcerpc_array_actual_count, &len);
1570 buffer_len = size_is * len;
1573 if (offset % size_is)
1574 offset += size_is - (offset % size_is);
1576 if (size_is == sizeof(guint16)) {
1577 /* XXX - use drep to determine the byte order? */
1578 s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
1580 * XXX - we don't support a string type with Unicode
1581 * characters, so if this is a string item, we make
1582 * its value be the "fake Unicode" string.
1584 if (tree && buffer_len) {
1585 hfinfo = proto_registrar_get_nth(hfindex);
1586 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1587 if (hfinfo->type == FT_STRING) {
1588 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1591 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1592 buffer_len, drep[0] & 0x10);
1597 * "tvb_get_string()" throws an exception if the entire string
1598 * isn't in the tvbuff. If the length is bogus, this should
1599 * keep us from trying to allocate an immensely large buffer.
1600 * (It won't help if the length is *valid* but immensely large,
1601 * but that's another matter; in any case, that would happen only
1602 * if we had an immensely large tvbuff....)
1604 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1605 s = tvb_get_string(tvb, offset, buffer_len);
1606 if (tree && buffer_len)
1607 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1608 buffer_len, drep[0] & 0x10);
1611 if (string_item != NULL)
1612 proto_item_append_text(string_item, ": %s", s);
1619 offset += buffer_len;
1621 proto_item_set_end(string_item, tvb, offset);
1625 /* Dissect an varying string of chars.
1626 This corresponds to IDL of the form '[string] char *foo'.
1628 XXX - at least according to the DCE RPC 1.1 spec, a string has
1629 a null terminator, which isn't necessary as a terminator for
1630 the transfer language (as there's a length), but is presumably
1631 there for the benefit of null-terminated-string languages
1632 such as C. Is this ever used for purely counted strings?
1633 (Not that it matters if it is.) */
1635 dissect_ndr_char_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1636 proto_tree *tree, guint8 *drep)
1639 di=pinfo->private_data;
1641 return dissect_ndr_vstring(tvb, offset, pinfo, tree, drep,
1642 sizeof(guint8), di->hf_index,
1646 /* Dissect a varying string of wchars (wide characters).
1647 This corresponds to IDL of the form '[string] wchar *foo'
1649 XXX - at least according to the DCE RPC 1.1 spec, a string has
1650 a null terminator, which isn't necessary as a terminator for
1651 the transfer language (as there's a length), but is presumably
1652 there for the benefit of null-terminated-string languages
1653 such as C. Is this ever used for purely counted strings?
1654 (Not that it matters if it is.) */
1656 dissect_ndr_wchar_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1657 proto_tree *tree, guint8 *drep)
1660 di=pinfo->private_data;
1662 return dissect_ndr_vstring(tvb, offset, pinfo, tree, drep,
1663 sizeof(guint16), di->hf_index,
1668 /* ndr pointer handling */
1669 /* list of pointers encountered so far */
1670 static GSList *ndr_pointer_list = NULL;
1672 /* position where in the list to insert newly encountered pointers */
1673 static int ndr_pointer_list_pos=0;
1675 /* boolean controlling whether pointers are top-level or embedded */
1676 static gboolean pointers_are_top_level = TRUE;
1678 /* as a kludge, we represent all embedded reference pointers as id==-1
1679 hoping that his will not collide with any non-ref pointers */
1680 typedef struct ndr_pointer_data {
1682 proto_item *item; /* proto_item for pointer */
1683 proto_tree *tree; /* subtree of above item */
1684 dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
1686 dcerpc_callback_fnct_t *callback;
1687 void *callback_args;
1688 } ndr_pointer_data_t;
1691 init_ndr_pointer_list(packet_info *pinfo)
1695 di=pinfo->private_data;
1696 di->conformant_run=0;
1698 while(ndr_pointer_list){
1699 ndr_pointer_data_t *npd;
1701 npd=g_slist_nth_data(ndr_pointer_list, 0);
1702 ndr_pointer_list=g_slist_remove(ndr_pointer_list, npd);
1708 ndr_pointer_list=NULL;
1709 ndr_pointer_list_pos=0;
1710 pointers_are_top_level=TRUE;
1714 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, guint8 *drep)
1716 int found_new_pointer;
1722 di=pinfo->private_data;
1726 found_new_pointer=0;
1727 len=g_slist_length(ndr_pointer_list);
1728 for(i=next_pointer;i<len;i++){
1729 ndr_pointer_data_t *tnpd;
1730 tnpd=g_slist_nth_data(ndr_pointer_list, i);
1732 dcerpc_dissect_fnct_t *fnct;
1735 found_new_pointer=1;
1738 ndr_pointer_list_pos=i+1;
1739 di->hf_index=tnpd->hf_index;
1740 /* first a run to handle any conformant
1742 di->conformant_run=1;
1743 di->conformant_eaten=0;
1744 old_offset = offset;
1745 offset = (*(fnct))(tvb, offset, pinfo, NULL, drep);
1747 DISSECTOR_ASSERT((offset-old_offset)==di->conformant_eaten);
1748 /* This is to check for any bugs in the dissectors.
1750 * Basically, the NDR representation will store all
1751 * arrays in two blocks, one block with the dimension
1752 * discreption, like size, number of elements and such,
1753 * and another block that contains the actual data stored
1755 * If the array is embedded directly inside another,
1756 * encapsulating aggregate type, like a union or struct,
1757 * then these two blocks will be stored at different places
1758 * in the bytestream, with other data between the blocks.
1760 * For this reason, all pointers to types (both aggregate
1761 * and scalar, for simplicity no distinction is made)
1762 * will have its dissector called twice.
1763 * The dissector will first be called with conformant_run==1
1764 * in which mode the dissector MUST NOT consume any data from
1765 * the tvbuff (i.e. may not dissect anything) except the
1766 * initial control block for arrays.
1767 * The second time the dissector is called, with
1768 * conformant_run==0, all other data for the type will be
1771 * All dissect_ndr_<type> dissectors are already prepared
1772 * for this and knows when it should eat data from the tvb
1773 * and when not to, so implementors of dissectors will
1774 * normally not need to worry about this or even know about
1775 * it. However, if a dissector for an aggregate type calls
1776 * a subdissector from outside packet-dcerpc.c, such as
1777 * the dissector in packet-smb.c for NT Security Descriptors
1778 * as an example, then it is VERY important to encapsulate
1779 * this call to an external subdissector with the appropriate
1780 * test for conformant_run, i.e. it will need something like
1784 * di=pinfo->private_data;
1785 * if(di->conformant_run){
1789 * to make sure it makes the right thing.
1790 * This assert will signal when someone has forgotten to
1791 * make the dissector aware of this requirement.
1794 /* now we dissect the actual pointer */
1795 di->conformant_run=0;
1796 old_offset = offset;
1797 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, drep);
1799 tnpd->callback(pinfo, tnpd->tree, tnpd->item, tvb, old_offset, offset, tnpd->callback_args);
1803 } while(found_new_pointer);
1810 add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
1811 dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index,
1812 dcerpc_callback_fnct_t *callback, void *callback_args)
1814 ndr_pointer_data_t *npd;
1816 /* check if this pointer is valid */
1819 dcerpc_call_value *value;
1821 di=pinfo->private_data;
1822 value=di->call_data;
1824 if(di->ptype == PDU_REQ){
1825 if(!(pinfo->fd->flags.visited)){
1826 if(id>value->max_ptr){
1831 /* if we havent seen the request bail out since we cant
1832 know whether this is the first non-NULL instance
1834 if(value->req_frame==0){
1835 /* XXX THROW EXCEPTION */
1838 /* We saw this one in the request frame, nothing to
1840 if(id<=value->max_ptr){
1846 npd=g_malloc(sizeof(ndr_pointer_data_t));
1851 npd->hf_index=hf_index;
1852 npd->callback=callback;
1853 npd->callback_args=callback_args;
1854 ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
1855 ndr_pointer_list_pos);
1856 ndr_pointer_list_pos++;
1861 find_pointer_index(guint32 id)
1863 ndr_pointer_data_t *npd;
1866 len=g_slist_length(ndr_pointer_list);
1868 npd=g_slist_nth_data(ndr_pointer_list, i);
1879 /* This function dissects an NDR pointer and stores the callback for later
1880 * deferred dissection.
1882 * fnct is the callback function for when we have reached this object in
1885 * type is what type of pointer.
1887 * this is text is what text we should put in any created tree node.
1889 * hf_index is what hf value we want to pass to the callback function when
1890 * it is called, the callback can later pich this one up from di->hf_index.
1892 * callback is executed after the pointer has been dereferenced.
1894 * callback_args is passed as an argument to the callback function
1896 * See packet-dcerpc-samr.c for examples
1899 dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1900 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
1901 int type, const char *text, int hf_index,
1902 dcerpc_callback_fnct_t *callback, void *callback_args)
1905 proto_tree *tr = NULL;
1906 gint start_offset = offset;
1908 di=pinfo->private_data;
1909 if(di->conformant_run){
1910 /* this call was only for dissecting the header for any
1911 embedded conformant array. we will not parse any
1912 pointers in this mode.
1917 /*TOP LEVEL REFERENCE POINTER*/
1918 if( pointers_are_top_level
1919 &&(type==NDR_POINTER_REF) ){
1922 /* we must find out a nice way to do the length here */
1923 item=proto_tree_add_text(tree, tvb, offset, 0,
1925 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1927 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1928 hf_index, callback, callback_args);
1932 /*TOP LEVEL FULL POINTER*/
1933 if( pointers_are_top_level
1934 && (type==NDR_POINTER_PTR) ){
1939 /* get the referent id */
1940 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1942 tvb_ensure_bytes_exist(tvb, offset-4, 4);
1943 /* we got a NULL pointer */
1945 proto_tree_add_text(tree, tvb, offset-4, 4,
1946 "(NULL pointer) %s",text);
1950 /* see if we have seen this pointer before */
1951 idx=find_pointer_index(id);
1953 /* we have seen this pointer before */
1955 proto_tree_add_text(tree, tvb, offset-4, 4,
1956 "(duplicate PTR) %s",text);
1961 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1963 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1964 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1965 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
1966 callback, callback_args);
1969 /*TOP LEVEL UNIQUE POINTER*/
1970 if( pointers_are_top_level
1971 && (type==NDR_POINTER_UNIQUE) ){
1975 /* get the referent id */
1976 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1978 tvb_ensure_bytes_exist(tvb, offset-4, 4);
1979 /* we got a NULL pointer */
1981 proto_tree_add_text(tree, tvb, offset-4, 4,
1982 "(NULL pointer) %s",text);
1987 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1989 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1990 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1991 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1992 hf_index, callback, callback_args);
1996 /*EMBEDDED REFERENCE POINTER*/
1997 if( (!pointers_are_top_level)
1998 && (type==NDR_POINTER_REF) ){
2002 /* get the referent id */
2003 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
2005 tvb_ensure_bytes_exist(tvb, offset-4, 4);
2007 item=proto_tree_add_text(tree, tvb, offset-4, 4,
2009 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2010 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
2011 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
2012 hf_index, callback, callback_args);
2016 /*EMBEDDED UNIQUE POINTER*/
2017 if( (!pointers_are_top_level)
2018 && (type==NDR_POINTER_UNIQUE) ){
2022 /* get the referent id */
2023 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
2025 tvb_ensure_bytes_exist(tvb, offset-4, 4);
2026 /* we got a NULL pointer */
2028 proto_tree_add_text(tree, tvb, offset-4, 4,
2029 "(NULL pointer) %s", text);
2034 item=proto_tree_add_text(tree, tvb, offset-4, 4,
2036 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2037 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
2038 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
2039 hf_index, callback, callback_args);
2043 /*EMBEDDED FULL POINTER*/
2044 if( (!pointers_are_top_level)
2045 && (type==NDR_POINTER_PTR) ){
2050 /* get the referent id */
2051 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
2053 tvb_ensure_bytes_exist(tvb, offset-4, 4);
2054 /* we got a NULL pointer */
2056 proto_tree_add_text(tree, tvb, offset-4, 4,
2057 "(NULL pointer) %s",text);
2061 /* see if we have seen this pointer before */
2062 idx=find_pointer_index(id);
2064 /* we have seen this pointer before */
2066 proto_tree_add_text(tree, tvb, offset-4, 4,
2067 "(duplicate PTR) %s",text);
2072 item=proto_tree_add_text(tree, tvb, offset-4, 4,
2074 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2075 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
2076 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
2077 callback, callback_args);
2083 /* After each top level pointer we have dissected we have to
2084 dissect all deferrals before we move on to the next top level
2086 if(pointers_are_top_level==TRUE){
2087 pointers_are_top_level=FALSE;
2088 offset = dissect_deferred_pointers(pinfo, tvb, offset, drep);
2089 pointers_are_top_level=TRUE;
2092 /* Set the length for the new subtree */
2094 proto_item_set_len(tr, offset-start_offset);
2100 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2101 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2102 int type, const char *text, int hf_index)
2104 return dissect_ndr_pointer_cb(
2105 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
2109 dissect_ndr_toplevel_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2110 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2111 int type, const char *text, int hf_index)
2115 pointers_are_top_level=TRUE;
2116 ret=dissect_ndr_pointer_cb(
2117 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
2122 dissect_ndr_embedded_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2123 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2124 int type, const char *text, int hf_index)
2128 pointers_are_top_level=FALSE;
2129 ret=dissect_ndr_pointer_cb(
2130 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
2136 show_stub_data (tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
2137 dcerpc_auth_info *auth_info, gboolean is_encrypted)
2139 int length, plain_length, auth_pad_len;
2140 guint auth_pad_offset;
2143 * We don't show stub data unless we have some in the tvbuff;
2144 * however, in the protocol tree, we show, as the number of
2145 * bytes, the reported number of bytes, not the number of bytes
2146 * that happen to be in the tvbuff.
2148 if (tvb_length_remaining (tvb, offset) > 0) {
2149 auth_pad_len = auth_info?auth_info->auth_pad_len:0;
2150 length = tvb_reported_length_remaining (tvb, offset);
2152 /* if auth_pad_len is larger than length then we ignore auth_pad_len totally */
2153 plain_length = length - auth_pad_len;
2154 if (plain_length < 1) {
2155 plain_length = length;
2158 auth_pad_offset = offset + plain_length;
2160 if (auth_info != NULL &&
2161 auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
2163 tvb_ensure_bytes_exist(tvb, offset, length);
2164 proto_tree_add_text(dcerpc_tree, tvb, offset, length,
2165 "Encrypted stub data (%d byte%s)",
2166 length, plurality(length, "", "s"));
2167 /* is the padding is still inside the encrypted blob, don't display it explicit */
2170 tvb_ensure_bytes_exist(tvb, offset, plain_length);
2171 proto_tree_add_text(dcerpc_tree, tvb, offset, plain_length,
2172 "Decrypted stub data (%d byte%s)",
2173 plain_length, plurality(plain_length, "", "s"));
2176 tvb_ensure_bytes_exist(tvb, offset, plain_length);
2177 proto_tree_add_text (dcerpc_tree, tvb, offset, plain_length,
2178 "Stub data (%d byte%s)", plain_length,
2179 plurality(plain_length, "", "s"));
2181 /* If there is auth padding at the end of the stub, display it */
2182 if (auth_pad_len != 0) {
2183 tvb_ensure_bytes_exist(tvb, auth_pad_offset, auth_pad_len);
2184 proto_tree_add_text (dcerpc_tree, tvb, auth_pad_offset,
2186 "Auth Padding (%u byte%s)",
2188 plurality(auth_pad_len, "", "s"));
2194 dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
2195 proto_tree *dcerpc_tree,
2196 tvbuff_t *volatile tvb, tvbuff_t *decrypted_tvb,
2197 guint8 *drep, dcerpc_info *info,
2198 dcerpc_auth_info *auth_info)
2200 volatile gint offset = 0;
2201 dcerpc_uuid_key key;
2202 dcerpc_uuid_value *sub_proto;
2203 proto_tree *volatile sub_tree = NULL;
2204 dcerpc_sub_dissector *proc;
2205 const gchar *name = NULL;
2206 dcerpc_dissect_fnct_t *volatile sub_dissect;
2207 const char *volatile saved_proto;
2208 void *volatile saved_private_data;
2209 guint length, reported_length;
2210 tvbuff_t *volatile stub_tvb;
2211 volatile guint auth_pad_len;
2212 volatile int auth_pad_offset;
2214 char UUID_NAME[MAX_PATH];
2216 proto_item *sub_item=NULL;
2218 key.uuid = info->call_data->uuid;
2219 key.ver = info->call_data->ver;
2222 if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == NULL
2223 || !proto_is_protocol_enabled(sub_proto->proto)) {
2225 * We don't have a dissector for this UUID, or the protocol
2226 * for that UUID is disabled.
2229 proto_tree_add_boolean_hidden(dcerpc_tree, hf_dcerpc_unknown_if_id,
2230 tvb, offset, 0, TRUE);
2231 if (check_col (pinfo->cinfo, COL_INFO)) {
2233 if(ResolveWin32UUID(info->call_data->uuid, UUID_NAME, MAX_PATH))
2234 col_append_fstr (pinfo->cinfo, COL_INFO, " [%s] UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x rpcver: %u",
2235 UUID_NAME, info->call_data->uuid.Data1, info->call_data->uuid.Data2, info->call_data->uuid.Data3, info->call_data->uuid.Data4[0],
2236 info->call_data->uuid.Data4[1], info->call_data->uuid.Data4[2], info->call_data->uuid.Data4[3],
2237 info->call_data->uuid.Data4[4], info->call_data->uuid.Data4[5], info->call_data->uuid.Data4[6],
2238 info->call_data->uuid.Data4[7], info->call_data->ver);
2241 col_append_fstr (pinfo->cinfo, COL_INFO, " UNKUUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x rpcver: %u",
2242 info->call_data->uuid.Data1, info->call_data->uuid.Data2, info->call_data->uuid.Data3, info->call_data->uuid.Data4[0],
2243 info->call_data->uuid.Data4[1], info->call_data->uuid.Data4[2], info->call_data->uuid.Data4[3],
2244 info->call_data->uuid.Data4[4], info->call_data->uuid.Data4[5], info->call_data->uuid.Data4[6],
2245 info->call_data->uuid.Data4[7], info->call_data->ver);
2248 if (decrypted_tvb != NULL) {
2249 show_stub_data (decrypted_tvb, 0, dcerpc_tree, auth_info,
2252 show_stub_data (tvb, 0, dcerpc_tree, auth_info, TRUE);
2256 for (proc = sub_proto->procs; proc->name; proc++) {
2257 if (proc->num == info->call_data->opnum) {
2266 if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
2267 col_set_str (pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
2270 if (check_col (pinfo->cinfo, COL_INFO)) {
2271 col_add_fstr (pinfo->cinfo, COL_INFO, "%s %s",
2272 name, (info->ptype == PDU_REQ) ? "request" : "response");
2276 sub_item = proto_tree_add_item (tree, sub_proto->proto_id, tvb, 0,
2280 sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
2281 proto_item_append_text(sub_item, ", %s", name);
2285 * Put the operation number into the tree along with
2286 * the operation's name.
2289 if (sub_proto->opnum_hf != -1)
2290 proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
2291 tvb, 0, 0, info->call_data->opnum,
2292 "Operation: %s (%u)",
2293 name, info->call_data->opnum);
2295 proto_tree_add_uint_format(sub_tree, hf_dcerpc_op, tvb,
2296 0, 0, info->call_data->opnum,
2297 "Operation: %s (%u)",
2298 name, info->call_data->opnum);
2301 sub_dissect = (info->ptype == PDU_REQ) ?
2302 proc->dissect_rqst : proc->dissect_resp;
2304 if (decrypted_tvb != NULL) {
2305 /* Either there was no encryption or we successfully decrypted
2306 the entrypted payload. */
2308 /* We have a subdissector - call it. */
2309 saved_proto = pinfo->current_proto;
2310 saved_private_data = pinfo->private_data;
2311 pinfo->current_proto = sub_proto->name;
2312 pinfo->private_data = (void *)info;
2314 init_ndr_pointer_list(pinfo);
2317 * Remove the authentication padding from the stub data.
2319 if (auth_info != NULL && auth_info->auth_pad_len != 0) {
2320 length = tvb_length(decrypted_tvb);
2321 reported_length = tvb_reported_length(decrypted_tvb);
2322 if (reported_length >= auth_info->auth_pad_len) {
2324 * OK, the padding length isn't so big that it
2325 * exceeds the stub length. Trim the reported
2326 * length of the tvbuff.
2328 reported_length -= auth_info->auth_pad_len;
2331 * If that exceeds the actual amount of data in
2332 * the tvbuff (which means we have at least one
2333 * byte of authentication padding in the tvbuff),
2334 * trim the actual amount.
2336 if (length > reported_length)
2337 length = reported_length;
2339 stub_tvb = tvb_new_subset(tvb, 0, length, reported_length);
2340 auth_pad_len = auth_info->auth_pad_len;
2341 auth_pad_offset = reported_length;
2344 * The padding length exceeds the stub length.
2345 * Don't bother dissecting the stub, trim the padding
2346 * length to what's in the stub data, and show the
2347 * entire stub as authentication padding.
2350 auth_pad_len = reported_length;
2351 auth_pad_offset = 0;
2355 * No authentication padding.
2357 stub_tvb = decrypted_tvb;
2359 auth_pad_offset = 0;
2362 if (stub_tvb != NULL) {
2364 * Catch all exceptions other than BoundsError, so that even
2365 * if the stub data is bad, we still show the authentication
2368 * If we get BoundsError, it means the frame was cut short
2369 * by a snapshot length, so there's nothing more to
2370 * dissect; just re-throw that exception.
2373 offset = sub_dissect (decrypted_tvb, 0, pinfo, sub_tree,
2376 proto_item_set_len(sub_item, offset);
2379 /* If we have a subdissector and it didn't dissect all
2380 data in the tvb, make a note of it. */
2381 /* XXX - don't do this, as this could be just another RPC Req./Resp. in this PDU */
2382 /*if (tvb_reported_length_remaining(stub_tvb, offset) > 0) {
2383 if (check_col(pinfo->cinfo, COL_INFO))
2384 col_append_fstr(pinfo->cinfo, COL_INFO,
2385 "[Long frame (%d bytes)]",
2386 tvb_reported_length_remaining(stub_tvb, offset));
2388 } CATCH(BoundsError) {
2391 show_exception(decrypted_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
2395 /* If there is auth padding at the end of the stub, display it */
2396 if (auth_pad_len != 0) {
2397 tvb_ensure_bytes_exist(tvb, auth_pad_offset, auth_pad_len);
2398 proto_tree_add_text (sub_tree, decrypted_tvb, auth_pad_offset,
2400 "Auth Padding (%u byte%s)",
2402 plurality(auth_pad_len, "", "s"));
2405 pinfo->current_proto = saved_proto;
2406 pinfo->private_data = saved_private_data;
2408 /* No subdissector - show it as stub data. */
2410 show_stub_data (decrypted_tvb, 0, sub_tree, auth_info, FALSE);
2412 show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
2416 show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
2418 tap_queue_packet(dcerpc_tap, pinfo, info);
2423 dissect_dcerpc_verifier (tvbuff_t *tvb, packet_info *pinfo,
2424 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
2425 dcerpc_auth_info *auth_info)
2429 auth_info->auth_data = NULL;
2431 if (auth_info->auth_size != 0) {
2432 dcerpc_auth_subdissector_fns *auth_fns;
2435 auth_offset = hdr->frag_len - hdr->auth_len;
2437 auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
2440 auth_info->auth_data = auth_tvb;
2442 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
2443 auth_info->auth_type))) {
2445 * Catch all exceptions, so that even if the verifier is bad
2446 * or we don't have all of it, we still show the stub data.
2449 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
2452 show_exception(auth_tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
2455 tvb_ensure_bytes_exist(tvb, 0, hdr->auth_len);
2456 proto_tree_add_text (dcerpc_tree, auth_tvb, 0, hdr->auth_len,
2461 return hdr->auth_len;
2465 dissect_dcerpc_cn_auth (tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
2466 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
2467 gboolean are_credentials, dcerpc_auth_info *auth_info)
2469 volatile int offset;
2472 * Initially set auth_level and auth_type to zero to indicate that we
2473 * haven't yet seen any authentication level information.
2475 auth_info->auth_level = 0;
2476 auth_info->auth_type = 0;
2477 auth_info->auth_size = 0;
2478 auth_info->auth_pad_len = 0;
2481 * The authentication information is at the *end* of the PDU; in
2482 * request and response PDUs, the request and response stub data
2485 * Is there any authentication data (i.e., is the authentication length
2486 * non-zero), and is the authentication length valid (i.e., is it, plus
2487 * 8 bytes for the type/level/pad length/reserved/context id, less than
2488 * or equal to the fragment length minus the starting offset of the
2493 && (hdr->auth_len + 8 <= hdr->frag_len - stub_offset)) {
2496 * Yes, there is authentication data, and the length is valid.
2497 * Do we have all the bytes of stub data?
2498 * (If not, we'd throw an exception dissecting *that*, so don't
2499 * bother trying to dissect the authentication information and
2500 * throwing another exception there.)
2502 offset = hdr->frag_len - (hdr->auth_len + 8);
2503 if (offset == 0 || tvb_offset_exists(tvb, offset - 1)) {
2505 * Either there's no stub data, or the last byte of the stub
2506 * data is present in the captured data, so we shouldn't
2507 * get a BoundsError dissecting the stub data.
2509 * Try dissecting the authentication data.
2510 * Catch all exceptions, so that even if the auth info is bad
2511 * or we don't have all of it, we still show the stuff we
2512 * dissect after this, such as stub data.
2515 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2516 hf_dcerpc_auth_type,
2517 &auth_info->auth_type);
2518 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2519 hf_dcerpc_auth_level,
2520 &auth_info->auth_level);
2522 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2523 hf_dcerpc_auth_pad_len,
2524 &auth_info->auth_pad_len);
2525 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2526 hf_dcerpc_auth_rsrvd, NULL);
2527 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2528 hf_dcerpc_auth_ctx_id, NULL);
2531 * Dissect the authentication data.
2533 if (are_credentials) {
2535 dcerpc_auth_subdissector_fns *auth_fns;
2537 auth_tvb = tvb_new_subset(tvb, offset,
2538 MIN(hdr->auth_len,tvb_length_remaining(tvb, offset)),
2541 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
2542 auth_info->auth_type)))
2543 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
2546 proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len,
2547 "Auth Credentials");
2550 /* Compute the size of the auth block. Note that this should not
2551 include auth padding, since when NTLMSSP encryption is used, the
2552 padding is actually inside the encrypted stub */
2553 auth_info->auth_size = hdr->auth_len + 8;
2555 show_exception(tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
2562 /* We need to hash in the SMB fid number to generate a unique hash table
2563 * key as DCERPC over SMB allows several pipes over the same TCP/IP
2565 * We pass this function the transport type here to make sure we only look
2566 * at this function if it came across an SMB pipe.
2567 * Other transports might need to mix in their own extra multiplexing data
2568 * as well in the future.
2571 guint16 dcerpc_get_transport_salt (packet_info *pinfo)
2573 switch(pinfo->dcetransporttype){
2574 case DCE_CN_TRANSPORT_SMBPIPE:
2575 /* DCERPC over smb */
2576 return pinfo->dcetransportsalt;
2579 /* Some other transport... */
2584 * Connection oriented packet types
2588 dissect_dcerpc_cn_bind (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2589 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2591 conversation_t *conv = NULL;
2592 guint8 num_ctx_items = 0;
2594 gboolean saw_ctx_item = FALSE;
2596 guint8 num_trans_items;
2601 guint16 if_ver, if_ver_minor;
2602 char uuid_str[DCERPC_UUID_STR_LEN];
2604 dcerpc_auth_info auth_info;
2606 char UUID_NAME[MAX_PATH];
2609 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2610 hf_dcerpc_cn_max_xmit, NULL);
2612 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2613 hf_dcerpc_cn_max_recv, NULL);
2615 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2616 hf_dcerpc_cn_assoc_group, NULL);
2618 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2619 hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
2624 for (i = 0; i < num_ctx_items; i++) {
2625 proto_tree *ctx_tree = NULL, *iface_tree = NULL;
2627 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, NULL, hdr->drep,
2628 hf_dcerpc_cn_ctx_id, &ctx_id);
2630 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
2631 /* (if we have multiple contexts, this might cause "decode as"
2632 * to behave unpredictably) */
2633 pinfo->dcectxid = ctx_id;
2636 proto_item *ctx_item;
2638 ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_id,
2640 hdr->drep[0] & 0x10);
2642 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
2645 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, ctx_tree, hdr->drep,
2646 hf_dcerpc_cn_num_trans_items, &num_trans_items);
2651 /* XXX - use "dissect_ndr_uuid_t()"? */
2652 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
2654 proto_item *iface_item;
2656 uuid_str_len = g_snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2657 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2658 if_id.Data1, if_id.Data2, if_id.Data3,
2659 if_id.Data4[0], if_id.Data4[1],
2660 if_id.Data4[2], if_id.Data4[3],
2661 if_id.Data4[4], if_id.Data4[5],
2662 if_id.Data4[6], if_id.Data4[7]);
2664 if (uuid_str_len == -1 || uuid_str_len >= DCERPC_UUID_STR_LEN)
2665 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2667 if(ResolveWin32UUID(if_id, UUID_NAME, MAX_PATH))
2668 iface_item = proto_tree_add_string_format (ctx_tree, hf_dcerpc_cn_bind_if_id, tvb,
2669 offset, 16, uuid_str, "Interface: %s\tUUID: %s", UUID_NAME, uuid_str);
2672 iface_item = proto_tree_add_string_format (ctx_tree, hf_dcerpc_cn_bind_if_id, tvb,
2673 offset, 16, uuid_str, "Interface UUID: %s", uuid_str);
2674 iface_tree = proto_item_add_subtree(iface_item, ett_dcerpc_cn_iface);
2678 if (hdr->drep[0] & 0x10) {
2679 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2680 hf_dcerpc_cn_bind_if_ver, &if_ver);
2681 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2682 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2684 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2685 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2686 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2687 hf_dcerpc_cn_bind_if_ver, &if_ver);
2690 if (!saw_ctx_item) {
2691 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
2692 pinfo->srcport, pinfo->destport, 0);
2694 conv = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
2695 pinfo->srcport, pinfo->destport, 0);
2699 /* if this is the first time we see this packet, we need to
2700 update the dcerpc_binds table so that any later calls can
2701 match to the interface.
2702 XXX We assume that BINDs will NEVER be fragmented.
2704 if(!(pinfo->fd->flags.visited)){
2705 dcerpc_bind_key *key;
2706 dcerpc_bind_value *value;
2708 key = se_alloc (sizeof (dcerpc_bind_key));
2710 key->ctx_id = ctx_id;
2711 key->smb_fid = dcerpc_get_transport_salt(pinfo);
2713 value = se_alloc (sizeof (dcerpc_bind_value));
2714 value->uuid = if_id;
2715 value->ver = if_ver;
2717 /* add this entry to the bind table, first removing any
2718 previous ones that are identical
2720 if(g_hash_table_lookup(dcerpc_binds, key)){
2721 g_hash_table_remove(dcerpc_binds, key);
2723 g_hash_table_insert (dcerpc_binds, key, value);
2726 if (check_col (pinfo->cinfo, COL_INFO)) {
2727 dcerpc_uuid_key key;
2728 dcerpc_uuid_value *value;
2733 if (num_ctx_items > 1)
2734 col_append_fstr(pinfo->cinfo, COL_INFO, ", %u context items, 1st", num_ctx_items);
2736 if ((value = g_hash_table_lookup(dcerpc_uuids, &key)))
2737 col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %s", value->name);
2740 if(ResolveWin32UUID(if_id, UUID_NAME, MAX_PATH))
2741 col_append_fstr(pinfo->cinfo, COL_INFO, " [%s] UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
2742 UUID_NAME, if_id.Data1, if_id.Data2, if_id.Data3,
2743 if_id.Data4[0], if_id.Data4[1],
2744 if_id.Data4[2], if_id.Data4[3],
2745 if_id.Data4[4], if_id.Data4[5],
2746 if_id.Data4[6], if_id.Data4[7],
2747 if_ver, if_ver_minor);
2750 col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
2751 if_id.Data1, if_id.Data2, if_id.Data3,
2752 if_id.Data4[0], if_id.Data4[1],
2753 if_id.Data4[2], if_id.Data4[3],
2754 if_id.Data4[4], if_id.Data4[5],
2755 if_id.Data4[6], if_id.Data4[7],
2756 if_ver, if_ver_minor);
2758 saw_ctx_item = TRUE;
2761 for (j = 0; j < num_trans_items; j++) {
2762 /* XXX - use "dissect_ndr_uuid_t()"? */
2763 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2765 uuid_str_len = g_snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2766 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2767 trans_id.Data1, trans_id.Data2, trans_id.Data3,
2768 trans_id.Data4[0], trans_id.Data4[1],
2769 trans_id.Data4[2], trans_id.Data4[3],
2770 trans_id.Data4[4], trans_id.Data4[5],
2771 trans_id.Data4[6], trans_id.Data4[7]);
2772 if (uuid_str_len == -1 || uuid_str_len >= DCERPC_UUID_STR_LEN)
2773 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2774 proto_tree_add_string_format (iface_tree, hf_dcerpc_cn_bind_trans_id, tvb,
2775 offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2779 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, iface_tree, hdr->drep,
2780 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
2785 * XXX - we should save the authentication type *if* we have
2786 * an authentication header, and associate it with an authentication
2787 * context, so subsequent PDUs can use that context.
2789 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2793 dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2794 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2796 guint16 max_xmit, max_recv;
2797 guint16 sec_addr_len;
2804 char uuid_str[DCERPC_UUID_STR_LEN];
2806 dcerpc_auth_info auth_info;
2808 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2809 hf_dcerpc_cn_max_xmit, &max_xmit);
2811 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2812 hf_dcerpc_cn_max_recv, &max_recv);
2814 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2815 hf_dcerpc_cn_assoc_group, NULL);
2817 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2818 hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
2819 if (sec_addr_len != 0) {
2820 tvb_ensure_bytes_exist(tvb, offset, sec_addr_len);
2821 proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
2822 sec_addr_len, FALSE);
2823 offset += sec_addr_len;
2827 offset += 4 - offset % 4;
2830 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2831 hf_dcerpc_cn_num_results, &num_results);
2836 for (i = 0; i < num_results; i++) {
2837 proto_tree *ctx_tree = NULL;
2840 proto_item *ctx_item;
2841 ctx_item = proto_tree_add_text(dcerpc_tree, tvb, offset, 24, "Context ID: %d", i);
2842 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
2845 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, ctx_tree,
2846 hdr->drep, hf_dcerpc_cn_ack_result,
2849 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, ctx_tree,
2850 hdr->drep, hf_dcerpc_cn_ack_reason,
2854 * The reason for rejection isn't meaningful, and often isn't
2855 * set, when the syntax was accepted.
2860 /* XXX - use "dissect_ndr_uuid_t()"? */
2861 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2863 uuid_str_len = g_snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2864 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2865 trans_id.Data1, trans_id.Data2, trans_id.Data3,
2866 trans_id.Data4[0], trans_id.Data4[1],
2867 trans_id.Data4[2], trans_id.Data4[3],
2868 trans_id.Data4[4], trans_id.Data4[5],
2869 trans_id.Data4[6], trans_id.Data4[7]);
2870 if (uuid_str_len == -1 || uuid_str_len >= DCERPC_UUID_STR_LEN)
2871 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2872 proto_tree_add_string_format (ctx_tree, hf_dcerpc_cn_ack_trans_id, tvb,
2873 offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2877 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, ctx_tree, hdr->drep,
2878 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
2882 * XXX - do we need to do anything with the authentication level
2883 * we get back from this?
2885 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2887 if (check_col (pinfo->cinfo, COL_INFO)) {
2888 if (num_results != 0 && result == 0) {
2889 /* XXX - only checks the last result */
2890 col_append_fstr (pinfo->cinfo, COL_INFO,
2891 " accept max_xmit: %u max_recv: %u",
2892 max_xmit, max_recv);
2894 /* XXX - only shows the last result and reason */
2895 col_append_fstr (pinfo->cinfo, COL_INFO, " %s, reason: %s",
2896 val_to_str(result, p_cont_result_vals,
2897 "Unknown result (%u)"),
2898 val_to_str(reason, p_provider_reason_vals,
2905 dissect_dcerpc_cn_bind_nak (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2906 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2909 guint8 num_protocols;
2912 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2913 hdr->drep, hf_dcerpc_cn_reject_reason,
2916 if (check_col (pinfo->cinfo, COL_INFO)) {
2917 col_append_fstr (pinfo->cinfo, COL_INFO, " reason: %s",
2918 val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
2921 if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
2922 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2923 hf_dcerpc_cn_num_protocols,
2926 for (i = 0; i < num_protocols; i++) {
2927 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2928 hdr->drep, hf_dcerpc_cn_protocol_ver_major,
2930 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2931 hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
2937 /* Return a string describing a DCE/RPC fragment as first, middle, or end
2940 #define PFC_FRAG_MASK 0x03
2943 fragment_type(guint8 flags)
2945 flags = flags & PFC_FRAG_MASK;
2947 if (flags == PFC_FIRST_FRAG)
2953 if (flags == PFC_LAST_FRAG)
2956 if (flags == (PFC_FIRST_FRAG | PFC_LAST_FRAG))
2962 /* Dissect stub data (payload) of a DCERPC packet. */
2965 dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
2966 proto_tree *dcerpc_tree, proto_tree *tree,
2967 e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
2968 dcerpc_auth_info *auth_info, guint32 alloc_hint _U_,
2971 gint length, reported_length;
2972 gboolean save_fragmented;
2973 fragment_data *fd_head=NULL;
2975 tvbuff_t *auth_tvb, *payload_tvb, *decrypted_tvb;
2977 proto_item *parent_pi;
2978 proto_item *dcerpc_tree_item;
2980 save_fragmented = pinfo->fragmented;
2982 length = tvb_length_remaining(tvb, offset);
2983 reported_length = tvb_reported_length_remaining(tvb, offset);
2984 if (reported_length < 0 ||
2985 (guint32)reported_length < auth_info->auth_size) {
2986 /* We don't even have enough bytes for the authentication
2990 reported_length -= auth_info->auth_size;
2991 if (length > reported_length)
2992 length = reported_length;
2993 payload_tvb = tvb_new_subset(tvb, offset, length, reported_length);
2996 /*dont bother if we dont have the entire tvb */
2997 /*XXX we should really make sure we calculate auth_info->auth_data
2998 and use that one instead of this auth_tvb hack
3000 if(tvb_length(tvb)==tvb_reported_length(tvb)){
3001 if(tvb_length_remaining(tvb, offset+length)>8){
3002 auth_tvb = tvb_new_subset(tvb, offset+length+8, -1, -1);
3006 /* Decrypt the PDU if it is encrypted */
3008 if (auth_info->auth_type &&
3009 auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
3011 * We know the authentication type, and the authentication
3012 * level is "Packet privacy", meaning the payload is
3013 * encrypted; attempt to decrypt it.
3015 dcerpc_auth_subdissector_fns *auth_fns;
3017 /* Start out assuming we won't succeed in decrypting. */
3018 decrypted_tvb = NULL;
3020 if ((auth_fns = get_auth_subdissector_fns(
3021 auth_info->auth_level, auth_info->auth_type))) {
3024 result = decode_encrypted_data(
3025 payload_tvb, auth_tvb, pinfo, auth_fns,
3026 hdr->ptype == PDU_REQ, auth_info);
3030 proto_tree_add_text(
3031 dcerpc_tree, payload_tvb, 0, -1,
3032 "Encrypted stub data (%d byte%s)",
3033 tvb_reported_length(payload_tvb),
3035 plurality(tvb_length(payload_tvb), "", "s"));
3037 add_new_data_source(
3038 pinfo, result, "Decrypted stub data");
3041 decrypted_tvb = result;
3045 decrypted_tvb = payload_tvb;
3047 /* if this packet is not fragmented, just dissect it and exit */
3048 if(PFC_NOT_FRAGMENTED(hdr)){
3049 pinfo->fragmented = FALSE;
3052 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
3053 hdr->drep, di, auth_info);
3055 pinfo->fragmented = save_fragmented;
3059 /* The packet is fragmented. */
3060 pinfo->fragmented = TRUE;
3062 /* debug output of essential fragment data. */
3063 /* leave it here for future debugging sessions */
3064 /*printf("DCE num:%u offset:%u frag_len:%u tvb_len:%u\n",
3065 pinfo->fd->num, offset, hdr->frag_len, tvb_length(decrypted_tvb));*/
3067 /* if we are not doing reassembly and this is the first fragment
3068 then just dissect it and exit
3069 XXX - if we're not doing reassembly, can we decrypt an
3072 if( (!dcerpc_reassemble) && hdr->flags&PFC_FIRST_FRAG ){
3075 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
3076 hdr->drep, di, auth_info);
3078 if (check_col(pinfo->cinfo, COL_INFO)) {
3079 col_append_fstr(pinfo->cinfo, COL_INFO,
3080 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
3082 expert_add_info_format(pinfo, NULL, PI_REASSEMBLE, PI_CHAT,
3083 "%s fragment", fragment_type(hdr->flags));
3084 pinfo->fragmented = save_fragmented;
3088 /* if we have already seen this packet, see if it was reassembled
3089 and if so dissect the full pdu.
3092 if(pinfo->fd->flags.visited){
3093 fd_head=fragment_get_reassembled(pinfo, frame, dcerpc_co_reassemble_table);
3097 /* if we are not doing reassembly and it was neither a complete PDU
3098 nor the first fragment then there is nothing more we can do
3099 so we just have to exit
3101 if( !dcerpc_reassemble )
3104 /* if we didnt get 'frame' we dont know where the PDU started and thus
3105 it is pointless to continue
3110 /* from now on we must attempt to reassemble the PDU
3113 /* if we get here we know it is the first time we see the packet
3114 and we also know it is only a fragment and not a full PDU,
3115 thus we must reassemble it.
3118 /* Do we have any non-encrypted data to reassemble? */
3119 if (decrypted_tvb == NULL) {
3120 /* No. We can't even try to reassemble. */
3124 /* defragmentation is a bit tricky, as there's no offset of the fragment
3125 * in the protocol data.
3127 * just use fragment_add_seq_next() and hope that TCP/SMB segments coming
3128 * in with the correct sequence.
3130 fd_head = fragment_add_seq_next(decrypted_tvb, 0, pinfo, frame,
3131 dcerpc_co_fragment_table, dcerpc_co_reassemble_table,
3132 tvb_length(decrypted_tvb),
3133 hdr->flags&PFC_LAST_FRAG ? FALSE : TRUE /* more_frags */);
3137 /* if reassembly is complete and this is the last fragment
3138 * (multiple fragments in one PDU are possible!)
3139 * dissect the full PDU
3141 if(fd_head && (fd_head->flags&FD_DEFRAGMENTED) ){
3143 if(pinfo->fd->num==fd_head->reassembled_in && (hdr->flags&PFC_LAST_FRAG) ){
3145 proto_item *frag_tree_item;
3147 next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
3148 tvb_set_child_real_data_tvbuff(decrypted_tvb, next_tvb);
3149 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3150 show_fragment_tree(fd_head, &dcerpc_frag_items,
3151 tree, pinfo, next_tvb, &frag_tree_item);
3152 /* the toplevel fragment subtree is now behind all desegmented data,
3153 * move it right behind the DCE/RPC tree */
3154 dcerpc_tree_item = proto_tree_get_parent(dcerpc_tree);
3155 if(frag_tree_item && dcerpc_tree_item) {
3156 proto_tree_move_item(tree, dcerpc_tree_item, frag_tree_item);
3159 pinfo->fragmented = FALSE;
3161 expert_add_info_format(pinfo, frag_tree_item, PI_REASSEMBLE, PI_CHAT,
3162 "%s fragment, %u bytes reassembled here in #%u",
3163 fragment_type(hdr->flags), fd_head->len, fd_head->reassembled_in);
3165 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
3166 next_tvb, hdr->drep, di, auth_info);
3169 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
3170 decrypted_tvb, 0, 0, fd_head->reassembled_in);
3171 PROTO_ITEM_SET_GENERATED(pi);
3172 parent_pi = proto_tree_get_parent(dcerpc_tree);
3173 if(parent_pi != NULL) {
3174 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
3176 if (check_col(pinfo->cinfo, COL_INFO)) {
3177 col_append_fstr(pinfo->cinfo, COL_INFO,
3178 " [DCE/RPC %s fragment, reas: #%u]", fragment_type(hdr->flags), fd_head->reassembled_in);
3180 expert_add_info_format(pinfo, NULL, PI_REASSEMBLE, PI_CHAT,
3181 "%s fragment, reassembled in #%u", fragment_type(hdr->flags), fd_head->reassembled_in);
3184 /* Reassembly not complete - some fragments
3185 are missing. Just show the stub data. */
3186 if (check_col(pinfo->cinfo, COL_INFO)) {
3187 col_append_fstr(pinfo->cinfo, COL_INFO,
3188 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
3190 expert_add_info_format(pinfo, NULL, PI_REASSEMBLE, PI_CHAT,
3191 "%s fragment", fragment_type(hdr->flags));
3194 show_stub_data (decrypted_tvb, 0, tree, auth_info, FALSE);
3196 show_stub_data (payload_tvb, 0, tree, auth_info, TRUE);
3200 pinfo->fragmented = save_fragmented;
3204 * Registers a conversation/UUID binding association, so that
3205 * we can invoke the proper sub-dissector for a given DCERPC
3208 * @param binding all values needed to create and bind a new conversation
3210 * @return Pointer to newly-added UUID/conversation binding.
3212 struct _dcerpc_bind_value *
3213 dcerpc_add_conv_to_bind_table(decode_dcerpc_bind_values_t *binding)
3215 dcerpc_bind_value *bind_value;
3216 dcerpc_bind_key *key;
3217 conversation_t *conv;
3219 conv = find_conversation (
3229 conv = conversation_new (
3239 bind_value = se_alloc (sizeof (dcerpc_bind_value));
3240 bind_value->uuid = binding->uuid;
3241 bind_value->ver = binding->ver;
3243 key = se_alloc(sizeof (dcerpc_bind_key));
3245 key->ctx_id = binding->ctx_id;
3246 key->smb_fid = binding->smb_fid;
3248 /* add this entry to the bind table, first removing any
3249 previous ones that are identical
3251 if(g_hash_table_lookup(dcerpc_binds, key)){
3252 g_hash_table_remove(dcerpc_binds, key);
3254 g_hash_table_insert(dcerpc_binds, key, bind_value);
3261 dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3262 proto_tree *dcerpc_tree, proto_tree *tree,
3263 e_dce_cn_common_hdr_t *hdr)
3265 conversation_t *conv;
3269 dcerpc_auth_info auth_info;
3271 char uuid_str[DCERPC_UUID_STR_LEN];
3274 proto_item *parent_pi;
3276 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3277 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3279 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3280 hf_dcerpc_cn_ctx_id, &ctx_id);
3281 parent_pi = proto_tree_get_parent(dcerpc_tree);
3282 if(parent_pi != NULL) {
3283 proto_item_append_text(parent_pi, " Ctx: %u", ctx_id);
3286 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3287 hf_dcerpc_opnum, &opnum);
3289 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3290 pinfo->dcectxid = ctx_id;
3292 if (check_col (pinfo->cinfo, COL_INFO)) {
3293 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u ctx_id: %u",
3297 if (hdr->flags & PFC_OBJECT_UUID) {
3298 /* XXX - use "dissect_ndr_uuid_t()"? */
3299 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id);
3301 uuid_str_len = g_snprintf(uuid_str, DCERPC_UUID_STR_LEN,
3302 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3303 obj_id.Data1, obj_id.Data2, obj_id.Data3,
3312 if (uuid_str_len == -1 || uuid_str_len >= DCERPC_UUID_STR_LEN)
3313 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
3314 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
3315 offset, 16, uuid_str, "Object UUID: %s", uuid_str);
3321 * XXX - what if this was set when the connection was set up,
3322 * and we just have a security context?
3324 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3326 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3327 pinfo->srcport, pinfo->destport, 0);
3329 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3331 dcerpc_matched_key matched_key, *new_matched_key;
3332 dcerpc_call_value *value;
3334 /* !!! we can NOT check flags.visited here since this will interact
3335 badly with when SMB handles (i.e. calls the subdissector)
3336 and desegmented pdu's .
3337 Instead we check if this pdu is already in the matched table or not
3339 matched_key.frame = pinfo->fd->num;
3340 matched_key.call_id = hdr->call_id;
3341 value = g_hash_table_lookup(dcerpc_matched, &matched_key);
3343 dcerpc_bind_key bind_key;
3344 dcerpc_bind_value *bind_value;
3347 bind_key.ctx_id=ctx_id;
3348 bind_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3350 if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key)) ){
3351 if(!(hdr->flags&PFC_FIRST_FRAG)){
3352 dcerpc_cn_call_key call_key;
3353 dcerpc_call_value *call_value;
3356 call_key.call_id=hdr->call_id;
3357 call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3358 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3359 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
3360 *new_matched_key = matched_key;
3361 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3365 dcerpc_cn_call_key *call_key;
3366 dcerpc_call_value *call_value;
3368 /* We found the binding and it is the first fragment
3369 (or a complete PDU) of a dcerpc pdu so just add
3370 the call to both the call table and the
3373 call_key=se_alloc (sizeof (dcerpc_cn_call_key));
3374 call_key->conv=conv;
3375 call_key->call_id=hdr->call_id;
3376 call_key->smb_fid=dcerpc_get_transport_salt(pinfo);
3378 /* if there is already a matching call in the table
3379 remove it so it is replaced with the new one */
3380 if(g_hash_table_lookup(dcerpc_cn_calls, call_key)){
3381 g_hash_table_remove(dcerpc_cn_calls, call_key);
3384 call_value=se_alloc (sizeof (dcerpc_call_value));
3385 call_value->uuid = bind_value->uuid;
3386 call_value->ver = bind_value->ver;
3387 call_value->opnum = opnum;
3388 call_value->req_frame=pinfo->fd->num;
3389 call_value->req_time=pinfo->fd->abs_ts;
3390 call_value->rep_frame=0;
3391 call_value->max_ptr=0;
3392 call_value->private_data = NULL;
3393 g_hash_table_insert (dcerpc_cn_calls, call_key, call_value);
3395 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
3396 *new_matched_key = matched_key;
3397 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3407 /* handoff this call */
3409 di->call_id = hdr->call_id;
3410 di->smb_fid = dcerpc_get_transport_salt(pinfo);
3411 di->ptype = PDU_REQ;
3412 di->call_data = value;
3415 if(value->rep_frame!=0){
3416 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
3417 tvb, 0, 0, value->rep_frame);
3418 PROTO_ITEM_SET_GENERATED(pi);
3419 if(parent_pi != NULL) {
3420 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
3424 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
3425 hdr, di, &auth_info, alloc_hint,
3428 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3431 /* Dissect the verifier */
3432 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
3437 dissect_dcerpc_cn_resp (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3438 proto_tree *dcerpc_tree, proto_tree *tree,
3439 e_dce_cn_common_hdr_t *hdr)
3441 dcerpc_call_value *value = NULL;
3442 conversation_t *conv;
3444 dcerpc_auth_info auth_info;
3447 proto_item *parent_pi;
3449 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3450 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3452 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3453 hf_dcerpc_cn_ctx_id, &ctx_id);
3454 parent_pi = proto_tree_get_parent(dcerpc_tree);
3455 if(parent_pi != NULL) {
3456 proto_item_append_text(parent_pi, " Ctx: %u", ctx_id);
3459 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3460 pinfo->dcectxid = ctx_id;
3462 if (check_col (pinfo->cinfo, COL_INFO)) {
3463 col_append_fstr (pinfo->cinfo, COL_INFO, " ctx_id: %u", ctx_id);
3466 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3467 hf_dcerpc_cn_cancel_count, NULL);
3472 * XXX - what if this was set when the connection was set up,
3473 * and we just have a security context?
3475 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3477 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3478 pinfo->srcport, pinfo->destport, 0);
3481 /* no point in creating one here, really */
3482 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3484 dcerpc_matched_key matched_key, *new_matched_key;
3486 /* !!! we can NOT check flags.visited here since this will interact
3487 badly with when SMB handles (i.e. calls the subdissector)
3488 and desegmented pdu's .
3489 Instead we check if this pdu is already in the matched table or not
3491 matched_key.frame = pinfo->fd->num;
3492 matched_key.call_id = hdr->call_id;
3493 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3495 dcerpc_cn_call_key call_key;
3496 dcerpc_call_value *call_value;
3499 call_key.call_id=hdr->call_id;
3500 call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3502 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3503 /* extra sanity check, only match them if the reply
3504 came after the request */
3505 if(call_value->req_frame<pinfo->fd->num){
3506 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
3507 *new_matched_key = matched_key;
3508 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3510 if(call_value->rep_frame==0){
3511 call_value->rep_frame=pinfo->fd->num;
3521 /* handoff this call */
3523 di->call_id = hdr->call_id;
3524 di->smb_fid = dcerpc_get_transport_salt(pinfo);
3525 di->ptype = PDU_RESP;
3526 di->call_data = value;
3528 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
3529 if(value->req_frame!=0){
3531 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3532 tvb, 0, 0, value->req_frame);
3533 PROTO_ITEM_SET_GENERATED(pi);
3534 if(parent_pi != NULL) {
3535 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
3537 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
3538 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
3539 PROTO_ITEM_SET_GENERATED(pi);
3542 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
3543 hdr, di, &auth_info, alloc_hint,
3546 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3549 /* Dissect the verifier */
3550 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
3554 dissect_dcerpc_cn_fault (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3555 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
3557 dcerpc_call_value *value = NULL;
3558 conversation_t *conv;
3562 dcerpc_auth_info auth_info;
3563 proto_item *pi = NULL;
3565 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3566 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3568 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3569 hf_dcerpc_cn_ctx_id, &ctx_id);
3571 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3572 hf_dcerpc_cn_cancel_count, NULL);
3576 /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3577 hf_dcerpc_cn_status, &status);*/
3578 status = ((hdr->drep[0] & 0x10)
3579 ? tvb_get_letohl (tvb, offset)
3580 : tvb_get_ntohl (tvb, offset));
3583 pi = proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_status, tvb, offset, 4, (hdr->drep[0] & 0x10));
3587 expert_add_info_format(pinfo, pi, PI_RESPONSE_CODE, PI_NOTE, "Fault: %s",
3588 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
3590 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3591 pinfo->dcectxid = ctx_id;
3593 if (check_col (pinfo->cinfo, COL_INFO)) {
3594 col_append_fstr (pinfo->cinfo, COL_INFO,
3595 " ctx_id: %u status: %s", ctx_id,
3596 val_to_str(status, reject_status_vals,
3597 "Unknown (0x%08x)"));
3604 * XXX - what if this was set when the connection was set up,
3605 * and we just have a security context?
3607 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3609 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3610 pinfo->srcport, pinfo->destport, 0);
3612 /* no point in creating one here, really */
3614 dcerpc_matched_key matched_key, *new_matched_key;
3616 /* !!! we can NOT check flags.visited here since this will interact
3617 badly with when SMB handles (i.e. calls the subdissector)
3618 and desegmented pdu's .
3619 Instead we check if this pdu is already in the matched table or not
3621 matched_key.frame = pinfo->fd->num;
3622 matched_key.call_id = hdr->call_id;
3623 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3625 dcerpc_cn_call_key call_key;
3626 dcerpc_call_value *call_value;
3629 call_key.call_id=hdr->call_id;
3630 call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3632 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3633 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
3634 *new_matched_key = matched_key;
3635 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3637 if(call_value->rep_frame==0){
3638 call_value->rep_frame=pinfo->fd->num;
3645 int length, reported_length, stub_length;
3647 proto_item *parent_pi;
3650 /* handoff this call */
3652 di->call_id = hdr->call_id;
3653 di->smb_fid = dcerpc_get_transport_salt(pinfo);
3654 di->ptype = PDU_FAULT;
3655 di->call_data = value;
3657 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
3658 if(value->req_frame!=0){
3660 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3661 tvb, 0, 0, value->req_frame);
3662 PROTO_ITEM_SET_GENERATED(pi);
3663 parent_pi = proto_tree_get_parent(dcerpc_tree);
3664 if(parent_pi != NULL) {
3665 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
3667 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
3668 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
3669 PROTO_ITEM_SET_GENERATED(pi);
3672 length = tvb_length_remaining(tvb, offset);
3673 reported_length = tvb_reported_length_remaining(tvb, offset);
3674 /* as we now create a tvb in dissect_dcerpc_cn() containing only the
3675 * stub_data, the following calculation is no longer valid:
3676 * stub_length = hdr->frag_len - offset - auth_info.auth_size;
3677 * simply use the remaining length of the tvb instead.
3678 * XXX - or better use the reported_length?!?
3680 stub_length = length;
3681 if (length > stub_length)
3682 length = stub_length;
3683 if (reported_length > stub_length)
3684 reported_length = stub_length;
3686 /* If we don't have reassembly enabled, or this packet contains
3687 the entire PDU, or if we don't have all the data in this
3688 fragment, just call the handoff directly if this is the
3689 first fragment or the PDU isn't fragmented. */
3690 if( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
3691 !tvb_bytes_exist(tvb, offset, stub_length) ){
3692 if(hdr->flags&PFC_FIRST_FRAG){
3693 /* First fragment, possibly the only fragment */
3695 * XXX - should there be a third routine for each
3696 * function in an RPC subdissector, to handle
3697 * fault responses? The DCE RPC 1.1 spec says
3698 * three's "stub data" here, which I infer means
3699 * that it's protocol-specific and call-specific.
3701 * It should probably get passed the status code
3702 * as well, as that might be protocol-specific.
3705 if (stub_length > 0) {
3706 tvb_ensure_bytes_exist(tvb, offset, stub_length);
3707 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3708 "Fault stub data (%d byte%s)",
3710 plurality(stub_length, "", "s"));
3714 /* PDU is fragmented and this isn't the first fragment */
3715 if (check_col(pinfo->cinfo, COL_INFO)) {
3716 col_append_fstr(pinfo->cinfo, COL_INFO,
3717 " [DCE/RPC fragment]");
3720 if (stub_length > 0) {
3721 tvb_ensure_bytes_exist(tvb, offset, stub_length);
3722 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3723 "Fragment data (%d byte%s)",
3725 plurality(stub_length, "", "s"));
3730 /* Reassembly is enabled, the PDU is fragmented, and
3731 we have all the data in the fragment; the first two
3732 of those mean we should attempt reassembly, and the
3733 third means we can attempt reassembly. */
3736 tvb_ensure_bytes_exist(tvb, offset, stub_length);
3737 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3738 "Fragment data (%d byte%s)",
3740 plurality(stub_length, "", "s"));
3743 if(hdr->flags&PFC_FIRST_FRAG){ /* FIRST fragment */
3744 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
3745 fragment_add_seq_next(tvb, offset, pinfo, value->rep_frame,
3746 dcerpc_co_fragment_table, dcerpc_co_reassemble_table,
3750 if (check_col(pinfo->cinfo, COL_INFO)) {
3751 col_append_fstr(pinfo->cinfo, COL_INFO,
3752 " [DCE/RPC fragment]");
3754 } else if(hdr->flags&PFC_LAST_FRAG){ /* LAST fragment */
3755 if( value->rep_frame ){
3756 fragment_data *fd_head;
3758 fd_head = fragment_add_seq_next(tvb, offset, pinfo,
3760 dcerpc_co_fragment_table, dcerpc_co_reassemble_table,
3765 /* We completed reassembly */
3767 proto_item *frag_tree_item;
3769 next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
3770 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
3771 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3772 show_fragment_tree(fd_head, &dcerpc_frag_items,
3773 dcerpc_tree, pinfo, next_tvb, &frag_tree_item);
3776 * XXX - should there be a third routine for each
3777 * function in an RPC subdissector, to handle
3778 * fault responses? The DCE RPC 1.1 spec says
3779 * three's "stub data" here, which I infer means
3780 * that it's protocol-specific and call-specific.
3782 * It should probably get passed the status code
3783 * as well, as that might be protocol-specific.
3787 tvb_ensure_bytes_exist(tvb, offset, stub_length);
3788 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3789 "Fault stub data (%d byte%s)",
3791 plurality(stub_length, "", "s"));
3795 /* Reassembly not complete - some fragments
3797 if (check_col(pinfo->cinfo, COL_INFO)) {
3798 col_append_fstr(pinfo->cinfo, COL_INFO,
3799 " [DCE/RPC fragment]");
3803 } else { /* MIDDLE fragment(s) */
3804 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
3805 fragment_add_seq_next(tvb, offset, pinfo, value->rep_frame,
3806 dcerpc_co_fragment_table, dcerpc_co_reassemble_table,
3810 if (check_col(pinfo->cinfo, COL_INFO)) {
3811 col_append_fstr(pinfo->cinfo, COL_INFO,
3812 " [DCE/RPC fragment]");
3821 * DCERPC dissector for connection oriented calls.
3822 * We use transport type to later multiplex between what kind of
3823 * pinfo->private_data structure to expect.
3826 dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
3827 proto_tree *tree, gboolean can_desegment, int *pkt_len)
3829 static const guint8 nulls[4] = { 0 };
3832 proto_item *ti = NULL;
3833 proto_item *tf = NULL;
3834 proto_tree *dcerpc_tree = NULL;
3835 proto_tree *cn_flags_tree = NULL;
3836 proto_tree *drep_tree = NULL;
3837 e_dce_cn_common_hdr_t hdr;
3838 dcerpc_auth_info auth_info;
3839 tvbuff_t *fragment_tvb;
3842 * when done over nbt, dcerpc requests are padded with 4 bytes of null
3843 * data for some reason.
3845 * XXX - if that's always the case, the right way to do this would
3846 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
3847 * the 4 bytes of null padding, and make that the dissector
3848 * used for "netbios".
3850 if (tvb_memeql (tvb, offset, nulls, 4) == 0) {
3859 * Check if this looks like a C/O DCERPC call
3861 if (!tvb_bytes_exist (tvb, offset, sizeof (hdr))) {
3862 return FALSE; /* not enough information to check */
3864 start_offset = offset;
3865 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
3866 if (hdr.rpc_ver != 5)
3868 hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
3869 if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
3871 hdr.ptype = tvb_get_guint8 (tvb, offset++);
3875 hdr.flags = tvb_get_guint8 (tvb, offset++);
3876 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
3877 offset += sizeof (hdr.drep);
3879 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3881 hdr.auth_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3883 hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3886 if (check_col (pinfo->cinfo, COL_DCE_CALL)) {
3887 if(pinfo->dcectxid == 0) {
3888 col_append_fstr (pinfo->cinfo, COL_DCE_CALL, "%u", hdr.call_id);
3890 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
3891 * prepend a delimiter */
3892 col_append_fstr (pinfo->cinfo, COL_DCE_CALL, "#%u", hdr.call_id);
3896 if (can_desegment && pinfo->can_desegment
3897 && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
3898 pinfo->desegment_offset = start_offset;
3899 pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, start_offset);
3900 *pkt_len = 0; /* desegmentation required */
3904 if (check_col (pinfo->cinfo, COL_PROTOCOL))
3905 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
3907 if (check_col (pinfo->cinfo, COL_INFO)) {
3908 if(pinfo->dcectxid != 0) {
3909 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
3910 * append a delimiter and set a column fence */
3911 col_append_str (pinfo->cinfo, COL_INFO, " # ");
3912 col_set_fence(pinfo->cinfo,COL_INFO);
3914 col_add_fstr (pinfo->cinfo, COL_INFO, "%s: call_id: %u",
3915 pckt_vals[hdr.ptype].strptr, hdr.call_id);
3918 if(pinfo->dcectxid != 0) {
3919 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU */
3920 expert_add_info_format(pinfo, NULL, PI_SEQUENCE, PI_NOTE, "Multiple DCE/RPC fragments/PDU's in one packet");
3923 offset = start_offset;
3924 tvb_ensure_bytes_exist(tvb, offset, 16);
3926 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE);
3927 dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
3930 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
3933 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset, 1, hdr.rpc_ver_minor);
3936 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
3939 /* XXX - too much "output noise", removed for now
3940 if(hdr.ptype == PDU_BIND || hdr.ptype == PDU_ALTER ||
3941 hdr.ptype == PDU_BIND_ACK || hdr.ptype == PDU_ALTER_ACK)
3942 expert_add_info_format(pinfo, tf, PI_SEQUENCE, PI_CHAT, "Context change: %s",
3943 val_to_str(hdr.ptype, pckt_vals, "(0x%x)"));*/
3944 if(hdr.ptype == PDU_BIND_NAK)
3945 expert_add_info_format(pinfo, tf, PI_SEQUENCE, PI_WARN, "Bind not acknowledged");
3948 proto_item_append_text(ti, " %s, Fragment:", val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"));
3950 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
3951 cn_flags_tree = proto_item_add_subtree (tf, ett_dcerpc_cn_flags);
3953 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
3954 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
3955 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
3956 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
3957 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
3958 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
3959 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
3960 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
3961 if( (hdr.flags & PFC_FIRST_FRAG) && (hdr.flags & PFC_LAST_FRAG) ) {
3962 proto_item_append_text(ti, " Single");
3964 if(hdr.flags & PFC_FIRST_FRAG) {
3965 proto_item_append_text(ti, " 1st");
3967 if(hdr.flags & PFC_LAST_FRAG) {
3968 proto_item_append_text(ti, " Last");
3970 if( !(hdr.flags & PFC_FIRST_FRAG) && !(hdr.flags & PFC_LAST_FRAG) ) {
3971 proto_item_append_text(ti, " Mid");
3977 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
3978 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
3980 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
3981 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
3982 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
3983 offset += sizeof (hdr.drep);
3985 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
3988 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
3991 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
3995 proto_item_append_text(ti, ", FragLen: %u, Call: %u", hdr.frag_len, hdr.call_id);
3999 * None of the stuff done above should throw an exception, because
4000 * we would have rejected this as "not DCE RPC" if we didn't have all
4001 * of it. (XXX - perhaps we should request reassembly if we have
4002 * enough of the header to consider it DCE RPC but not enough to
4003 * get the fragment length; in that case the stuff still wouldn't
4004 * throw an exception.)
4006 * The rest of the stuff might, so return the PDU length to our caller.
4007 * XXX - should we construct a tvbuff containing only the PDU and
4008 * use that? Or should we have separate "is this a DCE RPC PDU",
4009 * "how long is it", and "dissect it" routines - which might let us
4010 * do most of the work in "tcp_dissect_pdus()"?
4012 if (pkt_len != NULL)
4013 *pkt_len = hdr.frag_len + padding;
4015 /* The remaining bytes in the current tvb might contain multiple
4016 * DCE/RPC fragments, so create a new tvb subset for this fragment.
4017 * Only limit the end of the fragment, but not the offset start,
4018 * as the authentication function dissect_dcerpc_cn_auth() will fail
4019 * (and other functions might fail as well) computing the right start
4022 fragment_tvb = tvb_new_subset(tvb, 0,
4023 MIN((hdr.frag_len + (guint) start_offset), tvb_length(tvb)) /* length */,
4024 hdr.frag_len + start_offset /* reported_length */);
4027 * Packet type specific stuff is next.
4029 switch (hdr.ptype) {
4032 dissect_dcerpc_cn_bind (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr);
4037 dissect_dcerpc_cn_bind_ack (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr);
4042 * Nothing after the common header other than credentials.
4044 dissect_dcerpc_cn_auth (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr, TRUE,
4049 dissect_dcerpc_cn_rqst (fragment_tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
4053 dissect_dcerpc_cn_resp (fragment_tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
4057 dissect_dcerpc_cn_fault (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr);
4061 dissect_dcerpc_cn_bind_nak (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr);
4067 * Nothing after the common header other than an authentication
4070 dissect_dcerpc_cn_auth (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
4076 * Nothing after the common header, not even an authentication
4082 /* might as well dissect the auth info */
4083 dissect_dcerpc_cn_auth (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
4091 * DCERPC dissector for connection oriented calls over packet-oriented
4095 dissect_dcerpc_cn_pk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4098 * Only one PDU per transport packet, and only one transport
4101 pinfo->dcetransporttype=DCE_TRANSPORT_UNKNOWN;
4102 if (!dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE, NULL)) {
4104 * It wasn't a DCERPC PDU.
4116 * DCERPC dissector for connection oriented calls over byte-stream
4118 * we need to distinguish here between SMB and non-TCP (more in the future?)
4119 * to be able to know what kind of private_data structure to expect.
4122 dissect_dcerpc_cn_bs_body (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4124 volatile int offset = 0;
4126 volatile gboolean dcerpc_pdus = 0;
4127 volatile gboolean ret = FALSE;
4130 * There may be multiple PDUs per transport packet; keep
4133 while (tvb_reported_length_remaining(tvb, offset) != 0) {
4135 * Catch ReportedBoundsError, so that even if the stub data is bad,
4136 * we don't abort the full DCE RPC dissection - there might be more
4137 * than one DCE RPC PDU in the data being dissected.
4139 * If we get BoundsError, it means the frame was cut short by a
4140 * snapshot length, so there's nothing more to dissect; just
4141 * re-throw that exception.
4145 if(dissect_dcerpc_cn (tvb, offset, pinfo, tree,
4146 dcerpc_cn_desegment, &pdu_len)) {
4149 } CATCH(BoundsError) {
4151 } CATCH(ReportedBoundsError) {
4152 show_reported_bounds_error(tvb, pinfo, tree);
4154 * Presumably it looked enough like a DCE RPC PDU that we
4155 * dissected enough of it to throw an exception.
4168 * Well, we've seen at least one DCERPC PDU.
4172 /* if we had more than one Req/Resp in this PDU change the protocol column */
4173 /* this will formerly contain the last interface name, which may not be the same for all Req/Resp */
4174 if (dcerpc_pdus >= 2 && check_col (pinfo->cinfo, COL_PROTOCOL))
4175 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "%u*DCERPC", dcerpc_pdus);
4179 * Desegmentation required - bail now, but give the user a hint that desegmentation might be done later.
4181 proto_tree_add_uint_format(tree, hf_dcerpc_cn_deseg_req, tvb, offset,
4183 tvb_reported_length_remaining(tvb, offset),
4184 "[DCE RPC: %u byte%s left, desegmentation might follow]",
4185 tvb_reported_length_remaining(tvb, offset),
4186 plurality(tvb_reported_length_remaining(tvb, offset), "", "s"));
4191 * Step to the next PDU.
4199 dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4201 pinfo->dcetransporttype=DCE_TRANSPORT_UNKNOWN;
4202 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
4206 dissect_dcerpc_cn_smbpipe (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4208 pinfo->dcetransporttype=DCE_CN_TRANSPORT_SMBPIPE;
4209 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
4215 dissect_dcerpc_dg_auth (tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
4216 e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
4218 proto_item *ti = NULL;
4219 proto_tree *auth_tree = NULL;
4220 guint8 protection_level;
4223 * Initially set "*auth_level_p" to -1 to indicate that we haven't
4224 * yet seen any authentication level information.
4226 if (auth_level_p != NULL)
4230 * The authentication information is at the *end* of the PDU; in
4231 * request and response PDUs, the request and response stub data
4234 * If the full packet is here, and there's data past the end of the
4235 * packet body, then dissect the auth info.
4237 offset += hdr->frag_len;
4238 if (tvb_length_remaining(tvb, offset) > 0) {
4239 switch (hdr->auth_proto) {
4241 case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
4242 ti = proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Kerberos authentication verifier");
4243 auth_tree = proto_item_add_subtree (ti, ett_dcerpc_krb5_auth_verf);
4244 protection_level = tvb_get_guint8 (tvb, offset);
4245 if (auth_level_p != NULL)
4246 *auth_level_p = protection_level;
4247 proto_tree_add_uint (auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
4249 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, FALSE);
4251 if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
4252 offset += 6; /* 6 bytes of padding */
4254 offset += 2; /* 6 bytes of padding */
4255 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, FALSE);
4260 proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Authentication verifier");
4267 dissect_dcerpc_dg_cancel_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
4268 proto_tree *dcerpc_tree,
4269 e_dce_dg_common_hdr_t *hdr)
4273 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4274 hdr->drep, hf_dcerpc_dg_cancel_vers,
4280 /* The only version we know about */
4281 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4282 hdr->drep, hf_dcerpc_dg_cancel_id,
4284 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
4285 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
4292 dissect_dcerpc_dg_cancel (tvbuff_t *tvb, int offset, packet_info *pinfo,
4293 proto_tree *dcerpc_tree,
4294 e_dce_dg_common_hdr_t *hdr)
4298 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4299 hdr->drep, hf_dcerpc_dg_cancel_vers,
4305 /* The only version we know about */
4306 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4307 hdr->drep, hf_dcerpc_dg_cancel_id,
4309 /* XXX - are NDR booleans 32 bits? */
4311 /* XXX - the RPC reference in chapter: "the cancel PDU" doesn't mention
4312 the accepting_cancels field (it's only in the cancel_ack PDU)! */
4313 /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4314 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
4321 dissect_dcerpc_dg_fack (tvbuff_t *tvb, int offset, packet_info *pinfo,
4322 proto_tree *dcerpc_tree,
4323 e_dce_dg_common_hdr_t *hdr)
4330 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
4331 hdr->drep, hf_dcerpc_dg_fack_vers,
4338 case 0: /* The only version documented in the DCE RPC 1.1 spec */
4339 case 1: /* This appears to be the same */
4340 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
4341 hdr->drep, hf_dcerpc_dg_fack_window_size,
4343 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4344 hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
4346 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4347 hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
4349 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
4350 hdr->drep, hf_dcerpc_dg_fack_serial_num,
4352 if (check_col (pinfo->cinfo, COL_INFO)) {
4353 col_append_fstr (pinfo->cinfo, COL_INFO, " serial: %u",
4356 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
4357 hdr->drep, hf_dcerpc_dg_fack_selack_len,
4359 for (i = 0; i < selack_len; i++) {
4360 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4361 hdr->drep, hf_dcerpc_dg_fack_selack,
4370 dissect_dcerpc_dg_reject_fault (tvbuff_t *tvb, int offset, packet_info *pinfo,
4371 proto_tree *dcerpc_tree,
4372 e_dce_dg_common_hdr_t *hdr)
4376 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4377 hdr->drep, hf_dcerpc_dg_status,
4380 if (check_col (pinfo->cinfo, COL_INFO)) {
4381 col_append_fstr (pinfo->cinfo, COL_INFO,
4383 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
4388 dissect_dcerpc_dg_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
4389 proto_tree *dcerpc_tree, proto_tree *tree,
4390 e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
4392 int length, reported_length, stub_length;
4393 gboolean save_fragmented;
4394 fragment_data *fd_head;
4397 proto_item *parent_pi;
4399 if (check_col (pinfo->cinfo, COL_INFO))
4400 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u len: %u",
4401 di->call_data->opnum, hdr->frag_len );
4403 length = tvb_length_remaining (tvb, offset);
4404 reported_length = tvb_reported_length_remaining (tvb, offset);
4405 stub_length = hdr->frag_len;
4406 if (length > stub_length)
4407 length = stub_length;
4408 if (reported_length > stub_length)
4409 reported_length = stub_length;
4411 save_fragmented = pinfo->fragmented;
4413 /* If we don't have reassembly enabled, or this packet contains
4414 the entire PDU, or if this is a short frame (or a frame
4415 not reassembled at a lower layer) that doesn't include all
4416 the data in the fragment, just call the handoff directly if
4417 this is the first fragment or the PDU isn't fragmented. */
4418 if( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
4419 !tvb_bytes_exist(tvb, offset, stub_length) ){
4420 if(hdr->frag_num == 0) {
4423 /* First fragment, possibly the only fragment */
4426 * XXX - authentication info?
4428 pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
4429 next_tvb = tvb_new_subset (tvb, offset, length,
4431 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
4432 next_tvb, hdr->drep, di, NULL);
4434 /* PDU is fragmented and this isn't the first fragment */
4435 if (check_col(pinfo->cinfo, COL_INFO)) {
4436 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
4440 tvb_ensure_bytes_exist(tvb, offset, stub_length);
4441 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
4442 "Fragment data (%d byte%s)",
4444 plurality(stub_length, "", "s"));
4449 /* Reassembly is enabled, the PDU is fragmented, and
4450 we have all the data in the fragment; the first two
4451 of those mean we should attempt reassembly, and the
4452 third means we can attempt reassembly. */
4455 tvb_ensure_bytes_exist(tvb, offset, stub_length);
4456 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
4457 "Fragment data (%d byte%s)", stub_length,
4458 plurality(stub_length, "", "s"));
4462 fd_head = fragment_add_dcerpc_dg(tvb, offset, pinfo,
4463 hdr->seqnum, &hdr->act_id, dcerpc_cl_reassemble_table,
4464 hdr->frag_num, stub_length,
4465 !(hdr->flags1 & PFCL1_LASTFRAG));
4466 if (fd_head != NULL) {
4467 /* We completed reassembly... */
4468 if(pinfo->fd->num==fd_head->reassembled_in) {
4469 /* ...and this is the reassembled RPC PDU */
4470 next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
4471 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
4472 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
4473 show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
4474 tree, pinfo, next_tvb, &pi);
4477 * XXX - authentication info?
4479 pinfo->fragmented = FALSE;
4480 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
4481 next_tvb, hdr->drep, di, NULL);
4483 /* ...and this isn't the reassembled RPC PDU */
4484 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
4485 tvb, 0, 0, fd_head->reassembled_in);
4486 PROTO_ITEM_SET_GENERATED(pi);
4487 parent_pi = proto_tree_get_parent(dcerpc_tree);
4488 if(parent_pi != NULL) {
4489 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
4491 if (check_col(pinfo->cinfo, COL_INFO)) {
4492 col_append_fstr(pinfo->cinfo, COL_INFO,
4493 " [DCE/RPC fragment, reas: #%u]", fd_head->reassembled_in);
4497 /* Reassembly isn't completed yet */
4498 if (check_col(pinfo->cinfo, COL_INFO)) {
4499 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
4503 pinfo->fragmented = save_fragmented;
4507 dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo,
4508 proto_tree *dcerpc_tree, proto_tree *tree,
4509 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4512 dcerpc_call_value *value, v;
4513 dcerpc_matched_key matched_key, *new_matched_key;
4515 proto_item *parent_pi;
4518 if(!(pinfo->fd->flags.visited)){
4519 dcerpc_call_value *call_value;
4520 dcerpc_dg_call_key *call_key;
4522 call_key=se_alloc (sizeof (dcerpc_dg_call_key));
4523 call_key->conv=conv;
4524 call_key->seqnum=hdr->seqnum;
4525 call_key->act_id=hdr->act_id;
4527 call_value=se_alloc (sizeof (dcerpc_call_value));
4528 call_value->uuid = hdr->if_id;
4529 call_value->ver = hdr->if_ver;
4530 call_value->opnum = hdr->opnum;
4531 call_value->req_frame=pinfo->fd->num;
4532 call_value->req_time=pinfo->fd->abs_ts;
4533 call_value->rep_frame=0;
4534 call_value->max_ptr=0;
4535 call_value->private_data = NULL;
4536 g_hash_table_insert (dcerpc_dg_calls, call_key, call_value);
4538 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
4539 new_matched_key->frame = pinfo->fd->num;
4540 new_matched_key->call_id = hdr->seqnum;
4541 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
4544 matched_key.frame = pinfo->fd->num;
4545 matched_key.call_id = hdr->seqnum;
4546 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
4548 v.uuid = hdr->if_id;
4549 v.ver = hdr->if_ver;
4550 v.opnum = hdr->opnum;
4551 v.req_frame = pinfo->fd->num;
4554 v.private_data=NULL;
4559 di->call_id = hdr->seqnum;
4561 di->ptype = PDU_REQ;
4562 di->call_data = value;
4564 if(value->rep_frame!=0){
4565 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
4566 tvb, 0, 0, value->rep_frame);
4567 PROTO_ITEM_SET_GENERATED(pi);
4568 parent_pi = proto_tree_get_parent(dcerpc_tree);
4569 if(parent_pi != NULL) {
4570 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
4573 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
4577 dissect_dcerpc_dg_resp (tvbuff_t *tvb, int offset, packet_info *pinfo,
4578 proto_tree *dcerpc_tree, proto_tree *tree,
4579 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4582 dcerpc_call_value *value, v;
4583 dcerpc_matched_key matched_key, *new_matched_key;
4585 proto_item *parent_pi;
4588 if(!(pinfo->fd->flags.visited)){
4589 dcerpc_call_value *call_value;
4590 dcerpc_dg_call_key call_key;
4593 call_key.seqnum=hdr->seqnum;
4594 call_key.act_id=hdr->act_id;
4596 if((call_value=g_hash_table_lookup(dcerpc_dg_calls, &call_key))){
4597 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
4598 new_matched_key->frame = pinfo->fd->num;
4599 new_matched_key->call_id = hdr->seqnum;
4600 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
4601 if(call_value->rep_frame==0){
4602 call_value->rep_frame=pinfo->fd->num;
4607 matched_key.frame = pinfo->fd->num;
4608 matched_key.call_id = hdr->seqnum;
4609 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
4611 v.uuid = hdr->if_id;
4612 v.ver = hdr->if_ver;
4613 v.opnum = hdr->opnum;
4615 v.rep_frame=pinfo->fd->num;
4616 v.private_data=NULL;
4623 di->ptype = PDU_RESP;
4624 di->call_data = value;
4626 if(value->req_frame!=0){
4628 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4629 tvb, 0, 0, value->req_frame);
4630 PROTO_ITEM_SET_GENERATED(pi);
4631 parent_pi = proto_tree_get_parent(dcerpc_tree);
4632 if(parent_pi != NULL) {
4633 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
4635 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
4636 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
4637 PROTO_ITEM_SET_GENERATED(pi);
4639 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
4643 dissect_dcerpc_dg_ping_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
4644 proto_tree *dcerpc_tree,
4645 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4647 proto_item *parent_pi;
4648 /* if(!(pinfo->fd->flags.visited)){*/
4649 dcerpc_call_value *call_value;
4650 dcerpc_dg_call_key call_key;
4653 call_key.seqnum=hdr->seqnum;
4654 call_key.act_id=hdr->act_id;
4656 if((call_value=g_hash_table_lookup(dcerpc_dg_calls, &call_key))){
4660 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4661 tvb, 0, 0, call_value->req_frame);
4662 PROTO_ITEM_SET_GENERATED(pi);
4663 parent_pi = proto_tree_get_parent(dcerpc_tree);
4664 if(parent_pi != NULL) {
4665 proto_item_append_text(parent_pi, ", [Req: #%u]", call_value->req_frame);
4668 if (check_col (pinfo->cinfo, COL_INFO))
4669 col_append_fstr(pinfo->cinfo, COL_INFO, " [req: #%u]", call_value->req_frame);
4671 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &call_value->req_time);
4672 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
4673 PROTO_ITEM_SET_GENERATED(pi);
4679 * DCERPC dissector for connectionless calls
4682 dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4684 proto_item *ti = NULL;
4685 proto_item *tf = NULL;
4686 proto_tree *dcerpc_tree = NULL;
4687 proto_tree *dg_flags1_tree = NULL;
4688 proto_tree *dg_flags2_tree = NULL;
4689 proto_tree *drep_tree = NULL;
4690 e_dce_dg_common_hdr_t hdr;
4692 conversation_t *conv;
4694 char uuid_str[DCERPC_UUID_STR_LEN];
4698 * Check if this looks like a CL DCERPC call. All dg packets
4699 * have an 80 byte header on them. Which starts with
4700 * version (4), pkt_type.
4702 if (!tvb_bytes_exist (tvb, 0, sizeof (hdr))) {
4706 /* Version must be 4 */
4707 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
4708 if (hdr.rpc_ver != 4)
4711 /* Type must be <=19 or its not DCE/RPC */
4712 hdr.ptype = tvb_get_guint8 (tvb, offset++);
4716 /* flags1 has bit 1 and 8 as reserved so if any of them are set, it is
4717 probably not a DCE/RPC packet
4719 hdr.flags1 = tvb_get_guint8 (tvb, offset++);
4723 /* flags2 has all bits except bit 2 as reserved so if any of them are set
4724 it is probably not DCE/RPC.
4726 hdr.flags2 = tvb_get_guint8 (tvb, offset++);
4731 if (check_col (pinfo->cinfo, COL_PROTOCOL))
4732 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
4733 if (check_col (pinfo->cinfo, COL_INFO))
4734 col_add_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
4736 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
4737 offset += sizeof (hdr.drep);
4738 hdr.serial_hi = tvb_get_guint8 (tvb, offset++);
4739 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.obj_id);
4741 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.if_id);
4743 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.act_id);
4745 hdr.server_boot = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4747 hdr.if_ver = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4749 hdr.seqnum = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4751 hdr.opnum = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4753 hdr.ihint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4755 hdr.ahint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4757 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4759 hdr.frag_num = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4761 hdr.auth_proto = tvb_get_guint8 (tvb, offset++);
4762 hdr.serial_lo = tvb_get_guint8 (tvb, offset++);
4765 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, -1, FALSE);
4767 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
4768 proto_item_append_text(ti, " %s, Seq: %u, Serial: %u, Frag: %u, FragLen: %u",
4769 val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"),
4770 hdr.seqnum, hdr.serial_hi*256+hdr.serial_lo,
4771 hdr.frag_num, hdr.frag_len);
4777 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
4781 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
4785 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
4786 dg_flags1_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags1);
4787 if (dg_flags1_tree) {
4788 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
4789 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
4790 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
4791 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
4792 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
4793 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
4794 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
4795 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
4797 proto_item_append_text(tf, " %s%s%s%s%s%s",
4798 (hdr.flags1 & PFCL1_BROADCAST) ? "\"Broadcast\" " : "",
4799 (hdr.flags1 & PFCL1_IDEMPOTENT) ? "\"Idempotent\" " : "",
4800 (hdr.flags1 & PFCL1_MAYBE) ? "\"Maybe\" " : "",
4801 (hdr.flags1 & PFCL1_NOFACK) ? "\"No Fack\" " : "",
4802 (hdr.flags1 & PFCL1_FRAG) ? "\"Fragment\" " : "",
4803 (hdr.flags1 & PFCL1_LASTFRAG) ? "\"Last Fragment\" " : "");
4810 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
4811 dg_flags2_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags2);
4812 if (dg_flags2_tree) {
4813 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
4814 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
4815 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
4816 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
4817 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
4818 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
4819 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
4820 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
4822 proto_item_append_text(tf, " %s",
4823 (hdr.flags2 & PFCL2_CANCEL_PENDING) ? "\"Cancel Pending\" " : "");
4830 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
4831 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
4833 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
4834 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
4835 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
4836 proto_item_append_text(tf, " (Order: %s, Char: %s, Float: %s)",
4837 val_to_str(hdr.drep[0] >> 4, drep_byteorder_vals, "Unknown"),
4838 val_to_str(hdr.drep[0] & 0x0f, drep_character_vals, "Unknown"),
4839 val_to_str(hdr.drep[1], drep_fp_vals, "Unknown"));
4842 offset += sizeof (hdr.drep);
4845 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
4849 /* XXX - use "dissect_ndr_uuid_t()"? */
4850 uuid_str_len = g_snprintf(uuid_str, DCERPC_UUID_STR_LEN,
4851 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
4852 hdr.obj_id.Data1, hdr.obj_id.Data2, hdr.obj_id.Data3,
4853 hdr.obj_id.Data4[0],
4854 hdr.obj_id.Data4[1],
4855 hdr.obj_id.Data4[2],
4856 hdr.obj_id.Data4[3],
4857 hdr.obj_id.Data4[4],
4858 hdr.obj_id.Data4[5],
4859 hdr.obj_id.Data4[6],
4860 hdr.obj_id.Data4[7]);
4861 if (uuid_str_len == -1 || uuid_str_len >= DCERPC_UUID_STR_LEN)
4862 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
4863 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
4864 offset, 16, uuid_str, "Object UUID: %s", uuid_str);
4869 /* XXX - use "dissect_ndr_uuid_t()"? */
4870 uuid_str_len = g_snprintf(uuid_str, DCERPC_UUID_STR_LEN,
4871 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
4872 hdr.if_id.Data1, hdr.if_id.Data2, hdr.if_id.Data3,
4880 hdr.if_id.Data4[7]);
4881 if (uuid_str_len == -1 || uuid_str_len >= DCERPC_UUID_STR_LEN)
4882 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
4883 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
4884 offset, 16, uuid_str, "Interface: %s", uuid_str);
4889 /* XXX - use "dissect_ndr_uuid_t()"? */
4890 uuid_str_len = g_snprintf(uuid_str, DCERPC_UUID_STR_LEN,
4891 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
4892 hdr.act_id.Data1, hdr.act_id.Data2, hdr.act_id.Data3,
4893 hdr.act_id.Data4[0],
4894 hdr.act_id.Data4[1],
4895 hdr.act_id.Data4[2],
4896 hdr.act_id.Data4[3],
4897 hdr.act_id.Data4[4],
4898 hdr.act_id.Data4[5],
4899 hdr.act_id.Data4[6],
4900 hdr.act_id.Data4[7]);
4901 if (uuid_str_len == -1 || uuid_str_len >= DCERPC_UUID_STR_LEN)
4902 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
4903 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
4904 offset, 16, uuid_str, "Activity: %s", uuid_str);
4909 nstime_t server_boot;
4911 server_boot.secs = hdr.server_boot;
4912 server_boot.nsecs = 0;
4914 if (hdr.server_boot == 0)
4915 proto_tree_add_time_format (dcerpc_tree, hf_dcerpc_dg_server_boot,
4916 tvb, offset, 4, &server_boot,
4917 "Server boot time: Unknown (0)");
4919 proto_tree_add_time (dcerpc_tree, hf_dcerpc_dg_server_boot,
4920 tvb, offset, 4, &server_boot);
4925 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
4929 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
4930 if (check_col (pinfo->cinfo, COL_INFO)) {
4931 col_append_fstr (pinfo->cinfo, COL_INFO, ": seq: %u", hdr.seqnum);
4933 if (check_col (pinfo->cinfo, COL_DCE_CALL)) {
4934 col_append_fstr (pinfo->cinfo, COL_DCE_CALL, "%u", hdr.seqnum);
4939 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
4943 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
4947 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
4951 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
4955 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
4956 if (check_col (pinfo->cinfo, COL_INFO)) {
4957 if (hdr.flags1 & PFCL1_FRAG) {
4958 /* Fragmented - put the fragment number into the Info column */
4959 col_append_fstr (pinfo->cinfo, COL_INFO, " frag: %u",
4966 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
4970 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
4971 if (check_col (pinfo->cinfo, COL_INFO)) {
4972 if (hdr.flags1 & PFCL1_FRAG) {
4973 /* Fragmented - put the serial number into the Info column */
4974 col_append_fstr (pinfo->cinfo, COL_INFO, " serial: %u",
4975 (hdr.serial_hi << 8) | hdr.serial_lo);
4982 * XXX - for Kerberos, we get a protection level; if it's
4983 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
4986 dissect_dcerpc_dg_auth (tvb, offset, dcerpc_tree, &hdr,
4991 * keeping track of the conversation shouldn't really be necessary
4992 * for connectionless packets, because everything we need to know
4993 * to dissect is in the header for each packet. Unfortunately,
4994 * Microsoft's implementation is buggy and often puts the
4995 * completely wrong if_id in the header. go figure. So, keep
4996 * track of the seqnum and use that if possible. Note: that's not
4997 * completely correct. It should really be done based on both the
4998 * activity_id and seqnum. I haven't seen anywhere that it would
4999 * make a difference, but for future reference...
5001 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
5002 pinfo->srcport, pinfo->destport, 0);
5004 conv = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
5005 pinfo->srcport, pinfo->destport, 0);
5009 * Packet type specific stuff is next.
5012 switch (hdr.ptype) {
5014 case PDU_CANCEL_ACK:
5015 /* Body is optional */
5016 /* XXX - we assume "frag_len" is the length of the body */
5017 if (hdr.frag_len != 0)
5018 dissect_dcerpc_dg_cancel_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
5023 * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
5024 * but in at least one capture none of the Cl_cancel PDUs had a
5027 /* XXX - we assume "frag_len" is the length of the body */
5028 if (hdr.frag_len != 0)
5029 dissect_dcerpc_dg_cancel (tvb, offset, pinfo, dcerpc_tree, &hdr);
5033 /* Body is optional; if present, it's the same as PDU_FACK */
5034 /* XXX - we assume "frag_len" is the length of the body */
5035 if (hdr.frag_len != 0)
5036 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
5040 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
5045 dissect_dcerpc_dg_reject_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
5049 dissect_dcerpc_dg_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
5053 dissect_dcerpc_dg_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
5056 /* these requests have no body */
5059 dissect_dcerpc_dg_ping_ack (tvb, offset, pinfo, dcerpc_tree, &hdr, conv);
5070 dcerpc_init_protocol (void)
5072 /* structures and data for BIND */
5074 g_hash_table_destroy (dcerpc_binds);
5078 dcerpc_binds = g_hash_table_new (dcerpc_bind_hash, dcerpc_bind_equal);
5081 /* structures and data for CALL */
5082 if (dcerpc_cn_calls){
5083 g_hash_table_destroy (dcerpc_cn_calls);
5085 dcerpc_cn_calls = g_hash_table_new (dcerpc_cn_call_hash, dcerpc_cn_call_equal);
5086 if (dcerpc_dg_calls){
5087 g_hash_table_destroy (dcerpc_dg_calls);
5089 dcerpc_dg_calls = g_hash_table_new (dcerpc_dg_call_hash, dcerpc_dg_call_equal);
5091 /* structure and data for MATCHED */
5092 if (dcerpc_matched){
5093 g_hash_table_destroy (dcerpc_matched);
5095 dcerpc_matched = g_hash_table_new (dcerpc_matched_hash, dcerpc_matched_equal);
5097 /* call the registered hooks */
5098 g_hook_list_invoke(&dcerpc_hooks_init_protos, FALSE /* not may_recurse */);
5102 proto_register_dcerpc (void)
5104 static hf_register_info hf[] = {
5105 { &hf_dcerpc_request_in,
5106 { "Request in frame", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE,
5107 NULL, 0, "This packet is a response to the packet with this number", HFILL }},
5108 { &hf_dcerpc_response_in,
5109 { "Response in frame", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
5110 NULL, 0, "This packet will be responded in the packet with this number", HFILL }},
5111 { &hf_dcerpc_referent_id,
5112 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
5113 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
5115 { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5116 { &hf_dcerpc_ver_minor,
5117 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5118 { &hf_dcerpc_packet_type,
5119 { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS (pckt_vals), 0x0, "", HFILL }},
5120 { &hf_dcerpc_cn_flags,
5121 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
5122 { &hf_dcerpc_cn_flags_first_frag,
5123 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_FIRST_FRAG, "", HFILL }},
5124 { &hf_dcerpc_cn_flags_last_frag,
5125 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_LAST_FRAG, "", HFILL }},
5126 { &hf_dcerpc_cn_flags_cancel_pending,
5127 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_PENDING_CANCEL, "", HFILL }},
5128 { &hf_dcerpc_cn_flags_reserved,
5129 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_RESERVED_1, "", HFILL }},
5130 { &hf_dcerpc_cn_flags_mpx,
5131 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_CONC_MPX, "", HFILL }},
5132 { &hf_dcerpc_cn_flags_dne,
5133 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_DID_NOT_EXECUTE, "", HFILL }},
5134 { &hf_dcerpc_cn_flags_maybe,
5135 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_MAYBE, "", HFILL }},
5136 { &hf_dcerpc_cn_flags_object,
5137 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_OBJECT_UUID, "", HFILL }},
5139 { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
5140 { &hf_dcerpc_drep_byteorder,
5141 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS (drep_byteorder_vals), 0x0, "", HFILL }},
5142 { &hf_dcerpc_drep_character,
5143 { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS (drep_character_vals), 0x0, "", HFILL }},
5144 { &hf_dcerpc_drep_fp,
5145 { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS (drep_fp_vals), 0x0, "", HFILL }},
5146 { &hf_dcerpc_cn_frag_len,
5147 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5148 { &hf_dcerpc_cn_auth_len,
5149 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5150 { &hf_dcerpc_cn_call_id,
5151 { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5152 { &hf_dcerpc_cn_max_xmit,
5153 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5154 { &hf_dcerpc_cn_max_recv,
5155 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5156 { &hf_dcerpc_cn_assoc_group,
5157 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
5158 { &hf_dcerpc_cn_num_ctx_items,
5159 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5160 { &hf_dcerpc_cn_ctx_id,
5161 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5162 { &hf_dcerpc_cn_num_trans_items,
5163 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5164 { &hf_dcerpc_cn_bind_if_id,
5165 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
5166 { &hf_dcerpc_cn_bind_if_ver,
5167 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5168 { &hf_dcerpc_cn_bind_if_ver_minor,
5169 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5170 { &hf_dcerpc_cn_bind_trans_id,
5171 { "Transfer Syntax", "dcerpc.cn_bind_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
5172 { &hf_dcerpc_cn_bind_trans_ver,
5173 { "Syntax ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5174 { &hf_dcerpc_cn_alloc_hint,
5175 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5176 { &hf_dcerpc_cn_sec_addr_len,
5177 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5178 { &hf_dcerpc_cn_sec_addr,
5179 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, "", HFILL }},
5180 { &hf_dcerpc_cn_num_results,
5181 { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5182 { &hf_dcerpc_cn_ack_result,
5183 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, "", HFILL }},
5184 { &hf_dcerpc_cn_ack_reason,
5185 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, "", HFILL }},
5186 { &hf_dcerpc_cn_ack_trans_id,
5187 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
5188 { &hf_dcerpc_cn_ack_trans_ver,
5189 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5190 { &hf_dcerpc_cn_reject_reason,
5191 { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, "", HFILL }},
5192 { &hf_dcerpc_cn_num_protocols,
5193 { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5194 { &hf_dcerpc_cn_protocol_ver_major,
5195 { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5196 { &hf_dcerpc_cn_protocol_ver_minor,
5197 { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5198 { &hf_dcerpc_cn_cancel_count,
5199 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5200 { &hf_dcerpc_cn_status,
5201 { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
5202 { &hf_dcerpc_cn_deseg_req,
5203 { "Desegmentation Required", "dcerpc.cn_deseg_req", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5204 { &hf_dcerpc_auth_type,
5205 { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
5206 { &hf_dcerpc_auth_level,
5207 { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS (authn_level_vals), 0x0, "", HFILL }},
5208 { &hf_dcerpc_auth_pad_len,
5209 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5210 { &hf_dcerpc_auth_rsrvd,
5211 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5212 { &hf_dcerpc_auth_ctx_id,
5213 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5214 { &hf_dcerpc_dg_flags1,
5215 { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
5216 { &hf_dcerpc_dg_flags1_rsrvd_01,
5217 { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_01, "", HFILL }},
5218 { &hf_dcerpc_dg_flags1_last_frag,
5219 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_LASTFRAG, "", HFILL }},
5220 { &hf_dcerpc_dg_flags1_frag,
5221 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_FRAG, "", HFILL }},
5222 { &hf_dcerpc_dg_flags1_nofack,
5223 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_NOFACK, "", HFILL }},
5224 { &hf_dcerpc_dg_flags1_maybe,
5225 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_MAYBE, "", HFILL }},
5226 { &hf_dcerpc_dg_flags1_idempotent,
5227 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_IDEMPOTENT, "", HFILL }},
5228 { &hf_dcerpc_dg_flags1_broadcast,
5229 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_BROADCAST, "", HFILL }},
5230 { &hf_dcerpc_dg_flags1_rsrvd_80,
5231 { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_80, "", HFILL }},
5232 { &hf_dcerpc_dg_flags2,
5233 { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
5234 { &hf_dcerpc_dg_flags2_rsrvd_01,
5235 { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_01, "", HFILL }},
5236 { &hf_dcerpc_dg_flags2_cancel_pending,
5237 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_CANCEL_PENDING, "", HFILL }},
5238 { &hf_dcerpc_dg_flags2_rsrvd_04,
5239 { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_04, "", HFILL }},
5240 { &hf_dcerpc_dg_flags2_rsrvd_08,
5241 { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_08, "", HFILL }},
5242 { &hf_dcerpc_dg_flags2_rsrvd_10,
5243 { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_10, "", HFILL }},
5244 { &hf_dcerpc_dg_flags2_rsrvd_20,
5245 { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_20, "", HFILL }},
5246 { &hf_dcerpc_dg_flags2_rsrvd_40,
5247 { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_40, "", HFILL }},
5248 { &hf_dcerpc_dg_flags2_rsrvd_80,
5249 { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_80, "", HFILL }},
5250 { &hf_dcerpc_dg_serial_lo,
5251 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
5252 { &hf_dcerpc_dg_serial_hi,
5253 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
5254 { &hf_dcerpc_dg_ahint,
5255 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
5256 { &hf_dcerpc_dg_ihint,
5257 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
5258 { &hf_dcerpc_dg_frag_len,
5259 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5260 { &hf_dcerpc_dg_frag_num,
5261 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5262 { &hf_dcerpc_dg_auth_proto,
5263 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
5264 { &hf_dcerpc_dg_seqnum,
5265 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5266 { &hf_dcerpc_dg_server_boot,
5267 { "Server boot time", "dcerpc.dg_server_boot", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0, "", HFILL }},
5268 { &hf_dcerpc_dg_if_ver,
5269 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5270 { &hf_dcerpc_krb5_av_prot_level,
5271 { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, "", HFILL }},
5272 { &hf_dcerpc_krb5_av_key_vers_num,
5273 { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5274 { &hf_dcerpc_krb5_av_key_auth_verifier,
5275 { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
5276 { &hf_dcerpc_obj_id,
5277 { "Object", "dcerpc.obj_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
5278 { &hf_dcerpc_dg_if_id,
5279 { "Interface", "dcerpc.dg_if_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
5280 { &hf_dcerpc_dg_act_id,
5281 { "Activity", "dcerpc.dg_act_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
5283 { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5285 { &hf_dcerpc_dg_cancel_vers,
5286 { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5288 { &hf_dcerpc_dg_cancel_id,
5289 { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5291 { &hf_dcerpc_dg_server_accepting_cancels,
5292 { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
5294 { &hf_dcerpc_dg_fack_vers,
5295 { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5297 { &hf_dcerpc_dg_fack_window_size,
5298 { "Window Size", "dcerpc.fack_window_size", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5300 { &hf_dcerpc_dg_fack_max_tsdu,
5301 { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5303 { &hf_dcerpc_dg_fack_max_frag_size,
5304 { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5306 { &hf_dcerpc_dg_fack_serial_num,
5307 { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5309 { &hf_dcerpc_dg_fack_selack_len,
5310 { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5312 { &hf_dcerpc_dg_fack_selack,
5313 { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
5315 { &hf_dcerpc_dg_status,
5316 { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
5318 { &hf_dcerpc_array_max_count,
5319 { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
5321 { &hf_dcerpc_array_offset,
5322 { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
5324 { &hf_dcerpc_array_actual_count,
5325 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
5327 { &hf_dcerpc_array_buffer,
5328 { "Buffer", "dcerpc.array.buffer", FT_BYTES, BASE_NONE, NULL, 0x0, "Buffer: Buffer containing elements of the array", HFILL }},
5331 { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5333 { &hf_dcerpc_fragments,
5334 { "Reassembled DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
5335 NULL, 0x0, "DCE/RPC Fragments", HFILL }},
5337 { &hf_dcerpc_fragment,
5338 { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM, BASE_NONE,
5339 NULL, 0x0, "DCE/RPC Fragment", HFILL }},
5341 { &hf_dcerpc_fragment_overlap,
5342 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE,
5343 NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
5345 { &hf_dcerpc_fragment_overlap_conflict,
5346 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE,
5347 NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
5349 { &hf_dcerpc_fragment_multiple_tails,
5350 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE,
5351 NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
5353 { &hf_dcerpc_fragment_too_long_fragment,
5354 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE,
5355 NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
5357 { &hf_dcerpc_fragment_error,
5358 { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE,
5359 NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
5362 { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE,
5363 NULL, 0, "Time between Request and Response for DCE-RPC calls", HFILL }},
5365 { &hf_dcerpc_reassembled_in,
5366 { "Reassembled PDU in frame", "dcerpc.reassembled_in", FT_FRAMENUM, BASE_NONE,
5367 NULL, 0x0, "The DCE/RPC PDU is completely reassembled in the packet with this number", HFILL }},
5369 { &hf_dcerpc_unknown_if_id,
5370 { "Unknown DCERPC interface id", "dcerpc.unknown_if_id", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
5372 static gint *ett[] = {
5374 &ett_dcerpc_cn_flags,
5376 &ett_dcerpc_cn_iface,
5378 &ett_dcerpc_dg_flags1,
5379 &ett_dcerpc_dg_flags2,
5380 &ett_dcerpc_pointer_data,
5382 &ett_dcerpc_fragments,
5383 &ett_dcerpc_fragment,
5384 &ett_dcerpc_krb5_auth_verf,
5386 module_t *dcerpc_module;
5388 proto_dcerpc = proto_register_protocol ("DCE RPC", "DCERPC", "dcerpc");
5389 proto_register_field_array (proto_dcerpc, hf, array_length (hf));
5390 proto_register_subtree_array (ett, array_length (ett));
5391 register_init_routine (dcerpc_init_protocol);
5392 dcerpc_module = prefs_register_protocol (proto_dcerpc, NULL);
5393 prefs_register_bool_preference (dcerpc_module,
5395 "Reassemble DCE/RPC messages spanning multiple TCP segments",
5396 "Whether the DCE/RPC dissector should reassemble messages spanning multiple TCP segments."
5397 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
5398 &dcerpc_cn_desegment);
5399 prefs_register_bool_preference (dcerpc_module,
5400 "reassemble_dcerpc",
5401 "Reassemble DCE/RPC fragments",
5402 "Whether the DCE/RPC dissector should reassemble fragmented DCE/RPC PDUs",
5403 &dcerpc_reassemble);
5404 register_init_routine(dcerpc_reassemble_init);
5405 dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
5406 dcerpc_tap=register_tap("dcerpc");
5408 g_hook_list_init(&dcerpc_hooks_init_protos, sizeof(GHook));
5412 proto_reg_handoff_dcerpc (void)
5414 heur_dissector_add ("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
5415 heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
5416 heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
5417 heur_dissector_add ("smb_transact", dissect_dcerpc_cn_smbpipe, proto_dcerpc);
5418 heur_dissector_add ("http", dissect_dcerpc_cn_bs, proto_dcerpc);
5419 dcerpc_smb_init(proto_dcerpc);