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 */
230 static const value_string reject_reason_vals[] = {
231 { REASON_NOT_SPECIFIED, "Reason not specified" },
232 { TEMPORARY_CONGESTION, "Temporary congestion" },
233 { LOCAL_LIMIT_EXCEEDED, "Local limit exceeded" },
234 { CALLED_PADDR_UNKNOWN, "Called paddr unknown" },
235 { PROTOCOL_VERSION_NOT_SUPPORTED, "Protocol version not supported" },
236 { DEFAULT_CONTEXT_NOT_SUPPORTED, "Default context not supported" },
237 { USER_DATA_NOT_READABLE, "User data not readable" },
238 { NO_PSAP_AVAILABLE, "No PSAP available" },
243 * Reject status codes.
245 static const value_string reject_status_vals[] = {
246 { 0, "Stub-defined exception" },
247 { 0x00000001, "nca_s_fault_other" },
248 { 0x00000005, "nca_s_fault_access_denied" },
249 { 0x000006f7, "nca_s_fault_ndr" },
250 { 0x000006d8, "nca_s_fault_cant_perform" },
251 { 0x1c000001, "nca_s_fault_int_div_by_zero" },
252 { 0x1c000002, "nca_s_fault_addr_error" },
253 { 0x1c000003, "nca_s_fault_fp_div_zero" },
254 { 0x1c000004, "nca_s_fault_fp_underflow" },
255 { 0x1c000005, "nca_s_fault_fp_overflow" },
256 { 0x1c000006, "nca_s_fault_invalid_tag" },
257 { 0x1c000007, "nca_s_fault_invalid_bound" },
258 { 0x1c000008, "nca_rpc_version_mismatch" },
259 { 0x1c000009, "nca_unspec_reject" },
260 { 0x1c00000a, "nca_s_bad_actid" },
261 { 0x1c00000b, "nca_who_are_you_failed" },
262 { 0x1c00000c, "nca_manager_not_entered" },
263 { 0x1c00000d, "nca_s_fault_cancel" },
264 { 0x1c00000e, "nca_s_fault_ill_inst" },
265 { 0x1c00000f, "nca_s_fault_fp_error" },
266 { 0x1c000010, "nca_s_fault_int_overflow" },
267 { 0x1c000014, "nca_s_fault_pipe_empty" },
268 { 0x1c000015, "nca_s_fault_pipe_closed" },
269 { 0x1c000016, "nca_s_fault_pipe_order" },
270 { 0x1c000017, "nca_s_fault_pipe_discipline" },
271 { 0x1c000018, "nca_s_fault_pipe_comm_error" },
272 { 0x1c000019, "nca_s_fault_pipe_memory" },
273 { 0x1c00001a, "nca_s_fault_context_mismatch" },
274 { 0x1c00001b, "nca_s_fault_remote_no_memory" },
275 { 0x1c00001c, "nca_invalid_pres_context_id" },
276 { 0x1c00001d, "nca_unsupported_authn_level" },
277 { 0x1c00001f, "nca_invalid_checksum" },
278 { 0x1c000020, "nca_invalid_crc" },
279 { 0x1c000021, "ncs_s_fault_user_defined" },
280 { 0x1c000022, "nca_s_fault_tx_open_failed" },
281 { 0x1c000023, "nca_s_fault_codeset_conv_error" },
282 { 0x1c000024, "nca_s_fault_object_not_found" },
283 { 0x1c000025, "nca_s_fault_no_client_stub" },
284 { 0x1c010002, "nca_op_rng_error" },
285 { 0x1c010003, "nca_unk_if"},
286 { 0x1c010006, "nca_wrong_boot_time" },
287 { 0x1c010009, "nca_s_you_crashed" },
288 { 0x1c01000b, "nca_proto_error" },
289 { 0x1c010013, "nca_out_args_too_big" },
290 { 0x1c010014, "nca_server_too_busy" },
291 { 0x1c010017, "nca_unsupported_type" },
292 /* MS Windows specific values
293 * see: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/system_error_codes__1700-3999_.asp
294 * and: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/seccrypto/security/common_hresult_values.asp
295 * and: http://www.megos.ch/support/doserrors.txt
297 * XXX - we might need a way to dynamically add entries here, as higher layer protocols use these values too,
298 * at least MS protocols (like DCOM) do it that way ... */
299 { 0x80004001, "E_NOTIMPL" },
300 { 0x80004003, "E_POINTER" },
301 { 0x80004004, "E_ABORT" },
302 { 0x80010105, "RPC_E_SERVERFAULT" },
303 { 0x80010108, "RPC_E_DISCONNECTED" },
304 { 0x80010113, "RPC_E_INVALID_IPID" },
305 { 0x80020006, "DISP_E_UNKNOWNNAME" },
306 { 0x8004CB00, "CBA_E_MALFORMED" },
307 { 0x8004CB01, "CBA_E_UNKNOWNOBJECT" },
308 { 0x8004CB09, "CBA_E_INVALIDCOOKIE" },
309 { 0x8004CB0B, "CBA_E_QOSTYPEUNSUPPORTED" },
310 { 0x8004CB0C, "CBA_E_QOSVALUEUNSUPPORTED" },
311 { 0x8004CB0F, "CBA_E_NOTAPPLICABLE" },
312 { 0x8004CB12, "CBA_E_LIMITVIOLATION" },
313 { 0x8007000E, "E_OUTOFMEMORY" },
314 { 0x80070057, "E_INVALIDARG" },
315 { 0x800706d1, "RPC_S_PROCNUM_OUT_OF_RANGE" },
320 /* we need to keep track of what transport were used, ie what handle we came
321 * in through so we know what kind of pinfo->dce_smb_fid was passed to us.
323 /* Value of -1 is reserved for "not DCE packet" in packet_info.dcetransporttype. */
324 #define DCE_TRANSPORT_UNKNOWN 0
325 #define DCE_CN_TRANSPORT_SMBPIPE 1
328 static int proto_dcerpc = -1;
331 static int hf_dcerpc_request_in = -1;
332 static int hf_dcerpc_time = -1;
333 static int hf_dcerpc_response_in = -1;
334 static int hf_dcerpc_ver = -1;
335 static int hf_dcerpc_ver_minor = -1;
336 static int hf_dcerpc_packet_type = -1;
337 static int hf_dcerpc_cn_flags = -1;
338 static int hf_dcerpc_cn_flags_first_frag = -1;
339 static int hf_dcerpc_cn_flags_last_frag = -1;
340 static int hf_dcerpc_cn_flags_cancel_pending = -1;
341 static int hf_dcerpc_cn_flags_reserved = -1;
342 static int hf_dcerpc_cn_flags_mpx = -1;
343 static int hf_dcerpc_cn_flags_dne = -1;
344 static int hf_dcerpc_cn_flags_maybe = -1;
345 static int hf_dcerpc_cn_flags_object = -1;
346 static int hf_dcerpc_drep = -1;
347 static int hf_dcerpc_drep_byteorder = -1;
348 static int hf_dcerpc_drep_character = -1;
349 static int hf_dcerpc_drep_fp = -1;
350 static int hf_dcerpc_cn_frag_len = -1;
351 static int hf_dcerpc_cn_auth_len = -1;
352 static int hf_dcerpc_cn_call_id = -1;
353 static int hf_dcerpc_cn_max_xmit = -1;
354 static int hf_dcerpc_cn_max_recv = -1;
355 static int hf_dcerpc_cn_assoc_group = -1;
356 static int hf_dcerpc_cn_num_ctx_items = -1;
357 static int hf_dcerpc_cn_ctx_id = -1;
358 static int hf_dcerpc_cn_num_trans_items = -1;
359 static int hf_dcerpc_cn_bind_if_id = -1;
360 static int hf_dcerpc_cn_bind_if_ver = -1;
361 static int hf_dcerpc_cn_bind_if_ver_minor = -1;
362 static int hf_dcerpc_cn_bind_trans_id = -1;
363 static int hf_dcerpc_cn_bind_trans_ver = -1;
364 static int hf_dcerpc_cn_alloc_hint = -1;
365 static int hf_dcerpc_cn_sec_addr_len = -1;
366 static int hf_dcerpc_cn_sec_addr = -1;
367 static int hf_dcerpc_cn_num_results = -1;
368 static int hf_dcerpc_cn_ack_result = -1;
369 static int hf_dcerpc_cn_ack_reason = -1;
370 static int hf_dcerpc_cn_ack_trans_id = -1;
371 static int hf_dcerpc_cn_ack_trans_ver = -1;
372 static int hf_dcerpc_cn_reject_reason = -1;
373 static int hf_dcerpc_cn_num_protocols = -1;
374 static int hf_dcerpc_cn_protocol_ver_major = -1;
375 static int hf_dcerpc_cn_protocol_ver_minor = -1;
376 static int hf_dcerpc_cn_cancel_count = -1;
377 static int hf_dcerpc_cn_status = -1;
378 static int hf_dcerpc_cn_deseg_req = -1;
379 static int hf_dcerpc_auth_type = -1;
380 static int hf_dcerpc_auth_level = -1;
381 static int hf_dcerpc_auth_pad_len = -1;
382 static int hf_dcerpc_auth_rsrvd = -1;
383 static int hf_dcerpc_auth_ctx_id = -1;
384 static int hf_dcerpc_dg_flags1 = -1;
385 static int hf_dcerpc_dg_flags1_rsrvd_01 = -1;
386 static int hf_dcerpc_dg_flags1_last_frag = -1;
387 static int hf_dcerpc_dg_flags1_frag = -1;
388 static int hf_dcerpc_dg_flags1_nofack = -1;
389 static int hf_dcerpc_dg_flags1_maybe = -1;
390 static int hf_dcerpc_dg_flags1_idempotent = -1;
391 static int hf_dcerpc_dg_flags1_broadcast = -1;
392 static int hf_dcerpc_dg_flags1_rsrvd_80 = -1;
393 static int hf_dcerpc_dg_flags2 = -1;
394 static int hf_dcerpc_dg_flags2_rsrvd_01 = -1;
395 static int hf_dcerpc_dg_flags2_cancel_pending = -1;
396 static int hf_dcerpc_dg_flags2_rsrvd_04 = -1;
397 static int hf_dcerpc_dg_flags2_rsrvd_08 = -1;
398 static int hf_dcerpc_dg_flags2_rsrvd_10 = -1;
399 static int hf_dcerpc_dg_flags2_rsrvd_20 = -1;
400 static int hf_dcerpc_dg_flags2_rsrvd_40 = -1;
401 static int hf_dcerpc_dg_flags2_rsrvd_80 = -1;
402 static int hf_dcerpc_dg_serial_hi = -1;
403 static int hf_dcerpc_obj_id = -1;
404 static int hf_dcerpc_dg_if_id = -1;
405 static int hf_dcerpc_dg_act_id = -1;
406 static int hf_dcerpc_dg_serial_lo = -1;
407 static int hf_dcerpc_dg_ahint = -1;
408 static int hf_dcerpc_dg_ihint = -1;
409 static int hf_dcerpc_dg_frag_len = -1;
410 static int hf_dcerpc_dg_frag_num = -1;
411 static int hf_dcerpc_dg_auth_proto = -1;
412 static int hf_dcerpc_opnum = -1;
413 static int hf_dcerpc_dg_seqnum = -1;
414 static int hf_dcerpc_dg_server_boot = -1;
415 static int hf_dcerpc_dg_if_ver = -1;
416 static int hf_dcerpc_krb5_av_prot_level = -1;
417 static int hf_dcerpc_krb5_av_key_vers_num = -1;
418 static int hf_dcerpc_krb5_av_key_auth_verifier = -1;
419 static int hf_dcerpc_dg_cancel_vers = -1;
420 static int hf_dcerpc_dg_cancel_id = -1;
421 static int hf_dcerpc_dg_server_accepting_cancels = -1;
422 static int hf_dcerpc_dg_fack_vers = -1;
423 static int hf_dcerpc_dg_fack_window_size = -1;
424 static int hf_dcerpc_dg_fack_max_tsdu = -1;
425 static int hf_dcerpc_dg_fack_max_frag_size = -1;
426 static int hf_dcerpc_dg_fack_serial_num = -1;
427 static int hf_dcerpc_dg_fack_selack_len = -1;
428 static int hf_dcerpc_dg_fack_selack = -1;
429 static int hf_dcerpc_dg_status = -1;
430 static int hf_dcerpc_array_max_count = -1;
431 static int hf_dcerpc_array_offset = -1;
432 static int hf_dcerpc_array_actual_count = -1;
433 static int hf_dcerpc_array_buffer = -1;
434 static int hf_dcerpc_op = -1;
435 static int hf_dcerpc_referent_id = -1;
436 static int hf_dcerpc_fragments = -1;
437 static int hf_dcerpc_fragment = -1;
438 static int hf_dcerpc_fragment_overlap = -1;
439 static int hf_dcerpc_fragment_overlap_conflict = -1;
440 static int hf_dcerpc_fragment_multiple_tails = -1;
441 static int hf_dcerpc_fragment_too_long_fragment = -1;
442 static int hf_dcerpc_fragment_error = -1;
443 static int hf_dcerpc_reassembled_in = -1;
444 static int hf_dcerpc_unknown_if_id = -1;
446 static gint ett_dcerpc = -1;
447 static gint ett_dcerpc_cn_flags = -1;
448 static gint ett_dcerpc_cn_ctx = -1;
449 static gint ett_dcerpc_cn_iface = -1;
450 static gint ett_dcerpc_drep = -1;
451 static gint ett_dcerpc_dg_flags1 = -1;
452 static gint ett_dcerpc_dg_flags2 = -1;
453 static gint ett_dcerpc_pointer_data = -1;
454 static gint ett_dcerpc_string = -1;
455 static gint ett_dcerpc_fragments = -1;
456 static gint ett_dcerpc_fragment = -1;
457 static gint ett_dcerpc_krb5_auth_verf = -1;
459 static const fragment_items dcerpc_frag_items = {
460 &ett_dcerpc_fragments,
461 &ett_dcerpc_fragment,
463 &hf_dcerpc_fragments,
465 &hf_dcerpc_fragment_overlap,
466 &hf_dcerpc_fragment_overlap_conflict,
467 &hf_dcerpc_fragment_multiple_tails,
468 &hf_dcerpc_fragment_too_long_fragment,
469 &hf_dcerpc_fragment_error,
475 /* list of hooks to be called when init_protocols is done */
476 GHookList dcerpc_hooks_init_protos;
479 int ResolveWin32UUID(e_uuid_t if_id, char *UUID_NAME, int UUID_NAME_MAX_LEN)
481 char REG_UUID_NAME[MAX_PATH];
483 DWORD UUID_MAX_SIZE = MAX_PATH;
484 char REG_UUID_STR[MAX_PATH];
486 if(UUID_NAME_MAX_LEN < 2)
488 REG_UUID_NAME[0] = '\0';
489 g_snprintf(REG_UUID_STR, MAX_PATH, "SOFTWARE\\Classes\\Interface\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
490 if_id.Data1, if_id.Data2, if_id.Data3,
491 if_id.Data4[0], if_id.Data4[1],
492 if_id.Data4[2], if_id.Data4[3],
493 if_id.Data4[4], if_id.Data4[5],
494 if_id.Data4[6], if_id.Data4[7]);
495 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCSTR)REG_UUID_STR, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
497 if (RegQueryValueEx(hKey, NULL, NULL, NULL, (LPBYTE)REG_UUID_NAME, &UUID_MAX_SIZE) == ERROR_SUCCESS && UUID_MAX_SIZE <= MAX_PATH)
499 g_snprintf(UUID_NAME, UUID_NAME_MAX_LEN, "%s", REG_UUID_NAME);
501 return strlen(REG_UUID_NAME);
505 return 0; /* we didn't find anything anyhow. Please don't use the string! */
513 static dcerpc_info di[20];
514 static int di_counter=0;
520 return &di[di_counter];
523 /* try to desegment big DCE/RPC packets over TCP? */
524 static gboolean dcerpc_cn_desegment = TRUE;
526 /* reassemble DCE/RPC fragments */
527 /* reassembly of cl dcerpc fragments will not work for the case where ONE frame
528 might contain multiple dcerpc fragments for different PDUs.
529 this case would be so unusual/weird so if you got captures like that:
532 reassembly of co dcerpc fragments will not work for the case where TCP/SMB frames
533 are coming in out of sequence, but that will hurt in a lot of other places as well.
535 static gboolean dcerpc_reassemble = FALSE;
536 static GHashTable *dcerpc_co_fragment_table = NULL;
537 static GHashTable *dcerpc_co_reassemble_table = NULL;
538 static GHashTable *dcerpc_cl_reassemble_table = NULL;
541 dcerpc_reassemble_init(void)
543 fragment_table_init(&dcerpc_co_fragment_table);
544 reassembled_table_init(&dcerpc_co_reassemble_table);
545 dcerpc_fragment_table_init(&dcerpc_cl_reassemble_table);
549 * Authentication subdissectors. Used to dissect authentication blobs in
550 * DCERPC binds, requests and responses.
553 typedef struct _dcerpc_auth_subdissector {
556 dcerpc_auth_subdissector_fns auth_fns;
557 } dcerpc_auth_subdissector;
559 static GSList *dcerpc_auth_subdissector_list;
561 static dcerpc_auth_subdissector_fns *get_auth_subdissector_fns(
562 guint8 auth_level, guint8 auth_type)
567 for (i = 0; (data = g_slist_nth_data(dcerpc_auth_subdissector_list, i)); i++) {
568 dcerpc_auth_subdissector *asd = (dcerpc_auth_subdissector *)data;
570 if (asd->auth_level == auth_level &&
571 asd->auth_type == auth_type)
572 return &asd->auth_fns;
578 void register_dcerpc_auth_subdissector(guint8 auth_level, guint8 auth_type,
579 dcerpc_auth_subdissector_fns *fns)
581 dcerpc_auth_subdissector *d;
583 if (get_auth_subdissector_fns(auth_level, auth_type))
586 d = (dcerpc_auth_subdissector *)g_malloc(sizeof(dcerpc_auth_subdissector));
588 d->auth_level = auth_level;
589 d->auth_type = auth_type;
590 memcpy(&d->auth_fns, fns, sizeof(dcerpc_auth_subdissector_fns));
592 dcerpc_auth_subdissector_list = g_slist_append(dcerpc_auth_subdissector_list, d);
595 /* Hand off verifier data to a registered dissector */
597 static void dissect_auth_verf(tvbuff_t *auth_tvb, packet_info *pinfo,
599 dcerpc_auth_subdissector_fns *auth_fns,
600 e_dce_cn_common_hdr_t *hdr,
601 dcerpc_auth_info *auth_info)
603 dcerpc_dissect_fnct_t *volatile fn = NULL;
605 switch (hdr->ptype) {
608 fn = auth_fns->bind_fn;
612 fn = auth_fns->bind_ack_fn;
615 fn = auth_fns->auth3_fn;
618 fn = auth_fns->req_verf_fn;
621 fn = auth_fns->resp_verf_fn;
624 /* Don't know how to handle authentication data in this
628 g_warning("attempt to dissect %s pdu authentication data",
629 val_to_str(hdr->ptype, pckt_vals, "Unknown (%u)"));
634 fn(auth_tvb, 0, pinfo, tree, hdr->drep);
636 tvb_ensure_bytes_exist(auth_tvb, 0, hdr->auth_len);
637 proto_tree_add_text(tree, auth_tvb, 0, hdr->auth_len,
639 val_to_str(auth_info->auth_type,
645 /* Hand off payload data to a registered dissector */
647 static tvbuff_t *decode_encrypted_data(tvbuff_t *data_tvb,
650 dcerpc_auth_subdissector_fns *auth_fns,
652 dcerpc_auth_info *auth_info)
654 dcerpc_decode_data_fnct_t *fn;
657 fn = auth_fns->req_data_fn;
659 fn = auth_fns->resp_data_fn;
662 return fn(data_tvb, auth_tvb, 0, pinfo, auth_info);
671 /* the registered subdissectors */
672 GHashTable *dcerpc_uuids=NULL;
675 dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2)
677 const dcerpc_uuid_key *key1 = (const dcerpc_uuid_key *)k1;
678 const dcerpc_uuid_key *key2 = (const dcerpc_uuid_key *)k2;
679 return ((memcmp (&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
680 && (key1->ver == key2->ver));
684 dcerpc_uuid_hash (gconstpointer k)
686 const dcerpc_uuid_key *key = (const dcerpc_uuid_key *)k;
687 /* This isn't perfect, but the Data1 part of these is almost always
689 return key->uuid.Data1;
693 dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver,
694 dcerpc_sub_dissector *procs, int opnum_hf)
696 dcerpc_uuid_key *key = g_malloc (sizeof (*key));
697 dcerpc_uuid_value *value = g_malloc (sizeof (*value));
698 header_field_info *hf_info;
703 value->proto = find_protocol_by_id(proto);
704 value->proto_id = proto;
706 value->name = proto_get_protocol_short_name (value->proto);
707 value->procs = procs;
708 value->opnum_hf = opnum_hf;
710 g_hash_table_insert (dcerpc_uuids, key, value);
712 hf_info = proto_registrar_get_nth(opnum_hf);
713 hf_info->strings = value_string_from_subdissectors(procs);
717 /* try to get registered name for this uuid */
718 const gchar *dcerpc_get_uuid_name(e_uuid_t *uuid, guint16 ver)
721 dcerpc_uuid_value *sub_proto;
724 /* try to get registered uuid "name" of if_id */
728 if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) != NULL
729 && proto_is_protocol_enabled(sub_proto->proto)) {
731 return sub_proto->name;
738 /* Function to find the name of a registered protocol
739 * or NULL if the protocol/version is not known to ethereal.
742 dcerpc_get_proto_name(e_uuid_t *uuid, guint16 ver)
745 dcerpc_uuid_value *sub_proto;
749 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
752 return sub_proto->name;
755 /* Function to find the opnum hf-field of a registered protocol
756 * or -1 if the protocol/version is not known to ethereal.
759 dcerpc_get_proto_hf_opnum(e_uuid_t *uuid, guint16 ver)
762 dcerpc_uuid_value *sub_proto;
766 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
769 return sub_proto->opnum_hf;
772 /* Create a value_string consisting of DCERPC opnum and name from a
773 subdissector array. */
775 value_string *value_string_from_subdissectors(dcerpc_sub_dissector *sd)
777 value_string *vs = NULL;
781 for (i = 0; sd[i].name; i++) {
783 vs[i].value = sd[i].num;
784 vs[i].strptr = sd[i].name;
790 vs = g_malloc((num_sd + 1) * sizeof(value_string));
794 vs[num_sd].value = 0;
795 vs[num_sd].strptr = NULL;
800 /* Function to find the subdissector table of a registered protocol
801 * or NULL if the protocol/version is not known to ethereal.
803 dcerpc_sub_dissector *
804 dcerpc_get_proto_sub_dissector(e_uuid_t *uuid, guint16 ver)
807 dcerpc_uuid_value *sub_proto;
811 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
814 return sub_proto->procs;
819 * To keep track of ctx_id mappings.
821 * Everytime we see a bind call we update this table.
822 * Note that we always specify a SMB FID. For non-SMB transports this
825 static GHashTable *dcerpc_binds=NULL;
827 typedef struct _dcerpc_bind_key {
828 conversation_t *conv;
833 typedef struct _dcerpc_bind_value {
839 dcerpc_bind_equal (gconstpointer k1, gconstpointer k2)
841 const dcerpc_bind_key *key1 = (const dcerpc_bind_key *)k1;
842 const dcerpc_bind_key *key2 = (const dcerpc_bind_key *)k2;
843 return (key1->conv == key2->conv
844 && key1->ctx_id == key2->ctx_id
845 && key1->smb_fid == key2->smb_fid);
849 dcerpc_bind_hash (gconstpointer k)
851 const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
854 hash=GPOINTER_TO_UINT(key->conv) + key->ctx_id + key->smb_fid;
860 * To keep track of callid mappings. Should really use some generic
861 * conversation support instead.
863 static GHashTable *dcerpc_cn_calls=NULL;
864 static GHashTable *dcerpc_dg_calls=NULL;
866 typedef struct _dcerpc_cn_call_key {
867 conversation_t *conv;
870 } dcerpc_cn_call_key;
872 typedef struct _dcerpc_dg_call_key {
873 conversation_t *conv;
876 } dcerpc_dg_call_key;
880 dcerpc_cn_call_equal (gconstpointer k1, gconstpointer k2)
882 const dcerpc_cn_call_key *key1 = (const dcerpc_cn_call_key *)k1;
883 const dcerpc_cn_call_key *key2 = (const dcerpc_cn_call_key *)k2;
884 return (key1->conv == key2->conv
885 && key1->call_id == key2->call_id
886 && key1->smb_fid == key2->smb_fid);
890 dcerpc_dg_call_equal (gconstpointer k1, gconstpointer k2)
892 const dcerpc_dg_call_key *key1 = (const dcerpc_dg_call_key *)k1;
893 const dcerpc_dg_call_key *key2 = (const dcerpc_dg_call_key *)k2;
894 return (key1->conv == key2->conv
895 && key1->seqnum == key2->seqnum
896 && (memcmp (&key1->act_id, &key2->act_id, sizeof (e_uuid_t)) == 0));
900 dcerpc_cn_call_hash (gconstpointer k)
902 const dcerpc_cn_call_key *key = (const dcerpc_cn_call_key *)k;
903 return GPOINTER_TO_UINT(key->conv) + key->call_id + key->smb_fid;
907 dcerpc_dg_call_hash (gconstpointer k)
909 const dcerpc_dg_call_key *key = (const dcerpc_dg_call_key *)k;
910 return (GPOINTER_TO_UINT(key->conv) + key->seqnum + key->act_id.Data1
911 + (key->act_id.Data2 << 16) + key->act_id.Data3
912 + (key->act_id.Data4[0] << 24) + (key->act_id.Data4[1] << 16)
913 + (key->act_id.Data4[2] << 8) + (key->act_id.Data4[3] << 0)
914 + (key->act_id.Data4[4] << 24) + (key->act_id.Data4[5] << 16)
915 + (key->act_id.Data4[6] << 8) + (key->act_id.Data4[7] << 0));
918 /* to keep track of matched calls/responses
919 this one uses the same value struct as calls, but the key is the frame id
920 and call id; there can be more than one call in a frame.
922 XXX - why not just use the same keys as are used for calls?
925 static GHashTable *dcerpc_matched=NULL;
927 typedef struct _dcerpc_matched_key {
930 } dcerpc_matched_key;
933 dcerpc_matched_equal (gconstpointer k1, gconstpointer k2)
935 const dcerpc_matched_key *key1 = (const dcerpc_matched_key *)k1;
936 const dcerpc_matched_key *key2 = (const dcerpc_matched_key *)k2;
937 return (key1->frame == key2->frame
938 && key1->call_id == key2->call_id);
942 dcerpc_matched_hash (gconstpointer k)
944 const dcerpc_matched_key *key = (const dcerpc_matched_key *)k;
951 * Utility functions. Modeled after packet-rpc.c
955 dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
956 proto_tree *tree, guint8 *drep,
957 int hfindex, guint8 *pdata)
961 data = tvb_get_guint8 (tvb, offset);
963 proto_tree_add_item (tree, hfindex, tvb, offset, 1, (drep[0] & 0x10));
971 dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
972 proto_tree *tree, guint8 *drep,
973 int hfindex, guint16 *pdata)
977 data = ((drep[0] & 0x10)
978 ? tvb_get_letohs (tvb, offset)
979 : tvb_get_ntohs (tvb, offset));
982 proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10));
990 dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
991 proto_tree *tree, guint8 *drep,
992 int hfindex, guint32 *pdata)
996 data = ((drep[0] & 0x10)
997 ? tvb_get_letohl (tvb, offset)
998 : tvb_get_ntohl (tvb, offset));
1001 proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10));
1008 /* handles 32 bit unix time_t */
1010 dissect_dcerpc_time_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1011 proto_tree *tree, guint8 *drep,
1012 int hfindex, guint32 *pdata)
1017 data = ((drep[0] & 0x10)
1018 ? tvb_get_letohl (tvb, offset)
1019 : tvb_get_ntohl (tvb, offset));
1024 if(data==0xffffffff){
1025 /* special case, no time specified */
1026 proto_tree_add_time_format(tree, hfindex, tvb, offset, 4, &tv, "%s: No time specified", proto_registrar_get_nth(hfindex)->name);
1028 proto_tree_add_time (tree, hfindex, tvb, offset, 4, &tv);
1038 dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1039 proto_tree *tree, guint8 *drep,
1040 int hfindex, guint64 *pdata)
1044 data = ((drep[0] & 0x10)
1045 ? tvb_get_letoh64 (tvb, offset)
1046 : tvb_get_ntoh64 (tvb, offset));
1049 proto_tree_add_item(tree, hfindex, tvb, offset, 8, (drep[0] & 0x10));
1058 dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1059 proto_tree *tree, guint8 *drep,
1060 int hfindex, gfloat *pdata)
1066 case(DCE_RPC_DREP_FP_IEEE):
1067 data = ((drep[0] & 0x10)
1068 ? tvb_get_letohieee_float(tvb, offset)
1069 : tvb_get_ntohieee_float(tvb, offset));
1071 proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
1074 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
1075 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1076 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
1078 /* ToBeDone: non IEEE floating formats */
1079 /* Set data to a negative infinity value */
1082 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep[1]);
1092 dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1093 proto_tree *tree, guint8 *drep,
1094 int hfindex, gdouble *pdata)
1100 case(DCE_RPC_DREP_FP_IEEE):
1101 data = ((drep[0] & 0x10)
1102 ? tvb_get_letohieee_double(tvb, offset)
1103 : tvb_get_ntohieee_double(tvb, offset));
1105 proto_tree_add_double(tree, hfindex, tvb, offset, 8, data);
1108 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
1109 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1110 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
1112 /* ToBeDone: non IEEE double formats */
1113 /* Set data to a negative infinity value */
1114 data = -G_MAXDOUBLE;
1116 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep[1]);
1126 dissect_dcerpc_uuid_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1127 proto_tree *tree, char *drep,
1128 int hfindex, e_uuid_t *pdata)
1131 header_field_info* hfi;
1137 dcerpc_tvb_get_uuid (tvb, offset, drep, &uuid);
1139 /* get name of protocol field to prepend it later */
1140 hfi = proto_registrar_get_nth(hfindex);
1143 /* XXX - get the name won't work correct, as we don't know the version of this uuid (if it has one) */
1144 /* look for a registered uuid name */
1145 uuid_name = dcerpc_get_uuid_name(&uuid, 0);
1148 /* we know the name of this uuid */
1149 proto_tree_add_string_format (tree, hfindex, tvb, offset, 16, "",
1150 "%s: %s (%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x)",
1151 hfi->name, uuid_name,
1152 uuid.Data1, uuid.Data2, uuid.Data3,
1153 uuid.Data4[0], uuid.Data4[1],
1154 uuid.Data4[2], uuid.Data4[3],
1155 uuid.Data4[4], uuid.Data4[5],
1156 uuid.Data4[6], uuid.Data4[7]);
1159 /* GUID have changed from FT_STRING to FT_GUID
1160 but we havent changed all dissectors yet.
1162 if(hfi->type==FT_GUID){
1163 proto_tree_add_item(tree, hfindex, tvb, offset, 16, (drep[0] & 0x10));
1165 /* we don't know the name of this uuid */
1166 proto_tree_add_string_format (tree, hfindex, tvb, offset, 16, "",
1167 "%s: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1169 uuid.Data1, uuid.Data2, uuid.Data3,
1170 uuid.Data4[0], uuid.Data4[1],
1171 uuid.Data4[2], uuid.Data4[3],
1172 uuid.Data4[4], uuid.Data4[5],
1173 uuid.Data4[6], uuid.Data4[7]);
1187 * a couple simpler things
1190 dcerpc_tvb_get_ntohs (tvbuff_t *tvb, gint offset, guint8 *drep)
1192 if (drep[0] & 0x10) {
1193 return tvb_get_letohs (tvb, offset);
1195 return tvb_get_ntohs (tvb, offset);
1200 dcerpc_tvb_get_ntohl (tvbuff_t *tvb, gint offset, guint8 *drep)
1202 if (drep[0] & 0x10) {
1203 return tvb_get_letohl (tvb, offset);
1205 return tvb_get_ntohl (tvb, offset);
1210 dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, guint8 *drep, e_uuid_t *uuid)
1213 uuid->Data1 = dcerpc_tvb_get_ntohl (tvb, offset, drep);
1214 uuid->Data2 = dcerpc_tvb_get_ntohs (tvb, offset+4, drep);
1215 uuid->Data3 = dcerpc_tvb_get_ntohs (tvb, offset+6, drep);
1217 for (i=0; i<sizeof (uuid->Data4); i++) {
1218 uuid->Data4[i] = tvb_get_guint8 (tvb, offset+8+i);
1225 /* function to dissect a unidimensional conformant array */
1227 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1228 proto_tree *tree, guint8 *drep,
1229 dcerpc_dissect_fnct_t *fnct)
1235 di=pinfo->private_data;
1236 if(di->conformant_run){
1237 /* conformant run, just dissect the max_count header */
1239 di->conformant_run=0;
1240 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1241 hf_dcerpc_array_max_count, &di->array_max_count);
1242 di->array_max_count_offset=offset-4;
1243 di->conformant_run=1;
1244 di->conformant_eaten=offset-old_offset;
1246 /* we don't remember where in the bytestream this field was */
1247 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1249 /* real run, dissect the elements */
1250 for(i=0;i<di->array_max_count;i++){
1251 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1257 /* function to dissect a unidimensional conformant and varying array */
1259 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1260 proto_tree *tree, guint8 *drep,
1261 dcerpc_dissect_fnct_t *fnct)
1267 di=pinfo->private_data;
1268 if(di->conformant_run){
1269 /* conformant run, just dissect the max_count header */
1271 di->conformant_run=0;
1272 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1273 hf_dcerpc_array_max_count, &di->array_max_count);
1274 di->array_max_count_offset=offset-4;
1275 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1276 hf_dcerpc_array_offset, &di->array_offset);
1277 di->array_offset_offset=offset-4;
1278 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1279 hf_dcerpc_array_actual_count, &di->array_actual_count);
1280 di->array_actual_count_offset=offset-4;
1281 di->conformant_run=1;
1282 di->conformant_eaten=offset-old_offset;
1284 /* we dont dont remember where in the bytestream these fields were */
1285 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1286 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
1287 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
1289 /* real run, dissect the elements */
1290 for(i=0;i<di->array_actual_count;i++){
1291 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1297 /* function to dissect a unidimensional varying array */
1299 dissect_ndr_uvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1300 proto_tree *tree, guint8 *drep,
1301 dcerpc_dissect_fnct_t *fnct)
1307 di=pinfo->private_data;
1308 if(di->conformant_run){
1309 /* conformant run, just dissect the max_count header */
1311 di->conformant_run=0;
1312 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1313 hf_dcerpc_array_offset, &di->array_offset);
1314 di->array_offset_offset=offset-4;
1315 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1316 hf_dcerpc_array_actual_count, &di->array_actual_count);
1317 di->array_actual_count_offset=offset-4;
1318 di->conformant_run=1;
1319 di->conformant_eaten=offset-old_offset;
1321 /* we dont dont remember where in the bytestream these fields were */
1322 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
1323 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
1325 /* real run, dissect the elements */
1326 for(i=0;i<di->array_actual_count;i++){
1327 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1334 /* Dissect an string of bytes. This corresponds to
1335 IDL of the form '[string] byte *foo'.
1337 It can also be used for a conformant varying array of bytes if
1338 the contents of the array should be shown as a big blob, rather
1339 than showing each byte as an individual element.
1341 XXX - which of those is really the IDL type for, for example,
1342 the encrypted data in some MAPI packets? (Microsoft haven't
1345 XXX - does this need to do all the conformant array stuff that
1346 "dissect_ndr_ucvarray()" does? These are presumably for strings
1347 that are conformant and varying - they're stored like conformant
1348 varying arrays of bytes. */
1350 dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo,
1351 proto_tree *tree, guint8 *drep)
1356 di=pinfo->private_data;
1357 if(di->conformant_run){
1358 /* just a run to handle conformant arrays, no scalars to dissect */
1362 /* NDR array header */
1364 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1365 hf_dcerpc_array_max_count, NULL);
1367 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1368 hf_dcerpc_array_offset, NULL);
1370 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1371 hf_dcerpc_array_actual_count, &len);
1374 tvb_ensure_bytes_exist(tvb, offset, len);
1375 proto_tree_add_item(tree, hf_dcerpc_array_buffer,
1376 tvb, offset, len, drep[0] & 0x10);
1384 /* For dissecting arrays that are to be interpreted as strings. */
1386 /* Dissect an NDR conformant varying string of elements.
1387 The length of each element is given by the 'size_is' parameter;
1388 the elements are assumed to be characters or wide characters.
1390 XXX - does this need to do all the conformant array stuff that
1391 "dissect_ndr_ucvarray()" does? */
1393 dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1394 proto_tree *tree, guint8 *drep, int size_is,
1395 int hfindex, gboolean add_subtree, char **data)
1398 proto_item *string_item;
1399 proto_tree *string_tree;
1400 guint32 len, buffer_len;
1402 header_field_info *hfinfo;
1404 di=pinfo->private_data;
1405 if(di->conformant_run){
1406 /* just a run to handle conformant arrays, no scalars to dissect */
1411 string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1412 proto_registrar_get_name(hfindex));
1413 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1419 /* NDR array header */
1421 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1422 hf_dcerpc_array_max_count, NULL);
1424 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1425 hf_dcerpc_array_offset, NULL);
1427 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1428 hf_dcerpc_array_actual_count, &len);
1430 buffer_len = size_is * len;
1433 if (offset % size_is)
1434 offset += size_is - (offset % size_is);
1436 if (size_is == sizeof(guint16)) {
1437 /* XXX - use drep to determine the byte order? */
1438 s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
1440 * XXX - we don't support a string type with Unicode
1441 * characters, so if this is a string item, we make
1442 * its value be the "fake Unicode" string.
1444 if (tree && buffer_len) {
1445 hfinfo = proto_registrar_get_nth(hfindex);
1446 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1447 if (hfinfo->type == FT_STRING) {
1448 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1451 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1452 buffer_len, drep[0] & 0x10);
1457 * "tvb_get_string()" throws an exception if the entire string
1458 * isn't in the tvbuff. If the length is bogus, this should
1459 * keep us from trying to allocate an immensely large buffer.
1460 * (It won't help if the length is *valid* but immensely large,
1461 * but that's another matter; in any case, that would happen only
1462 * if we had an immensely large tvbuff....)
1464 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1465 s = tvb_get_string(tvb, offset, buffer_len);
1466 if (tree && buffer_len)
1467 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1468 buffer_len, drep[0] & 0x10);
1471 if (string_item != NULL)
1472 proto_item_append_text(string_item, ": %s", s);
1479 offset += buffer_len;
1481 proto_item_set_end(string_item, tvb, offset);
1486 /* Dissect an conformant varying string of chars.
1487 This corresponds to IDL of the form '[string] char *foo'.
1489 XXX - at least according to the DCE RPC 1.1 spec, a string has
1490 a null terminator, which isn't necessary as a terminator for
1491 the transfer language (as there's a length), but is presumably
1492 there for the benefit of null-terminated-string languages
1493 such as C. Is this ever used for purely counted strings?
1494 (Not that it matters if it is.) */
1496 dissect_ndr_char_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1497 proto_tree *tree, guint8 *drep)
1500 di=pinfo->private_data;
1502 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1503 sizeof(guint8), di->hf_index,
1507 /* Dissect a conformant varying string of wchars (wide characters).
1508 This corresponds to IDL of the form '[string] wchar *foo'
1510 XXX - at least according to the DCE RPC 1.1 spec, a string has
1511 a null terminator, which isn't necessary as a terminator for
1512 the transfer language (as there's a length), but is presumably
1513 there for the benefit of null-terminated-string languages
1514 such as C. Is this ever used for purely counted strings?
1515 (Not that it matters if it is.) */
1517 dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1518 proto_tree *tree, guint8 *drep)
1521 di=pinfo->private_data;
1523 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1524 sizeof(guint16), di->hf_index,
1528 /* Dissect an NDR varying string of elements.
1529 The length of each element is given by the 'size_is' parameter;
1530 the elements are assumed to be characters or wide characters.
1533 dissect_ndr_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1534 proto_tree *tree, guint8 *drep, int size_is,
1535 int hfindex, gboolean add_subtree, char **data)
1538 proto_item *string_item;
1539 proto_tree *string_tree;
1540 guint32 len, buffer_len;
1542 header_field_info *hfinfo;
1544 di=pinfo->private_data;
1545 if(di->conformant_run){
1546 /* just a run to handle conformant arrays, no scalars to dissect */
1551 string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1552 proto_registrar_get_name(hfindex));
1553 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1559 /* NDR array header */
1560 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1561 hf_dcerpc_array_offset, NULL);
1563 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1564 hf_dcerpc_array_actual_count, &len);
1566 buffer_len = size_is * len;
1569 if (offset % size_is)
1570 offset += size_is - (offset % size_is);
1572 if (size_is == sizeof(guint16)) {
1573 /* XXX - use drep to determine the byte order? */
1574 s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
1576 * XXX - we don't support a string type with Unicode
1577 * characters, so if this is a string item, we make
1578 * its value be the "fake Unicode" string.
1580 if (tree && buffer_len) {
1581 hfinfo = proto_registrar_get_nth(hfindex);
1582 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1583 if (hfinfo->type == FT_STRING) {
1584 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1587 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1588 buffer_len, drep[0] & 0x10);
1593 * "tvb_get_string()" throws an exception if the entire string
1594 * isn't in the tvbuff. If the length is bogus, this should
1595 * keep us from trying to allocate an immensely large buffer.
1596 * (It won't help if the length is *valid* but immensely large,
1597 * but that's another matter; in any case, that would happen only
1598 * if we had an immensely large tvbuff....)
1600 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1601 s = tvb_get_string(tvb, offset, buffer_len);
1602 if (tree && buffer_len)
1603 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1604 buffer_len, drep[0] & 0x10);
1607 if (string_item != NULL)
1608 proto_item_append_text(string_item, ": %s", s);
1615 offset += buffer_len;
1617 proto_item_set_end(string_item, tvb, offset);
1621 /* Dissect an varying string of chars.
1622 This corresponds to IDL of the form '[string] char *foo'.
1624 XXX - at least according to the DCE RPC 1.1 spec, a string has
1625 a null terminator, which isn't necessary as a terminator for
1626 the transfer language (as there's a length), but is presumably
1627 there for the benefit of null-terminated-string languages
1628 such as C. Is this ever used for purely counted strings?
1629 (Not that it matters if it is.) */
1631 dissect_ndr_char_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1632 proto_tree *tree, guint8 *drep)
1635 di=pinfo->private_data;
1637 return dissect_ndr_vstring(tvb, offset, pinfo, tree, drep,
1638 sizeof(guint8), di->hf_index,
1642 /* Dissect a varying string of wchars (wide characters).
1643 This corresponds to IDL of the form '[string] wchar *foo'
1645 XXX - at least according to the DCE RPC 1.1 spec, a string has
1646 a null terminator, which isn't necessary as a terminator for
1647 the transfer language (as there's a length), but is presumably
1648 there for the benefit of null-terminated-string languages
1649 such as C. Is this ever used for purely counted strings?
1650 (Not that it matters if it is.) */
1652 dissect_ndr_wchar_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1653 proto_tree *tree, guint8 *drep)
1656 di=pinfo->private_data;
1658 return dissect_ndr_vstring(tvb, offset, pinfo, tree, drep,
1659 sizeof(guint16), di->hf_index,
1664 /* ndr pointer handling */
1665 /* list of pointers encountered so far */
1666 static GSList *ndr_pointer_list = NULL;
1668 /* position where in the list to insert newly encountered pointers */
1669 static int ndr_pointer_list_pos=0;
1671 /* boolean controlling whether pointers are top-level or embedded */
1672 static gboolean pointers_are_top_level = TRUE;
1674 /* as a kludge, we represent all embedded reference pointers as id==-1
1675 hoping that his will not collide with any non-ref pointers */
1676 typedef struct ndr_pointer_data {
1678 proto_item *item; /* proto_item for pointer */
1679 proto_tree *tree; /* subtree of above item */
1680 dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
1682 dcerpc_callback_fnct_t *callback;
1683 void *callback_args;
1684 } ndr_pointer_data_t;
1687 init_ndr_pointer_list(packet_info *pinfo)
1691 di=pinfo->private_data;
1692 di->conformant_run=0;
1694 while(ndr_pointer_list){
1695 ndr_pointer_data_t *npd;
1697 npd=g_slist_nth_data(ndr_pointer_list, 0);
1698 ndr_pointer_list=g_slist_remove(ndr_pointer_list, npd);
1704 ndr_pointer_list=NULL;
1705 ndr_pointer_list_pos=0;
1706 pointers_are_top_level=TRUE;
1710 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, guint8 *drep)
1712 int found_new_pointer;
1718 di=pinfo->private_data;
1722 found_new_pointer=0;
1723 len=g_slist_length(ndr_pointer_list);
1724 for(i=next_pointer;i<len;i++){
1725 ndr_pointer_data_t *tnpd;
1726 tnpd=g_slist_nth_data(ndr_pointer_list, i);
1728 dcerpc_dissect_fnct_t *fnct;
1731 found_new_pointer=1;
1734 ndr_pointer_list_pos=i+1;
1735 di->hf_index=tnpd->hf_index;
1736 /* first a run to handle any conformant
1738 di->conformant_run=1;
1739 di->conformant_eaten=0;
1740 old_offset = offset;
1741 offset = (*(fnct))(tvb, offset, pinfo, NULL, drep);
1743 DISSECTOR_ASSERT((offset-old_offset)==di->conformant_eaten);
1744 /* This is to check for any bugs in the dissectors.
1746 * Basically, the NDR representation will store all
1747 * arrays in two blocks, one block with the dimension
1748 * discreption, like size, number of elements and such,
1749 * and another block that contains the actual data stored
1751 * If the array is embedded directly inside another,
1752 * encapsulating aggregate type, like a union or struct,
1753 * then these two blocks will be stored at different places
1754 * in the bytestream, with other data between the blocks.
1756 * For this reason, all pointers to types (both aggregate
1757 * and scalar, for simplicity no distinction is made)
1758 * will have its dissector called twice.
1759 * The dissector will first be called with conformant_run==1
1760 * in which mode the dissector MUST NOT consume any data from
1761 * the tvbuff (i.e. may not dissect anything) except the
1762 * initial control block for arrays.
1763 * The second time the dissector is called, with
1764 * conformant_run==0, all other data for the type will be
1767 * All dissect_ndr_<type> dissectors are already prepared
1768 * for this and knows when it should eat data from the tvb
1769 * and when not to, so implementors of dissectors will
1770 * normally not need to worry about this or even know about
1771 * it. However, if a dissector for an aggregate type calls
1772 * a subdissector from outside packet-dcerpc.c, such as
1773 * the dissector in packet-smb.c for NT Security Descriptors
1774 * as an example, then it is VERY important to encapsulate
1775 * this call to an external subdissector with the appropriate
1776 * test for conformant_run, i.e. it will need something like
1780 * di=pinfo->private_data;
1781 * if(di->conformant_run){
1785 * to make sure it makes the right thing.
1786 * This assert will signal when someone has forgotten to
1787 * make the dissector aware of this requirement.
1790 /* now we dissect the actual pointer */
1791 di->conformant_run=0;
1792 old_offset = offset;
1793 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, drep);
1795 tnpd->callback(pinfo, tnpd->tree, tnpd->item, tvb, old_offset, offset, tnpd->callback_args);
1799 } while(found_new_pointer);
1806 add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
1807 dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index,
1808 dcerpc_callback_fnct_t *callback, void *callback_args)
1810 ndr_pointer_data_t *npd;
1812 /* check if this pointer is valid */
1815 dcerpc_call_value *value;
1817 di=pinfo->private_data;
1818 value=di->call_data;
1820 if(di->ptype == PDU_REQ){
1821 if(!(pinfo->fd->flags.visited)){
1822 if(id>value->max_ptr){
1827 /* if we havent seen the request bail out since we cant
1828 know whether this is the first non-NULL instance
1830 if(value->req_frame==0){
1831 /* XXX THROW EXCEPTION */
1834 /* We saw this one in the request frame, nothing to
1836 if(id<=value->max_ptr){
1842 npd=g_malloc(sizeof(ndr_pointer_data_t));
1847 npd->hf_index=hf_index;
1848 npd->callback=callback;
1849 npd->callback_args=callback_args;
1850 ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
1851 ndr_pointer_list_pos);
1852 ndr_pointer_list_pos++;
1857 find_pointer_index(guint32 id)
1859 ndr_pointer_data_t *npd;
1862 len=g_slist_length(ndr_pointer_list);
1864 npd=g_slist_nth_data(ndr_pointer_list, i);
1875 /* This function dissects an NDR pointer and stores the callback for later
1876 * deferred dissection.
1878 * fnct is the callback function for when we have reached this object in
1881 * type is what type of pointer.
1883 * this is text is what text we should put in any created tree node.
1885 * hf_index is what hf value we want to pass to the callback function when
1886 * it is called, the callback can later pich this one up from di->hf_index.
1888 * callback is executed after the pointer has been dereferenced.
1890 * callback_args is passed as an argument to the callback function
1892 * See packet-dcerpc-samr.c for examples
1895 dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1896 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
1897 int type, const char *text, int hf_index,
1898 dcerpc_callback_fnct_t *callback, void *callback_args)
1901 proto_tree *tr = NULL;
1902 gint start_offset = offset;
1904 di=pinfo->private_data;
1905 if(di->conformant_run){
1906 /* this call was only for dissecting the header for any
1907 embedded conformant array. we will not parse any
1908 pointers in this mode.
1913 /*TOP LEVEL REFERENCE POINTER*/
1914 if( pointers_are_top_level
1915 &&(type==NDR_POINTER_REF) ){
1918 /* we must find out a nice way to do the length here */
1919 item=proto_tree_add_text(tree, tvb, offset, 0,
1921 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1923 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1924 hf_index, callback, callback_args);
1928 /*TOP LEVEL FULL POINTER*/
1929 if( pointers_are_top_level
1930 && (type==NDR_POINTER_PTR) ){
1935 /* get the referent id */
1936 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1938 tvb_ensure_bytes_exist(tvb, offset-4, 4);
1939 /* we got a NULL pointer */
1941 proto_tree_add_text(tree, tvb, offset-4, 4,
1942 "(NULL pointer) %s",text);
1946 /* see if we have seen this pointer before */
1947 idx=find_pointer_index(id);
1949 /* we have seen this pointer before */
1951 proto_tree_add_text(tree, tvb, offset-4, 4,
1952 "(duplicate PTR) %s",text);
1957 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1959 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1960 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1961 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
1962 callback, callback_args);
1965 /*TOP LEVEL UNIQUE POINTER*/
1966 if( pointers_are_top_level
1967 && (type==NDR_POINTER_UNIQUE) ){
1971 /* get the referent id */
1972 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1974 tvb_ensure_bytes_exist(tvb, offset-4, 4);
1975 /* we got a NULL pointer */
1977 proto_tree_add_text(tree, tvb, offset-4, 4,
1978 "(NULL pointer) %s",text);
1983 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1985 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1986 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1987 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1988 hf_index, callback, callback_args);
1992 /*EMBEDDED REFERENCE POINTER*/
1993 if( (!pointers_are_top_level)
1994 && (type==NDR_POINTER_REF) ){
1998 /* get the referent id */
1999 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
2001 tvb_ensure_bytes_exist(tvb, offset-4, 4);
2003 item=proto_tree_add_text(tree, tvb, offset-4, 4,
2005 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2006 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
2007 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
2008 hf_index, callback, callback_args);
2012 /*EMBEDDED UNIQUE POINTER*/
2013 if( (!pointers_are_top_level)
2014 && (type==NDR_POINTER_UNIQUE) ){
2018 /* get the referent id */
2019 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
2021 tvb_ensure_bytes_exist(tvb, offset-4, 4);
2022 /* we got a NULL pointer */
2024 proto_tree_add_text(tree, tvb, offset-4, 4,
2025 "(NULL pointer) %s", text);
2030 item=proto_tree_add_text(tree, tvb, offset-4, 4,
2032 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2033 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
2034 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
2035 hf_index, callback, callback_args);
2039 /*EMBEDDED FULL POINTER*/
2040 if( (!pointers_are_top_level)
2041 && (type==NDR_POINTER_PTR) ){
2046 /* get the referent id */
2047 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
2049 tvb_ensure_bytes_exist(tvb, offset-4, 4);
2050 /* we got a NULL pointer */
2052 proto_tree_add_text(tree, tvb, offset-4, 4,
2053 "(NULL pointer) %s",text);
2057 /* see if we have seen this pointer before */
2058 idx=find_pointer_index(id);
2060 /* we have seen this pointer before */
2062 proto_tree_add_text(tree, tvb, offset-4, 4,
2063 "(duplicate PTR) %s",text);
2068 item=proto_tree_add_text(tree, tvb, offset-4, 4,
2070 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2071 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
2072 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
2073 callback, callback_args);
2079 /* After each top level pointer we have dissected we have to
2080 dissect all deferrals before we move on to the next top level
2082 if(pointers_are_top_level==TRUE){
2083 pointers_are_top_level=FALSE;
2084 offset = dissect_deferred_pointers(pinfo, tvb, offset, drep);
2085 pointers_are_top_level=TRUE;
2088 /* Set the length for the new subtree */
2090 proto_item_set_len(tr, offset-start_offset);
2096 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2097 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2098 int type, const char *text, int hf_index)
2100 return dissect_ndr_pointer_cb(
2101 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
2105 dissect_ndr_toplevel_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2106 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2107 int type, const char *text, int hf_index)
2111 pointers_are_top_level=TRUE;
2112 ret=dissect_ndr_pointer_cb(
2113 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
2118 dissect_ndr_embedded_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2119 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2120 int type, const char *text, int hf_index)
2124 pointers_are_top_level=FALSE;
2125 ret=dissect_ndr_pointer_cb(
2126 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
2132 show_stub_data (tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
2133 dcerpc_auth_info *auth_info, gboolean is_encrypted)
2135 int length, plain_length, auth_pad_len;
2136 guint auth_pad_offset;
2139 * We don't show stub data unless we have some in the tvbuff;
2140 * however, in the protocol tree, we show, as the number of
2141 * bytes, the reported number of bytes, not the number of bytes
2142 * that happen to be in the tvbuff.
2144 if (tvb_length_remaining (tvb, offset) > 0) {
2145 auth_pad_len = auth_info?auth_info->auth_pad_len:0;
2146 length = tvb_reported_length_remaining (tvb, offset);
2148 /* if auth_pad_len is larger than length then we ignore auth_pad_len totally */
2149 plain_length = length - auth_pad_len;
2150 if (plain_length < 1) {
2151 plain_length = length;
2154 auth_pad_offset = offset + plain_length;
2156 if (auth_info != NULL &&
2157 auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
2159 tvb_ensure_bytes_exist(tvb, offset, length);
2160 proto_tree_add_text(dcerpc_tree, tvb, offset, length,
2161 "Encrypted stub data (%d byte%s)",
2162 length, plurality(length, "", "s"));
2163 /* is the padding is still inside the encrypted blob, don't display it explicit */
2166 tvb_ensure_bytes_exist(tvb, offset, plain_length);
2167 proto_tree_add_text(dcerpc_tree, tvb, offset, plain_length,
2168 "Decrypted stub data (%d byte%s)",
2169 plain_length, plurality(plain_length, "", "s"));
2172 tvb_ensure_bytes_exist(tvb, offset, plain_length);
2173 proto_tree_add_text (dcerpc_tree, tvb, offset, plain_length,
2174 "Stub data (%d byte%s)", plain_length,
2175 plurality(plain_length, "", "s"));
2177 /* If there is auth padding at the end of the stub, display it */
2178 if (auth_pad_len != 0) {
2179 tvb_ensure_bytes_exist(tvb, auth_pad_offset, auth_pad_len);
2180 proto_tree_add_text (dcerpc_tree, tvb, auth_pad_offset,
2182 "Auth Padding (%u byte%s)",
2184 plurality(auth_pad_len, "", "s"));
2190 dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
2191 proto_tree *dcerpc_tree,
2192 tvbuff_t *volatile tvb, tvbuff_t *decrypted_tvb,
2193 guint8 *drep, dcerpc_info *info,
2194 dcerpc_auth_info *auth_info)
2196 volatile gint offset = 0;
2197 dcerpc_uuid_key key;
2198 dcerpc_uuid_value *sub_proto;
2199 proto_tree *volatile sub_tree = NULL;
2200 dcerpc_sub_dissector *proc;
2201 const gchar *name = NULL;
2202 dcerpc_dissect_fnct_t *volatile sub_dissect;
2203 const char *volatile saved_proto;
2204 void *volatile saved_private_data;
2205 guint length, reported_length;
2206 tvbuff_t *volatile stub_tvb;
2207 volatile guint auth_pad_len;
2208 volatile int auth_pad_offset;
2210 char UUID_NAME[MAX_PATH];
2212 proto_item *sub_item;
2214 key.uuid = info->call_data->uuid;
2215 key.ver = info->call_data->ver;
2218 if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == NULL
2219 || !proto_is_protocol_enabled(sub_proto->proto)) {
2221 * We don't have a dissector for this UUID, or the protocol
2222 * for that UUID is disabled.
2225 proto_tree_add_boolean_hidden(dcerpc_tree, hf_dcerpc_unknown_if_id,
2226 tvb, offset, 0, TRUE);
2227 if (check_col (pinfo->cinfo, COL_INFO)) {
2229 if(ResolveWin32UUID(info->call_data->uuid, UUID_NAME, MAX_PATH))
2230 col_append_fstr (pinfo->cinfo, COL_INFO, " [%s] UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x rpcver: %u",
2231 UUID_NAME, info->call_data->uuid.Data1, info->call_data->uuid.Data2, info->call_data->uuid.Data3, info->call_data->uuid.Data4[0],
2232 info->call_data->uuid.Data4[1], info->call_data->uuid.Data4[2], info->call_data->uuid.Data4[3],
2233 info->call_data->uuid.Data4[4], info->call_data->uuid.Data4[5], info->call_data->uuid.Data4[6],
2234 info->call_data->uuid.Data4[7], info->call_data->ver);
2237 col_append_fstr (pinfo->cinfo, COL_INFO, " UNKUUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x rpcver: %u",
2238 info->call_data->uuid.Data1, info->call_data->uuid.Data2, info->call_data->uuid.Data3, info->call_data->uuid.Data4[0],
2239 info->call_data->uuid.Data4[1], info->call_data->uuid.Data4[2], info->call_data->uuid.Data4[3],
2240 info->call_data->uuid.Data4[4], info->call_data->uuid.Data4[5], info->call_data->uuid.Data4[6],
2241 info->call_data->uuid.Data4[7], info->call_data->ver);
2244 if (decrypted_tvb != NULL) {
2245 show_stub_data (decrypted_tvb, 0, dcerpc_tree, auth_info,
2248 show_stub_data (tvb, 0, dcerpc_tree, auth_info, TRUE);
2252 for (proc = sub_proto->procs; proc->name; proc++) {
2253 if (proc->num == info->call_data->opnum) {
2262 if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
2263 col_set_str (pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
2266 if (check_col (pinfo->cinfo, COL_INFO)) {
2267 col_add_fstr (pinfo->cinfo, COL_INFO, "%s %s",
2268 name, (info->ptype == PDU_REQ) ? "request" : "response");
2272 sub_item = proto_tree_add_item (tree, sub_proto->proto_id, tvb, 0,
2276 sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
2277 proto_item_append_text(sub_item, ", %s", name);
2281 * Put the operation number into the tree along with
2282 * the operation's name.
2285 if (sub_proto->opnum_hf != -1)
2286 proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
2287 tvb, 0, 0, info->call_data->opnum,
2288 "Operation: %s (%u)",
2289 name, info->call_data->opnum);
2291 proto_tree_add_uint_format(sub_tree, hf_dcerpc_op, tvb,
2292 0, 0, info->call_data->opnum,
2293 "Operation: %s (%u)",
2294 name, info->call_data->opnum);
2297 sub_dissect = (info->ptype == PDU_REQ) ?
2298 proc->dissect_rqst : proc->dissect_resp;
2300 if (decrypted_tvb != NULL) {
2301 /* Either there was no encryption or we successfully decrypted
2302 the entrypted payload. */
2304 /* We have a subdissector - call it. */
2305 saved_proto = pinfo->current_proto;
2306 saved_private_data = pinfo->private_data;
2307 pinfo->current_proto = sub_proto->name;
2308 pinfo->private_data = (void *)info;
2310 init_ndr_pointer_list(pinfo);
2313 * Remove the authentication padding from the stub data.
2315 if (auth_info != NULL && auth_info->auth_pad_len != 0) {
2316 length = tvb_length(decrypted_tvb);
2317 reported_length = tvb_reported_length(decrypted_tvb);
2318 if (reported_length >= auth_info->auth_pad_len) {
2320 * OK, the padding length isn't so big that it
2321 * exceeds the stub length. Trim the reported
2322 * length of the tvbuff.
2324 reported_length -= auth_info->auth_pad_len;
2327 * If that exceeds the actual amount of data in
2328 * the tvbuff (which means we have at least one
2329 * byte of authentication padding in the tvbuff),
2330 * trim the actual amount.
2332 if (length > reported_length)
2333 length = reported_length;
2335 stub_tvb = tvb_new_subset(tvb, 0, length, reported_length);
2336 auth_pad_len = auth_info->auth_pad_len;
2337 auth_pad_offset = reported_length;
2340 * The padding length exceeds the stub length.
2341 * Don't bother dissecting the stub, trim the padding
2342 * length to what's in the stub data, and show the
2343 * entire stub as authentication padding.
2346 auth_pad_len = reported_length;
2347 auth_pad_offset = 0;
2351 * No authentication padding.
2353 stub_tvb = decrypted_tvb;
2355 auth_pad_offset = 0;
2358 if (stub_tvb != NULL) {
2360 * Catch all exceptions other than BoundsError, so that even
2361 * if the stub data is bad, we still show the authentication
2364 * If we get BoundsError, it means the frame was cut short
2365 * by a snapshot length, so there's nothing more to
2366 * dissect; just re-throw that exception.
2369 offset = sub_dissect (decrypted_tvb, 0, pinfo, sub_tree,
2372 proto_item_set_len(sub_item, offset);
2375 /* If we have a subdissector and it didn't dissect all
2376 data in the tvb, make a note of it. */
2377 /* XXX - don't do this, as this could be just another RPC Req./Resp. in this PDU */
2378 /*if (tvb_reported_length_remaining(stub_tvb, offset) > 0) {
2379 if (check_col(pinfo->cinfo, COL_INFO))
2380 col_append_fstr(pinfo->cinfo, COL_INFO,
2381 "[Long frame (%d bytes)]",
2382 tvb_reported_length_remaining(stub_tvb, offset));
2384 } CATCH(BoundsError) {
2387 show_exception(decrypted_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
2391 /* If there is auth padding at the end of the stub, display it */
2392 if (auth_pad_len != 0) {
2393 tvb_ensure_bytes_exist(tvb, auth_pad_offset, auth_pad_len);
2394 proto_tree_add_text (sub_tree, decrypted_tvb, auth_pad_offset,
2396 "Auth Padding (%u byte%s)",
2398 plurality(auth_pad_len, "", "s"));
2401 pinfo->current_proto = saved_proto;
2402 pinfo->private_data = saved_private_data;
2404 /* No subdissector - show it as stub data. */
2406 show_stub_data (decrypted_tvb, 0, sub_tree, auth_info, FALSE);
2408 show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
2412 show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
2414 tap_queue_packet(dcerpc_tap, pinfo, info);
2419 dissect_dcerpc_verifier (tvbuff_t *tvb, packet_info *pinfo,
2420 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
2421 dcerpc_auth_info *auth_info)
2425 auth_info->auth_data = NULL;
2427 if (auth_info->auth_size != 0) {
2428 dcerpc_auth_subdissector_fns *auth_fns;
2431 auth_offset = hdr->frag_len - hdr->auth_len;
2433 auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
2436 auth_info->auth_data = auth_tvb;
2438 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
2439 auth_info->auth_type))) {
2441 * Catch all exceptions, so that even if the verifier is bad
2442 * or we don't have all of it, we still show the stub data.
2445 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
2448 show_exception(auth_tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
2451 tvb_ensure_bytes_exist(tvb, 0, hdr->auth_len);
2452 proto_tree_add_text (dcerpc_tree, auth_tvb, 0, hdr->auth_len,
2457 return hdr->auth_len;
2461 dissect_dcerpc_cn_auth (tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
2462 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
2463 gboolean are_credentials, dcerpc_auth_info *auth_info)
2465 volatile int offset;
2468 * Initially set auth_level and auth_type to zero to indicate that we
2469 * haven't yet seen any authentication level information.
2471 auth_info->auth_level = 0;
2472 auth_info->auth_type = 0;
2473 auth_info->auth_size = 0;
2474 auth_info->auth_pad_len = 0;
2477 * The authentication information is at the *end* of the PDU; in
2478 * request and response PDUs, the request and response stub data
2481 * Is there any authentication data (i.e., is the authentication length
2482 * non-zero), and is the authentication length valid (i.e., is it, plus
2483 * 8 bytes for the type/level/pad length/reserved/context id, less than
2484 * or equal to the fragment length minus the starting offset of the
2489 && (hdr->auth_len + 8 <= hdr->frag_len - stub_offset)) {
2492 * Yes, there is authentication data, and the length is valid.
2493 * Do we have all the bytes of stub data?
2494 * (If not, we'd throw an exception dissecting *that*, so don't
2495 * bother trying to dissect the authentication information and
2496 * throwing another exception there.)
2498 offset = hdr->frag_len - (hdr->auth_len + 8);
2499 if (offset == 0 || tvb_offset_exists(tvb, offset - 1)) {
2501 * Either there's no stub data, or the last byte of the stub
2502 * data is present in the captured data, so we shouldn't
2503 * get a BoundsError dissecting the stub data.
2505 * Try dissecting the authentication data.
2506 * Catch all exceptions, so that even if the auth info is bad
2507 * or we don't have all of it, we still show the stuff we
2508 * dissect after this, such as stub data.
2511 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2512 hf_dcerpc_auth_type,
2513 &auth_info->auth_type);
2514 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2515 hf_dcerpc_auth_level,
2516 &auth_info->auth_level);
2518 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2519 hf_dcerpc_auth_pad_len,
2520 &auth_info->auth_pad_len);
2521 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2522 hf_dcerpc_auth_rsrvd, NULL);
2523 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2524 hf_dcerpc_auth_ctx_id, NULL);
2527 * Dissect the authentication data.
2529 if (are_credentials) {
2531 dcerpc_auth_subdissector_fns *auth_fns;
2533 auth_tvb = tvb_new_subset(tvb, offset,
2534 MIN(hdr->auth_len,tvb_length_remaining(tvb, offset)),
2537 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
2538 auth_info->auth_type)))
2539 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
2542 proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len,
2543 "Auth Credentials");
2546 /* Compute the size of the auth block. Note that this should not
2547 include auth padding, since when NTLMSSP encryption is used, the
2548 padding is actually inside the encrypted stub */
2549 auth_info->auth_size = hdr->auth_len + 8;
2551 show_exception(tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
2558 /* We need to hash in the SMB fid number to generate a unique hash table
2559 * key as DCERPC over SMB allows several pipes over the same TCP/IP
2561 * We pass this function the transport type here to make sure we only look
2562 * at this function if it came across an SMB pipe.
2563 * Other transports might need to mix in their own extra multiplexing data
2564 * as well in the future.
2567 guint16 dcerpc_get_transport_salt (packet_info *pinfo)
2569 switch(pinfo->dcetransporttype){
2570 case DCE_CN_TRANSPORT_SMBPIPE:
2571 /* DCERPC over smb */
2572 return pinfo->dcetransportsalt;
2575 /* Some other transport... */
2580 * Connection oriented packet types
2584 dissect_dcerpc_cn_bind (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2585 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2587 conversation_t *conv = NULL;
2588 guint8 num_ctx_items = 0;
2590 gboolean saw_ctx_item = FALSE;
2592 guint8 num_trans_items;
2597 guint16 if_ver, if_ver_minor;
2598 char uuid_str[DCERPC_UUID_STR_LEN];
2600 dcerpc_auth_info auth_info;
2602 char UUID_NAME[MAX_PATH];
2605 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2606 hf_dcerpc_cn_max_xmit, NULL);
2608 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2609 hf_dcerpc_cn_max_recv, NULL);
2611 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2612 hf_dcerpc_cn_assoc_group, NULL);
2614 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2615 hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
2620 for (i = 0; i < num_ctx_items; i++) {
2621 proto_tree *ctx_tree = NULL, *iface_tree = NULL;
2623 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, NULL, hdr->drep,
2624 hf_dcerpc_cn_ctx_id, &ctx_id);
2626 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
2627 /* (if we have multiple contexts, this might cause "decode as"
2628 * to behave unpredictably) */
2629 pinfo->dcectxid = ctx_id;
2632 proto_item *ctx_item;
2634 ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_id,
2636 hdr->drep[0] & 0x10);
2638 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
2641 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, ctx_tree, hdr->drep,
2642 hf_dcerpc_cn_num_trans_items, &num_trans_items);
2647 /* XXX - use "dissect_ndr_uuid_t()"? */
2648 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
2650 proto_item *iface_item;
2652 uuid_str_len = g_snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2653 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2654 if_id.Data1, if_id.Data2, if_id.Data3,
2655 if_id.Data4[0], if_id.Data4[1],
2656 if_id.Data4[2], if_id.Data4[3],
2657 if_id.Data4[4], if_id.Data4[5],
2658 if_id.Data4[6], if_id.Data4[7]);
2660 if (uuid_str_len == -1 || uuid_str_len >= DCERPC_UUID_STR_LEN)
2661 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2663 if(ResolveWin32UUID(if_id, UUID_NAME, MAX_PATH))
2664 iface_item = proto_tree_add_string_format (ctx_tree, hf_dcerpc_cn_bind_if_id, tvb,
2665 offset, 16, uuid_str, "Interface: %s\tUUID: %s", UUID_NAME, uuid_str);
2668 iface_item = proto_tree_add_string_format (ctx_tree, hf_dcerpc_cn_bind_if_id, tvb,
2669 offset, 16, uuid_str, "Interface UUID: %s", uuid_str);
2670 iface_tree = proto_item_add_subtree(iface_item, ett_dcerpc_cn_iface);
2674 if (hdr->drep[0] & 0x10) {
2675 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2676 hf_dcerpc_cn_bind_if_ver, &if_ver);
2677 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2678 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2680 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2681 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2682 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2683 hf_dcerpc_cn_bind_if_ver, &if_ver);
2686 if (!saw_ctx_item) {
2687 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
2688 pinfo->srcport, pinfo->destport, 0);
2690 conv = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
2691 pinfo->srcport, pinfo->destport, 0);
2695 /* if this is the first time we see this packet, we need to
2696 update the dcerpc_binds table so that any later calls can
2697 match to the interface.
2698 XXX We assume that BINDs will NEVER be fragmented.
2700 if(!(pinfo->fd->flags.visited)){
2701 dcerpc_bind_key *key;
2702 dcerpc_bind_value *value;
2704 key = se_alloc (sizeof (dcerpc_bind_key));
2706 key->ctx_id = ctx_id;
2707 key->smb_fid = dcerpc_get_transport_salt(pinfo);
2709 value = se_alloc (sizeof (dcerpc_bind_value));
2710 value->uuid = if_id;
2711 value->ver = if_ver;
2713 /* add this entry to the bind table, first removing any
2714 previous ones that are identical
2716 if(g_hash_table_lookup(dcerpc_binds, key)){
2717 g_hash_table_remove(dcerpc_binds, key);
2719 g_hash_table_insert (dcerpc_binds, key, value);
2722 if (check_col (pinfo->cinfo, COL_INFO)) {
2723 dcerpc_uuid_key key;
2724 dcerpc_uuid_value *value;
2729 if (num_ctx_items > 1)
2730 col_append_fstr(pinfo->cinfo, COL_INFO, ", %u context items, 1st", num_ctx_items);
2732 if ((value = g_hash_table_lookup(dcerpc_uuids, &key)))
2733 col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %s", value->name);
2736 if(ResolveWin32UUID(if_id, UUID_NAME, MAX_PATH))
2737 col_append_fstr(pinfo->cinfo, COL_INFO, " [%s] UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
2738 UUID_NAME, if_id.Data1, if_id.Data2, if_id.Data3,
2739 if_id.Data4[0], if_id.Data4[1],
2740 if_id.Data4[2], if_id.Data4[3],
2741 if_id.Data4[4], if_id.Data4[5],
2742 if_id.Data4[6], if_id.Data4[7],
2743 if_ver, if_ver_minor);
2746 col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
2747 if_id.Data1, if_id.Data2, if_id.Data3,
2748 if_id.Data4[0], if_id.Data4[1],
2749 if_id.Data4[2], if_id.Data4[3],
2750 if_id.Data4[4], if_id.Data4[5],
2751 if_id.Data4[6], if_id.Data4[7],
2752 if_ver, if_ver_minor);
2754 saw_ctx_item = TRUE;
2757 for (j = 0; j < num_trans_items; j++) {
2758 /* XXX - use "dissect_ndr_uuid_t()"? */
2759 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2761 uuid_str_len = g_snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2762 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2763 trans_id.Data1, trans_id.Data2, trans_id.Data3,
2764 trans_id.Data4[0], trans_id.Data4[1],
2765 trans_id.Data4[2], trans_id.Data4[3],
2766 trans_id.Data4[4], trans_id.Data4[5],
2767 trans_id.Data4[6], trans_id.Data4[7]);
2768 if (uuid_str_len == -1 || uuid_str_len >= DCERPC_UUID_STR_LEN)
2769 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2770 proto_tree_add_string_format (iface_tree, hf_dcerpc_cn_bind_trans_id, tvb,
2771 offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2775 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, iface_tree, hdr->drep,
2776 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
2781 * XXX - we should save the authentication type *if* we have
2782 * an authentication header, and associate it with an authentication
2783 * context, so subsequent PDUs can use that context.
2785 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2789 dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2790 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2792 guint16 max_xmit, max_recv;
2793 guint16 sec_addr_len;
2800 char uuid_str[DCERPC_UUID_STR_LEN];
2802 dcerpc_auth_info auth_info;
2804 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2805 hf_dcerpc_cn_max_xmit, &max_xmit);
2807 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2808 hf_dcerpc_cn_max_recv, &max_recv);
2810 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2811 hf_dcerpc_cn_assoc_group, NULL);
2813 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2814 hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
2815 if (sec_addr_len != 0) {
2816 tvb_ensure_bytes_exist(tvb, offset, sec_addr_len);
2817 proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
2818 sec_addr_len, FALSE);
2819 offset += sec_addr_len;
2823 offset += 4 - offset % 4;
2826 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2827 hf_dcerpc_cn_num_results, &num_results);
2832 for (i = 0; i < num_results; i++) {
2833 proto_tree *ctx_tree = NULL;
2836 proto_item *ctx_item;
2837 ctx_item = proto_tree_add_text(dcerpc_tree, tvb, offset, 24, "Context ID: %d", i);
2838 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
2841 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, ctx_tree,
2842 hdr->drep, hf_dcerpc_cn_ack_result,
2845 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, ctx_tree,
2846 hdr->drep, hf_dcerpc_cn_ack_reason,
2850 * The reason for rejection isn't meaningful, and often isn't
2851 * set, when the syntax was accepted.
2856 /* XXX - use "dissect_ndr_uuid_t()"? */
2857 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2859 uuid_str_len = g_snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2860 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2861 trans_id.Data1, trans_id.Data2, trans_id.Data3,
2862 trans_id.Data4[0], trans_id.Data4[1],
2863 trans_id.Data4[2], trans_id.Data4[3],
2864 trans_id.Data4[4], trans_id.Data4[5],
2865 trans_id.Data4[6], trans_id.Data4[7]);
2866 if (uuid_str_len == -1 || uuid_str_len >= DCERPC_UUID_STR_LEN)
2867 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2868 proto_tree_add_string_format (ctx_tree, hf_dcerpc_cn_ack_trans_id, tvb,
2869 offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2873 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, ctx_tree, hdr->drep,
2874 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
2878 * XXX - do we need to do anything with the authentication level
2879 * we get back from this?
2881 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2883 if (check_col (pinfo->cinfo, COL_INFO)) {
2884 if (num_results != 0 && result == 0) {
2885 /* XXX - only checks the last result */
2886 col_append_fstr (pinfo->cinfo, COL_INFO,
2887 " accept max_xmit: %u max_recv: %u",
2888 max_xmit, max_recv);
2890 /* XXX - only shows the last result and reason */
2891 col_append_fstr (pinfo->cinfo, COL_INFO, " %s, reason: %s",
2892 val_to_str(result, p_cont_result_vals,
2893 "Unknown result (%u)"),
2894 val_to_str(reason, p_provider_reason_vals,
2901 dissect_dcerpc_cn_bind_nak (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2902 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2905 guint8 num_protocols;
2908 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2909 hdr->drep, hf_dcerpc_cn_reject_reason,
2912 if (check_col (pinfo->cinfo, COL_INFO)) {
2913 col_append_fstr (pinfo->cinfo, COL_INFO, " reason: %s",
2914 val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
2917 if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
2918 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2919 hf_dcerpc_cn_num_protocols,
2922 for (i = 0; i < num_protocols; i++) {
2923 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2924 hdr->drep, hf_dcerpc_cn_protocol_ver_major,
2926 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2927 hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
2933 /* Return a string describing a DCE/RPC fragment as first, middle, or end
2936 #define PFC_FRAG_MASK 0x03
2939 fragment_type(guint8 flags)
2941 flags = flags & PFC_FRAG_MASK;
2943 if (flags == PFC_FIRST_FRAG)
2949 if (flags == PFC_LAST_FRAG)
2952 if (flags == (PFC_FIRST_FRAG | PFC_LAST_FRAG))
2958 /* Dissect stub data (payload) of a DCERPC packet. */
2961 dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
2962 proto_tree *dcerpc_tree, proto_tree *tree,
2963 e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
2964 dcerpc_auth_info *auth_info, guint32 alloc_hint,
2967 gint length, reported_length;
2968 gboolean save_fragmented;
2969 fragment_data *fd_head=NULL;
2971 tvbuff_t *auth_tvb, *payload_tvb, *decrypted_tvb;
2973 proto_item *parent_pi;
2974 proto_item *dcerpc_tree_item;
2976 save_fragmented = pinfo->fragmented;
2978 length = tvb_length_remaining(tvb, offset);
2979 reported_length = tvb_reported_length_remaining(tvb, offset);
2980 if (reported_length < 0 ||
2981 (guint32)reported_length < auth_info->auth_size) {
2982 /* We don't even have enough bytes for the authentication
2986 reported_length -= auth_info->auth_size;
2987 if (length > reported_length)
2988 length = reported_length;
2989 payload_tvb = tvb_new_subset(tvb, offset, length, reported_length);
2992 /*dont bother if we dont have the entire tvb */
2993 /*XXX we should really make sure we calculate auth_info->auth_data
2994 and use that one instead of this auth_tvb hack
2996 if(tvb_length(tvb)==tvb_reported_length(tvb)){
2997 if(tvb_length_remaining(tvb, offset+length)>8){
2998 auth_tvb = tvb_new_subset(tvb, offset+length+8, -1, -1);
3002 /* Decrypt the PDU if it is encrypted */
3004 if (auth_info->auth_type &&
3005 auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
3007 * We know the authentication type, and the authentication
3008 * level is "Packet privacy", meaning the payload is
3009 * encrypted; attempt to decrypt it.
3011 dcerpc_auth_subdissector_fns *auth_fns;
3013 /* Start out assuming we won't succeed in decrypting. */
3014 decrypted_tvb = NULL;
3016 if ((auth_fns = get_auth_subdissector_fns(
3017 auth_info->auth_level, auth_info->auth_type))) {
3020 result = decode_encrypted_data(
3021 payload_tvb, auth_tvb, pinfo, auth_fns,
3022 hdr->ptype == PDU_REQ, auth_info);
3026 proto_tree_add_text(
3027 dcerpc_tree, payload_tvb, 0, -1,
3028 "Encrypted stub data (%d byte%s)",
3029 tvb_reported_length(payload_tvb),
3031 plurality(tvb_length(payload_tvb), "", "s"));
3033 add_new_data_source(
3034 pinfo, result, "Decrypted stub data");
3037 decrypted_tvb = result;
3041 decrypted_tvb = payload_tvb;
3043 /* if this packet is not fragmented, just dissect it and exit */
3044 if(PFC_NOT_FRAGMENTED(hdr)){
3045 pinfo->fragmented = FALSE;
3048 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
3049 hdr->drep, di, auth_info);
3051 pinfo->fragmented = save_fragmented;
3055 /* The packet is fragmented. */
3056 pinfo->fragmented = TRUE;
3058 /* debug output of essential fragment data. */
3059 /* leave it here for future debugging sessions */
3060 /*printf("DCE num:%u offset:%u frag_len:%u tvb_len:%u\n",
3061 pinfo->fd->num, offset, hdr->frag_len, tvb_length(decrypted_tvb));*/
3063 /* if we are not doing reassembly and this is the first fragment
3064 then just dissect it and exit
3065 XXX - if we're not doing reassembly, can we decrypt an
3068 if( (!dcerpc_reassemble) && hdr->flags&PFC_FIRST_FRAG ){
3071 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
3072 hdr->drep, di, auth_info);
3074 if (check_col(pinfo->cinfo, COL_INFO)) {
3075 col_append_fstr(pinfo->cinfo, COL_INFO,
3076 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
3078 expert_add_info_format(pinfo, NULL, PI_REASSEMBLE, PI_CHAT,
3079 "%s fragment", fragment_type(hdr->flags));
3080 pinfo->fragmented = save_fragmented;
3084 /* if we have already seen this packet, see if it was reassembled
3085 and if so dissect the full pdu.
3088 if(pinfo->fd->flags.visited){
3089 fd_head=fragment_get_reassembled(pinfo, frame, dcerpc_co_reassemble_table);
3093 /* if we are not doing reassembly and it was neither a complete PDU
3094 nor the first fragment then there is nothing more we can do
3095 so we just have to exit
3097 if( !dcerpc_reassemble )
3100 /* if we didnt get 'frame' we dont know where the PDU started and thus
3101 it is pointless to continue
3106 /* from now on we must attempt to reassemble the PDU
3109 /* if we get here we know it is the first time we see the packet
3110 and we also know it is only a fragment and not a full PDU,
3111 thus we must reassemble it.
3114 /* Do we have any non-encrypted data to reassemble? */
3115 if (decrypted_tvb == NULL) {
3116 /* No. We can't even try to reassemble. */
3120 /* defragmentation is a bit tricky, as there's no offset of the fragment
3121 * in the protocol data.
3123 * just use fragment_add_seq_next() and hope that TCP/SMB segments coming
3124 * in with the correct sequence.
3126 fd_head = fragment_add_seq_next(decrypted_tvb, 0, pinfo, frame,
3127 dcerpc_co_fragment_table, dcerpc_co_reassemble_table,
3128 tvb_length(decrypted_tvb),
3129 hdr->flags&PFC_LAST_FRAG ? FALSE : TRUE /* more_frags */);
3133 /* if reassembly is complete and this is the last fragment
3134 * (multiple fragments in one PDU are possible!)
3135 * dissect the full PDU
3137 if(fd_head && (fd_head->flags&FD_DEFRAGMENTED) ){
3139 if(pinfo->fd->num==fd_head->reassembled_in && (hdr->flags&PFC_LAST_FRAG) ){
3141 proto_item *frag_tree_item;
3143 next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
3144 tvb_set_child_real_data_tvbuff(decrypted_tvb, next_tvb);
3145 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3146 show_fragment_tree(fd_head, &dcerpc_frag_items,
3147 tree, pinfo, next_tvb, &frag_tree_item);
3148 /* the toplevel fragment subtree is now behind all desegmented data,
3149 * move it right behind the DCE/RPC tree */
3150 dcerpc_tree_item = proto_tree_get_parent(dcerpc_tree);
3151 if(frag_tree_item && dcerpc_tree_item) {
3152 proto_tree_move_item(tree, dcerpc_tree_item, frag_tree_item);
3155 pinfo->fragmented = FALSE;
3157 expert_add_info_format(pinfo, frag_tree_item, PI_REASSEMBLE, PI_CHAT,
3158 "%s fragment, %u bytes reassembled here in #%u",
3159 fragment_type(hdr->flags), fd_head->len, fd_head->reassembled_in);
3161 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
3162 next_tvb, hdr->drep, di, auth_info);
3165 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
3166 decrypted_tvb, 0, 0, fd_head->reassembled_in);
3167 PROTO_ITEM_SET_GENERATED(pi);
3168 parent_pi = proto_tree_get_parent(dcerpc_tree);
3169 if(parent_pi != NULL) {
3170 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
3172 if (check_col(pinfo->cinfo, COL_INFO)) {
3173 col_append_fstr(pinfo->cinfo, COL_INFO,
3174 " [DCE/RPC %s fragment, reas: #%u]", fragment_type(hdr->flags), fd_head->reassembled_in);
3176 expert_add_info_format(pinfo, NULL, PI_REASSEMBLE, PI_CHAT,
3177 "%s fragment, reassembled in #%u", fragment_type(hdr->flags), fd_head->reassembled_in);
3180 /* Reassembly not complete - some fragments
3181 are missing. Just show the stub data. */
3182 if (check_col(pinfo->cinfo, COL_INFO)) {
3183 col_append_fstr(pinfo->cinfo, COL_INFO,
3184 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
3186 expert_add_info_format(pinfo, NULL, PI_REASSEMBLE, PI_CHAT,
3187 "%s fragment", fragment_type(hdr->flags));
3190 show_stub_data (decrypted_tvb, 0, tree, auth_info, FALSE);
3192 show_stub_data (payload_tvb, 0, tree, auth_info, TRUE);
3196 pinfo->fragmented = save_fragmented;
3200 * Registers a conversation/UUID binding association, so that
3201 * we can invoke the proper sub-dissector for a given DCERPC
3204 * @param binding all values needed to create and bind a new conversation
3206 * @return Pointer to newly-added UUID/conversation binding.
3208 struct _dcerpc_bind_value *
3209 dcerpc_add_conv_to_bind_table(decode_dcerpc_bind_values_t *binding)
3211 dcerpc_bind_value *bind_value;
3212 dcerpc_bind_key *key;
3213 conversation_t *conv;
3215 conv = find_conversation (
3225 conv = conversation_new (
3235 bind_value = se_alloc (sizeof (dcerpc_bind_value));
3236 bind_value->uuid = binding->uuid;
3237 bind_value->ver = binding->ver;
3239 key = se_alloc(sizeof (dcerpc_bind_key));
3241 key->ctx_id = binding->ctx_id;
3242 key->smb_fid = binding->smb_fid;
3244 /* add this entry to the bind table, first removing any
3245 previous ones that are identical
3247 if(g_hash_table_lookup(dcerpc_binds, key)){
3248 g_hash_table_remove(dcerpc_binds, key);
3250 g_hash_table_insert(dcerpc_binds, key, bind_value);
3257 dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3258 proto_tree *dcerpc_tree, proto_tree *tree,
3259 e_dce_cn_common_hdr_t *hdr)
3261 conversation_t *conv;
3265 dcerpc_auth_info auth_info;
3267 char uuid_str[DCERPC_UUID_STR_LEN];
3270 proto_item *parent_pi;
3272 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3273 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3275 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3276 hf_dcerpc_cn_ctx_id, &ctx_id);
3277 parent_pi = proto_tree_get_parent(dcerpc_tree);
3278 if(parent_pi != NULL) {
3279 proto_item_append_text(parent_pi, " Ctx: %u", ctx_id);
3282 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3283 hf_dcerpc_opnum, &opnum);
3285 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3286 pinfo->dcectxid = ctx_id;
3288 if (check_col (pinfo->cinfo, COL_INFO)) {
3289 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u ctx_id: %u",
3293 if (hdr->flags & PFC_OBJECT_UUID) {
3294 /* XXX - use "dissect_ndr_uuid_t()"? */
3295 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id);
3297 uuid_str_len = g_snprintf(uuid_str, DCERPC_UUID_STR_LEN,
3298 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3299 obj_id.Data1, obj_id.Data2, obj_id.Data3,
3308 if (uuid_str_len == -1 || uuid_str_len >= DCERPC_UUID_STR_LEN)
3309 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
3310 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
3311 offset, 16, uuid_str, "Object UUID: %s", uuid_str);
3317 * XXX - what if this was set when the connection was set up,
3318 * and we just have a security context?
3320 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3322 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3323 pinfo->srcport, pinfo->destport, 0);
3325 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3327 dcerpc_matched_key matched_key, *new_matched_key;
3328 dcerpc_call_value *value;
3330 /* !!! we can NOT check flags.visited here since this will interact
3331 badly with when SMB handles (i.e. calls the subdissector)
3332 and desegmented pdu's .
3333 Instead we check if this pdu is already in the matched table or not
3335 matched_key.frame = pinfo->fd->num;
3336 matched_key.call_id = hdr->call_id;
3337 value = g_hash_table_lookup(dcerpc_matched, &matched_key);
3339 dcerpc_bind_key bind_key;
3340 dcerpc_bind_value *bind_value;
3343 bind_key.ctx_id=ctx_id;
3344 bind_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3346 if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key)) ){
3347 if(!(hdr->flags&PFC_FIRST_FRAG)){
3348 dcerpc_cn_call_key call_key;
3349 dcerpc_call_value *call_value;
3352 call_key.call_id=hdr->call_id;
3353 call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3354 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3355 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
3356 *new_matched_key = matched_key;
3357 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3361 dcerpc_cn_call_key *call_key;
3362 dcerpc_call_value *call_value;
3364 /* We found the binding and it is the first fragment
3365 (or a complete PDU) of a dcerpc pdu so just add
3366 the call to both the call table and the
3369 call_key=se_alloc (sizeof (dcerpc_cn_call_key));
3370 call_key->conv=conv;
3371 call_key->call_id=hdr->call_id;
3372 call_key->smb_fid=dcerpc_get_transport_salt(pinfo);
3374 /* if there is already a matching call in the table
3375 remove it so it is replaced with the new one */
3376 if(g_hash_table_lookup(dcerpc_cn_calls, call_key)){
3377 g_hash_table_remove(dcerpc_cn_calls, call_key);
3380 call_value=se_alloc (sizeof (dcerpc_call_value));
3381 call_value->uuid = bind_value->uuid;
3382 call_value->ver = bind_value->ver;
3383 call_value->opnum = opnum;
3384 call_value->req_frame=pinfo->fd->num;
3385 call_value->req_time=pinfo->fd->abs_ts;
3386 call_value->rep_frame=0;
3387 call_value->max_ptr=0;
3388 call_value->private_data = NULL;
3389 g_hash_table_insert (dcerpc_cn_calls, call_key, call_value);
3391 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
3392 *new_matched_key = matched_key;
3393 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3403 /* handoff this call */
3405 di->call_id = hdr->call_id;
3406 di->smb_fid = dcerpc_get_transport_salt(pinfo);
3407 di->ptype = PDU_REQ;
3408 di->call_data = value;
3411 if(value->rep_frame!=0){
3412 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
3413 tvb, 0, 0, value->rep_frame);
3414 PROTO_ITEM_SET_GENERATED(pi);
3415 if(parent_pi != NULL) {
3416 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
3420 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
3421 hdr, di, &auth_info, alloc_hint,
3424 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3427 /* Dissect the verifier */
3428 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
3433 dissect_dcerpc_cn_resp (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3434 proto_tree *dcerpc_tree, proto_tree *tree,
3435 e_dce_cn_common_hdr_t *hdr)
3437 dcerpc_call_value *value = NULL;
3438 conversation_t *conv;
3440 dcerpc_auth_info auth_info;
3443 proto_item *parent_pi;
3445 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3446 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3448 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3449 hf_dcerpc_cn_ctx_id, &ctx_id);
3450 parent_pi = proto_tree_get_parent(dcerpc_tree);
3451 if(parent_pi != NULL) {
3452 proto_item_append_text(parent_pi, " Ctx: %u", ctx_id);
3455 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3456 pinfo->dcectxid = ctx_id;
3458 if (check_col (pinfo->cinfo, COL_INFO)) {
3459 col_append_fstr (pinfo->cinfo, COL_INFO, " ctx_id: %u", ctx_id);
3462 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3463 hf_dcerpc_cn_cancel_count, NULL);
3468 * XXX - what if this was set when the connection was set up,
3469 * and we just have a security context?
3471 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3473 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3474 pinfo->srcport, pinfo->destport, 0);
3477 /* no point in creating one here, really */
3478 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3480 dcerpc_matched_key matched_key, *new_matched_key;
3482 /* !!! we can NOT check flags.visited here since this will interact
3483 badly with when SMB handles (i.e. calls the subdissector)
3484 and desegmented pdu's .
3485 Instead we check if this pdu is already in the matched table or not
3487 matched_key.frame = pinfo->fd->num;
3488 matched_key.call_id = hdr->call_id;
3489 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3491 dcerpc_cn_call_key call_key;
3492 dcerpc_call_value *call_value;
3495 call_key.call_id=hdr->call_id;
3496 call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3498 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3499 /* extra sanity check, only match them if the reply
3500 came after the request */
3501 if(call_value->req_frame<pinfo->fd->num){
3502 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
3503 *new_matched_key = matched_key;
3504 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3506 if(call_value->rep_frame==0){
3507 call_value->rep_frame=pinfo->fd->num;
3517 /* handoff this call */
3519 di->call_id = hdr->call_id;
3520 di->smb_fid = dcerpc_get_transport_salt(pinfo);
3521 di->ptype = PDU_RESP;
3522 di->call_data = value;
3524 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
3525 if(value->req_frame!=0){
3527 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3528 tvb, 0, 0, value->req_frame);
3529 PROTO_ITEM_SET_GENERATED(pi);
3530 if(parent_pi != NULL) {
3531 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
3533 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
3534 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
3535 PROTO_ITEM_SET_GENERATED(pi);
3538 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
3539 hdr, di, &auth_info, alloc_hint,
3542 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3545 /* Dissect the verifier */
3546 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
3550 dissect_dcerpc_cn_fault (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3551 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
3553 dcerpc_call_value *value = NULL;
3554 conversation_t *conv;
3558 dcerpc_auth_info auth_info;
3559 proto_item *pi = NULL;
3561 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3562 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3564 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3565 hf_dcerpc_cn_ctx_id, &ctx_id);
3567 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3568 hf_dcerpc_cn_cancel_count, NULL);
3572 /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3573 hf_dcerpc_cn_status, &status);*/
3574 status = ((hdr->drep[0] & 0x10)
3575 ? tvb_get_letohl (tvb, offset)
3576 : tvb_get_ntohl (tvb, offset));
3579 pi = proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_status, tvb, offset, 4, (hdr->drep[0] & 0x10));
3583 expert_add_info_format(pinfo, pi, PI_RESPONSE_CODE, PI_NOTE, "Fault: %s",
3584 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
3586 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3587 pinfo->dcectxid = ctx_id;
3589 if (check_col (pinfo->cinfo, COL_INFO)) {
3590 col_append_fstr (pinfo->cinfo, COL_INFO,
3591 " ctx_id: %u status: %s", ctx_id,
3592 val_to_str(status, reject_status_vals,
3593 "Unknown (0x%08x)"));
3600 * XXX - what if this was set when the connection was set up,
3601 * and we just have a security context?
3603 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3605 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3606 pinfo->srcport, pinfo->destport, 0);
3608 /* no point in creating one here, really */
3610 dcerpc_matched_key matched_key, *new_matched_key;
3612 /* !!! we can NOT check flags.visited here since this will interact
3613 badly with when SMB handles (i.e. calls the subdissector)
3614 and desegmented pdu's .
3615 Instead we check if this pdu is already in the matched table or not
3617 matched_key.frame = pinfo->fd->num;
3618 matched_key.call_id = hdr->call_id;
3619 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3621 dcerpc_cn_call_key call_key;
3622 dcerpc_call_value *call_value;
3625 call_key.call_id=hdr->call_id;
3626 call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3628 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3629 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
3630 *new_matched_key = matched_key;
3631 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3633 if(call_value->rep_frame==0){
3634 call_value->rep_frame=pinfo->fd->num;
3641 int length, reported_length, stub_length;
3643 proto_item *parent_pi;
3646 /* handoff this call */
3648 di->call_id = hdr->call_id;
3649 di->smb_fid = dcerpc_get_transport_salt(pinfo);
3650 di->ptype = PDU_FAULT;
3651 di->call_data = value;
3653 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
3654 if(value->req_frame!=0){
3656 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3657 tvb, 0, 0, value->req_frame);
3658 PROTO_ITEM_SET_GENERATED(pi);
3659 parent_pi = proto_tree_get_parent(dcerpc_tree);
3660 if(parent_pi != NULL) {
3661 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
3663 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
3664 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
3665 PROTO_ITEM_SET_GENERATED(pi);
3668 length = tvb_length_remaining(tvb, offset);
3669 reported_length = tvb_reported_length_remaining(tvb, offset);
3670 /* as we now create a tvb in dissect_dcerpc_cn() containing only the
3671 * stub_data, the following calculation is no longer valid:
3672 * stub_length = hdr->frag_len - offset - auth_info.auth_size;
3673 * simply use the remaining length of the tvb instead.
3674 * XXX - or better use the reported_length?!?
3676 stub_length = length;
3677 if (length > stub_length)
3678 length = stub_length;
3679 if (reported_length > stub_length)
3680 reported_length = stub_length;
3682 /* If we don't have reassembly enabled, or this packet contains
3683 the entire PDU, or if we don't have all the data in this
3684 fragment, just call the handoff directly if this is the
3685 first fragment or the PDU isn't fragmented. */
3686 if( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
3687 !tvb_bytes_exist(tvb, offset, stub_length) ){
3688 if(hdr->flags&PFC_FIRST_FRAG){
3689 /* First fragment, possibly the only fragment */
3691 * XXX - should there be a third routine for each
3692 * function in an RPC subdissector, to handle
3693 * fault responses? The DCE RPC 1.1 spec says
3694 * three's "stub data" here, which I infer means
3695 * that it's protocol-specific and call-specific.
3697 * It should probably get passed the status code
3698 * as well, as that might be protocol-specific.
3701 if (stub_length > 0) {
3702 tvb_ensure_bytes_exist(tvb, offset, stub_length);
3703 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3704 "Fault stub data (%d byte%s)",
3706 plurality(stub_length, "", "s"));
3710 /* PDU is fragmented and this isn't the first fragment */
3711 if (check_col(pinfo->cinfo, COL_INFO)) {
3712 col_append_fstr(pinfo->cinfo, COL_INFO,
3713 " [DCE/RPC fragment]");
3716 if (stub_length > 0) {
3717 tvb_ensure_bytes_exist(tvb, offset, stub_length);
3718 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3719 "Fragment data (%d byte%s)",
3721 plurality(stub_length, "", "s"));
3726 /* Reassembly is enabled, the PDU is fragmented, and
3727 we have all the data in the fragment; the first two
3728 of those mean we should attempt reassembly, and the
3729 third means we can attempt reassembly. */
3732 tvb_ensure_bytes_exist(tvb, offset, stub_length);
3733 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3734 "Fragment data (%d byte%s)",
3736 plurality(stub_length, "", "s"));
3739 if(hdr->flags&PFC_FIRST_FRAG){ /* FIRST fragment */
3740 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
3741 fragment_add_seq_next(tvb, offset, pinfo, value->rep_frame,
3742 dcerpc_co_fragment_table, dcerpc_co_reassemble_table,
3746 if (check_col(pinfo->cinfo, COL_INFO)) {
3747 col_append_fstr(pinfo->cinfo, COL_INFO,
3748 " [DCE/RPC fragment]");
3750 } else if(hdr->flags&PFC_LAST_FRAG){ /* LAST fragment */
3751 if( value->rep_frame ){
3752 fragment_data *fd_head;
3754 fd_head = fragment_add_seq_next(tvb, offset, pinfo,
3756 dcerpc_co_fragment_table, dcerpc_co_reassemble_table,
3761 /* We completed reassembly */
3763 proto_item *frag_tree_item;
3765 next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
3766 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
3767 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3768 show_fragment_tree(fd_head, &dcerpc_frag_items,
3769 dcerpc_tree, pinfo, next_tvb, &frag_tree_item);
3772 * XXX - should there be a third routine for each
3773 * function in an RPC subdissector, to handle
3774 * fault responses? The DCE RPC 1.1 spec says
3775 * three's "stub data" here, which I infer means
3776 * that it's protocol-specific and call-specific.
3778 * It should probably get passed the status code
3779 * as well, as that might be protocol-specific.
3783 tvb_ensure_bytes_exist(tvb, offset, stub_length);
3784 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3785 "Fault stub data (%d byte%s)",
3787 plurality(stub_length, "", "s"));
3791 /* Reassembly not complete - some fragments
3793 if (check_col(pinfo->cinfo, COL_INFO)) {
3794 col_append_fstr(pinfo->cinfo, COL_INFO,
3795 " [DCE/RPC fragment]");
3799 } else { /* MIDDLE fragment(s) */
3800 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
3801 fragment_add_seq_next(tvb, offset, pinfo, value->rep_frame,
3802 dcerpc_co_fragment_table, dcerpc_co_reassemble_table,
3806 if (check_col(pinfo->cinfo, COL_INFO)) {
3807 col_append_fstr(pinfo->cinfo, COL_INFO,
3808 " [DCE/RPC fragment]");
3817 * DCERPC dissector for connection oriented calls.
3818 * We use transport type to later multiplex between what kind of
3819 * pinfo->private_data structure to expect.
3822 dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
3823 proto_tree *tree, gboolean can_desegment, int *pkt_len)
3825 static const guint8 nulls[4] = { 0 };
3828 proto_item *ti = NULL;
3829 proto_item *tf = NULL;
3830 proto_tree *dcerpc_tree = NULL;
3831 proto_tree *cn_flags_tree = NULL;
3832 proto_tree *drep_tree = NULL;
3833 e_dce_cn_common_hdr_t hdr;
3834 dcerpc_auth_info auth_info;
3835 tvbuff_t *fragment_tvb;
3838 * when done over nbt, dcerpc requests are padded with 4 bytes of null
3839 * data for some reason.
3841 * XXX - if that's always the case, the right way to do this would
3842 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
3843 * the 4 bytes of null padding, and make that the dissector
3844 * used for "netbios".
3846 if (tvb_memeql (tvb, offset, nulls, 4) == 0) {
3855 * Check if this looks like a C/O DCERPC call
3857 if (!tvb_bytes_exist (tvb, offset, sizeof (hdr))) {
3858 return FALSE; /* not enough information to check */
3860 start_offset = offset;
3861 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
3862 if (hdr.rpc_ver != 5)
3864 hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
3865 if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
3867 hdr.ptype = tvb_get_guint8 (tvb, offset++);
3871 hdr.flags = tvb_get_guint8 (tvb, offset++);
3872 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
3873 offset += sizeof (hdr.drep);
3875 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3877 hdr.auth_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3879 hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3882 if (check_col (pinfo->cinfo, COL_DCE_CALL)) {
3883 if(pinfo->dcectxid == 0) {
3884 col_append_fstr (pinfo->cinfo, COL_DCE_CALL, "%u", hdr.call_id);
3886 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
3887 * prepend a delimiter */
3888 col_append_fstr (pinfo->cinfo, COL_DCE_CALL, "#%u", hdr.call_id);
3892 if (can_desegment && pinfo->can_desegment
3893 && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
3894 pinfo->desegment_offset = start_offset;
3895 pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, start_offset);
3896 *pkt_len = 0; /* desegmentation required */
3900 if (check_col (pinfo->cinfo, COL_PROTOCOL))
3901 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
3903 if (check_col (pinfo->cinfo, COL_INFO)) {
3904 if(pinfo->dcectxid != 0) {
3905 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
3906 * append a delimiter and set a column fence */
3907 col_append_str (pinfo->cinfo, COL_INFO, " # ");
3908 col_set_fence(pinfo->cinfo,COL_INFO);
3910 col_add_fstr (pinfo->cinfo, COL_INFO, "%s: call_id: %u",
3911 pckt_vals[hdr.ptype].strptr, hdr.call_id);
3914 if(pinfo->dcectxid != 0) {
3915 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU */
3916 expert_add_info_format(pinfo, NULL, PI_SEQUENCE, PI_NOTE, "Multiple DCE/RPC fragments/PDU's in one packet");
3919 offset = start_offset;
3920 tvb_ensure_bytes_exist(tvb, offset, 16);
3922 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE);
3923 dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
3926 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
3929 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset, 1, hdr.rpc_ver_minor);
3932 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
3935 /* XXX - too much "output noise", removed for now
3936 if(hdr.ptype == PDU_BIND || hdr.ptype == PDU_ALTER ||
3937 hdr.ptype == PDU_BIND_ACK || hdr.ptype == PDU_ALTER_ACK)
3938 expert_add_info_format(pinfo, tf, PI_SEQUENCE, PI_CHAT, "Context change: %s",
3939 val_to_str(hdr.ptype, pckt_vals, "(0x%x)"));*/
3940 if(hdr.ptype == PDU_BIND_NAK)
3941 expert_add_info_format(pinfo, tf, PI_SEQUENCE, PI_WARN, "Bind not acknowledged");
3944 proto_item_append_text(ti, " %s, Fragment:", val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"));
3946 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
3947 cn_flags_tree = proto_item_add_subtree (tf, ett_dcerpc_cn_flags);
3949 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
3950 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
3951 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
3952 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
3953 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
3954 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
3955 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
3956 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
3957 if( (hdr.flags & PFC_FIRST_FRAG) && (hdr.flags & PFC_LAST_FRAG) ) {
3958 proto_item_append_text(ti, " Single");
3960 if(hdr.flags & PFC_FIRST_FRAG) {
3961 proto_item_append_text(ti, " 1st");
3963 if(hdr.flags & PFC_LAST_FRAG) {
3964 proto_item_append_text(ti, " Last");
3966 if( !(hdr.flags & PFC_FIRST_FRAG) && !(hdr.flags & PFC_LAST_FRAG) ) {
3967 proto_item_append_text(ti, " Mid");
3973 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
3974 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
3976 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
3977 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
3978 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
3979 offset += sizeof (hdr.drep);
3981 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
3984 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
3987 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
3991 proto_item_append_text(ti, ", FragLen: %u, Call: %u", hdr.frag_len, hdr.call_id);
3995 * None of the stuff done above should throw an exception, because
3996 * we would have rejected this as "not DCE RPC" if we didn't have all
3997 * of it. (XXX - perhaps we should request reassembly if we have
3998 * enough of the header to consider it DCE RPC but not enough to
3999 * get the fragment length; in that case the stuff still wouldn't
4000 * throw an exception.)
4002 * The rest of the stuff might, so return the PDU length to our caller.
4003 * XXX - should we construct a tvbuff containing only the PDU and
4004 * use that? Or should we have separate "is this a DCE RPC PDU",
4005 * "how long is it", and "dissect it" routines - which might let us
4006 * do most of the work in "tcp_dissect_pdus()"?
4008 if (pkt_len != NULL)
4009 *pkt_len = hdr.frag_len + padding;
4011 /* The remaining bytes in the current tvb might contain multiple
4012 * DCE/RPC fragments, so create a new tvb subset for this fragment.
4013 * Only limit the end of the fragment, but not the offset start,
4014 * as the authentication function dissect_dcerpc_cn_auth() will fail
4015 * (and other functions might fail as well) computing the right start
4018 fragment_tvb = tvb_new_subset(tvb, 0,
4019 MIN((hdr.frag_len + start_offset),tvb_length(tvb)) /* length */,
4020 hdr.frag_len + start_offset /* reported_length */);
4023 * Packet type specific stuff is next.
4025 switch (hdr.ptype) {
4028 dissect_dcerpc_cn_bind (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr);
4033 dissect_dcerpc_cn_bind_ack (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr);
4038 * Nothing after the common header other than credentials.
4040 dissect_dcerpc_cn_auth (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr, TRUE,
4045 dissect_dcerpc_cn_rqst (fragment_tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
4049 dissect_dcerpc_cn_resp (fragment_tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
4053 dissect_dcerpc_cn_fault (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr);
4057 dissect_dcerpc_cn_bind_nak (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr);
4063 * Nothing after the common header other than an authentication
4066 dissect_dcerpc_cn_auth (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
4072 * Nothing after the common header, not even an authentication
4078 /* might as well dissect the auth info */
4079 dissect_dcerpc_cn_auth (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
4087 * DCERPC dissector for connection oriented calls over packet-oriented
4091 dissect_dcerpc_cn_pk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4094 * Only one PDU per transport packet, and only one transport
4097 pinfo->dcetransporttype=DCE_TRANSPORT_UNKNOWN;
4098 if (!dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE, NULL)) {
4100 * It wasn't a DCERPC PDU.
4112 * DCERPC dissector for connection oriented calls over byte-stream
4114 * we need to distinguish here between SMB and non-TCP (more in the future?)
4115 * to be able to know what kind of private_data structure to expect.
4118 dissect_dcerpc_cn_bs_body (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4120 volatile int offset = 0;
4122 volatile gboolean dcerpc_pdus = 0;
4123 volatile gboolean ret = FALSE;
4126 * There may be multiple PDUs per transport packet; keep
4129 while (tvb_reported_length_remaining(tvb, offset) != 0) {
4131 * Catch ReportedBoundsError, so that even if the stub data is bad,
4132 * we don't abort the full DCE RPC dissection - there might be more
4133 * than one DCE RPC PDU in the data being dissected.
4135 * If we get BoundsError, it means the frame was cut short by a
4136 * snapshot length, so there's nothing more to dissect; just
4137 * re-throw that exception.
4141 if(dissect_dcerpc_cn (tvb, offset, pinfo, tree,
4142 dcerpc_cn_desegment, &pdu_len)) {
4145 } CATCH(BoundsError) {
4147 } CATCH(ReportedBoundsError) {
4148 show_reported_bounds_error(tvb, pinfo, tree);
4159 * Well, we've seen at least one DCERPC PDU.
4163 /* if we had more than one Req/Resp in this PDU change the protocol column */
4164 /* this will formerly contain the last interface name, which may not be the same for all Req/Resp */
4165 if (dcerpc_pdus >= 2 && check_col (pinfo->cinfo, COL_PROTOCOL))
4166 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "%u*DCERPC", dcerpc_pdus);
4170 * Desegmentation required - bail now, but give the user a hint that desegmentation might be done later.
4172 proto_tree_add_uint_format(tree, hf_dcerpc_cn_deseg_req, tvb, offset,
4174 tvb_reported_length_remaining(tvb, offset),
4175 "[DCE RPC: %u byte%s left, desegmentation might follow]",
4176 tvb_reported_length_remaining(tvb, offset),
4177 plurality(tvb_reported_length_remaining(tvb, offset), "", "s"));
4182 * Step to the next PDU.
4190 dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4192 pinfo->dcetransporttype=DCE_TRANSPORT_UNKNOWN;
4193 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
4197 dissect_dcerpc_cn_smbpipe (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4199 pinfo->dcetransporttype=DCE_CN_TRANSPORT_SMBPIPE;
4200 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
4206 dissect_dcerpc_dg_auth (tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
4207 e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
4209 proto_item *ti = NULL;
4210 proto_tree *auth_tree = NULL;
4211 guint8 protection_level;
4214 * Initially set "*auth_level_p" to -1 to indicate that we haven't
4215 * yet seen any authentication level information.
4217 if (auth_level_p != NULL)
4221 * The authentication information is at the *end* of the PDU; in
4222 * request and response PDUs, the request and response stub data
4225 * If the full packet is here, and there's data past the end of the
4226 * packet body, then dissect the auth info.
4228 offset += hdr->frag_len;
4229 if (tvb_length_remaining(tvb, offset) > 0) {
4230 switch (hdr->auth_proto) {
4232 case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
4233 ti = proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Kerberos authentication verifier");
4234 auth_tree = proto_item_add_subtree (ti, ett_dcerpc_krb5_auth_verf);
4235 protection_level = tvb_get_guint8 (tvb, offset);
4236 if (auth_level_p != NULL)
4237 *auth_level_p = protection_level;
4238 proto_tree_add_uint (auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
4240 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, FALSE);
4242 if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
4243 offset += 6; /* 6 bytes of padding */
4245 offset += 2; /* 6 bytes of padding */
4246 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, FALSE);
4251 proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Authentication verifier");
4258 dissect_dcerpc_dg_cancel_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
4259 proto_tree *dcerpc_tree,
4260 e_dce_dg_common_hdr_t *hdr)
4264 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4265 hdr->drep, hf_dcerpc_dg_cancel_vers,
4271 /* The only version we know about */
4272 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4273 hdr->drep, hf_dcerpc_dg_cancel_id,
4275 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
4276 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
4283 dissect_dcerpc_dg_cancel (tvbuff_t *tvb, int offset, packet_info *pinfo,
4284 proto_tree *dcerpc_tree,
4285 e_dce_dg_common_hdr_t *hdr)
4289 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4290 hdr->drep, hf_dcerpc_dg_cancel_vers,
4296 /* The only version we know about */
4297 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4298 hdr->drep, hf_dcerpc_dg_cancel_id,
4300 /* XXX - are NDR booleans 32 bits? */
4302 /* XXX - the RPC reference in chapter: "the cancel PDU" doesn't mention
4303 the accepting_cancels field (it's only in the cancel_ack PDU)! */
4304 /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4305 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
4312 dissect_dcerpc_dg_fack (tvbuff_t *tvb, int offset, packet_info *pinfo,
4313 proto_tree *dcerpc_tree,
4314 e_dce_dg_common_hdr_t *hdr)
4321 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
4322 hdr->drep, hf_dcerpc_dg_fack_vers,
4329 case 0: /* The only version documented in the DCE RPC 1.1 spec */
4330 case 1: /* This appears to be the same */
4331 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
4332 hdr->drep, hf_dcerpc_dg_fack_window_size,
4334 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4335 hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
4337 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4338 hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
4340 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
4341 hdr->drep, hf_dcerpc_dg_fack_serial_num,
4343 if (check_col (pinfo->cinfo, COL_INFO)) {
4344 col_append_fstr (pinfo->cinfo, COL_INFO, " serial: %u",
4347 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
4348 hdr->drep, hf_dcerpc_dg_fack_selack_len,
4350 for (i = 0; i < selack_len; i++) {
4351 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4352 hdr->drep, hf_dcerpc_dg_fack_selack,
4361 dissect_dcerpc_dg_reject_fault (tvbuff_t *tvb, int offset, packet_info *pinfo,
4362 proto_tree *dcerpc_tree,
4363 e_dce_dg_common_hdr_t *hdr)
4367 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4368 hdr->drep, hf_dcerpc_dg_status,
4371 if (check_col (pinfo->cinfo, COL_INFO)) {
4372 col_append_fstr (pinfo->cinfo, COL_INFO,
4374 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
4379 dissect_dcerpc_dg_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
4380 proto_tree *dcerpc_tree, proto_tree *tree,
4381 e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
4383 int length, reported_length, stub_length;
4384 gboolean save_fragmented;
4385 fragment_data *fd_head;
4388 proto_item *parent_pi;
4390 if (check_col (pinfo->cinfo, COL_INFO))
4391 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u len: %u",
4392 di->call_data->opnum, hdr->frag_len );
4394 length = tvb_length_remaining (tvb, offset);
4395 reported_length = tvb_reported_length_remaining (tvb, offset);
4396 stub_length = hdr->frag_len;
4397 if (length > stub_length)
4398 length = stub_length;
4399 if (reported_length > stub_length)
4400 reported_length = stub_length;
4402 save_fragmented = pinfo->fragmented;
4404 /* If we don't have reassembly enabled, or this packet contains
4405 the entire PDU, or if this is a short frame (or a frame
4406 not reassembled at a lower layer) that doesn't include all
4407 the data in the fragment, just call the handoff directly if
4408 this is the first fragment or the PDU isn't fragmented. */
4409 if( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
4410 !tvb_bytes_exist(tvb, offset, stub_length) ){
4411 if(hdr->frag_num == 0) {
4414 /* First fragment, possibly the only fragment */
4417 * XXX - authentication info?
4419 pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
4420 next_tvb = tvb_new_subset (tvb, offset, length,
4422 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
4423 next_tvb, hdr->drep, di, NULL);
4425 /* PDU is fragmented and this isn't the first fragment */
4426 if (check_col(pinfo->cinfo, COL_INFO)) {
4427 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
4431 tvb_ensure_bytes_exist(tvb, offset, stub_length);
4432 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
4433 "Fragment data (%d byte%s)",
4435 plurality(stub_length, "", "s"));
4440 /* Reassembly is enabled, the PDU is fragmented, and
4441 we have all the data in the fragment; the first two
4442 of those mean we should attempt reassembly, and the
4443 third means we can attempt reassembly. */
4446 tvb_ensure_bytes_exist(tvb, offset, stub_length);
4447 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
4448 "Fragment data (%d byte%s)", stub_length,
4449 plurality(stub_length, "", "s"));
4453 fd_head = fragment_add_dcerpc_dg(tvb, offset, pinfo,
4454 hdr->seqnum, &hdr->act_id, dcerpc_cl_reassemble_table,
4455 hdr->frag_num, stub_length,
4456 !(hdr->flags1 & PFCL1_LASTFRAG));
4457 if (fd_head != NULL) {
4458 /* We completed reassembly... */
4459 if(pinfo->fd->num==fd_head->reassembled_in) {
4460 /* ...and this is the reassembled RPC PDU */
4461 next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
4462 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
4463 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
4464 show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
4465 tree, pinfo, next_tvb, &pi);
4468 * XXX - authentication info?
4470 pinfo->fragmented = FALSE;
4471 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
4472 next_tvb, hdr->drep, di, NULL);
4474 /* ...and this isn't the reassembled RPC PDU */
4475 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
4476 tvb, 0, 0, fd_head->reassembled_in);
4477 PROTO_ITEM_SET_GENERATED(pi);
4478 parent_pi = proto_tree_get_parent(dcerpc_tree);
4479 if(parent_pi != NULL) {
4480 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
4482 if (check_col(pinfo->cinfo, COL_INFO)) {
4483 col_append_fstr(pinfo->cinfo, COL_INFO,
4484 " [DCE/RPC fragment, reas: #%u]", fd_head->reassembled_in);
4488 /* Reassembly isn't completed yet */
4489 if (check_col(pinfo->cinfo, COL_INFO)) {
4490 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
4494 pinfo->fragmented = save_fragmented;
4498 dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo,
4499 proto_tree *dcerpc_tree, proto_tree *tree,
4500 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4503 dcerpc_call_value *value, v;
4504 dcerpc_matched_key matched_key, *new_matched_key;
4506 proto_item *parent_pi;
4509 if(!(pinfo->fd->flags.visited)){
4510 dcerpc_call_value *call_value;
4511 dcerpc_dg_call_key *call_key;
4513 call_key=se_alloc (sizeof (dcerpc_dg_call_key));
4514 call_key->conv=conv;
4515 call_key->seqnum=hdr->seqnum;
4516 call_key->act_id=hdr->act_id;
4518 call_value=se_alloc (sizeof (dcerpc_call_value));
4519 call_value->uuid = hdr->if_id;
4520 call_value->ver = hdr->if_ver;
4521 call_value->opnum = hdr->opnum;
4522 call_value->req_frame=pinfo->fd->num;
4523 call_value->req_time=pinfo->fd->abs_ts;
4524 call_value->rep_frame=0;
4525 call_value->max_ptr=0;
4526 call_value->private_data = NULL;
4527 g_hash_table_insert (dcerpc_dg_calls, call_key, call_value);
4529 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
4530 new_matched_key->frame = pinfo->fd->num;
4531 new_matched_key->call_id = hdr->seqnum;
4532 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
4535 matched_key.frame = pinfo->fd->num;
4536 matched_key.call_id = hdr->seqnum;
4537 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
4539 v.uuid = hdr->if_id;
4540 v.ver = hdr->if_ver;
4541 v.opnum = hdr->opnum;
4542 v.req_frame = pinfo->fd->num;
4545 v.private_data=NULL;
4550 di->call_id = hdr->seqnum;
4552 di->ptype = PDU_REQ;
4553 di->call_data = value;
4555 if(value->rep_frame!=0){
4556 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
4557 tvb, 0, 0, value->rep_frame);
4558 PROTO_ITEM_SET_GENERATED(pi);
4559 parent_pi = proto_tree_get_parent(dcerpc_tree);
4560 if(parent_pi != NULL) {
4561 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
4564 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
4568 dissect_dcerpc_dg_resp (tvbuff_t *tvb, int offset, packet_info *pinfo,
4569 proto_tree *dcerpc_tree, proto_tree *tree,
4570 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4573 dcerpc_call_value *value, v;
4574 dcerpc_matched_key matched_key, *new_matched_key;
4576 proto_item *parent_pi;
4579 if(!(pinfo->fd->flags.visited)){
4580 dcerpc_call_value *call_value;
4581 dcerpc_dg_call_key call_key;
4584 call_key.seqnum=hdr->seqnum;
4585 call_key.act_id=hdr->act_id;
4587 if((call_value=g_hash_table_lookup(dcerpc_dg_calls, &call_key))){
4588 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
4589 new_matched_key->frame = pinfo->fd->num;
4590 new_matched_key->call_id = hdr->seqnum;
4591 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
4592 if(call_value->rep_frame==0){
4593 call_value->rep_frame=pinfo->fd->num;
4598 matched_key.frame = pinfo->fd->num;
4599 matched_key.call_id = hdr->seqnum;
4600 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
4602 v.uuid = hdr->if_id;
4603 v.ver = hdr->if_ver;
4604 v.opnum = hdr->opnum;
4606 v.rep_frame=pinfo->fd->num;
4607 v.private_data=NULL;
4614 di->ptype = PDU_RESP;
4615 di->call_data = value;
4617 if(value->req_frame!=0){
4619 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4620 tvb, 0, 0, value->req_frame);
4621 PROTO_ITEM_SET_GENERATED(pi);
4622 parent_pi = proto_tree_get_parent(dcerpc_tree);
4623 if(parent_pi != NULL) {
4624 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
4626 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
4627 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
4628 PROTO_ITEM_SET_GENERATED(pi);
4630 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
4634 dissect_dcerpc_dg_ping_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
4635 proto_tree *dcerpc_tree, proto_tree *tree,
4636 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4638 proto_item *parent_pi;
4639 /* if(!(pinfo->fd->flags.visited)){*/
4640 dcerpc_call_value *call_value;
4641 dcerpc_dg_call_key call_key;
4644 call_key.seqnum=hdr->seqnum;
4645 call_key.act_id=hdr->act_id;
4647 if((call_value=g_hash_table_lookup(dcerpc_dg_calls, &call_key))){
4651 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4652 tvb, 0, 0, call_value->req_frame);
4653 PROTO_ITEM_SET_GENERATED(pi);
4654 parent_pi = proto_tree_get_parent(dcerpc_tree);
4655 if(parent_pi != NULL) {
4656 proto_item_append_text(parent_pi, ", [Req: #%u]", call_value->req_frame);
4659 if (check_col (pinfo->cinfo, COL_INFO))
4660 col_append_fstr(pinfo->cinfo, COL_INFO, " [req: #%u]", call_value->req_frame);
4662 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &call_value->req_time);
4663 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
4664 PROTO_ITEM_SET_GENERATED(pi);
4670 * DCERPC dissector for connectionless calls
4673 dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4675 proto_item *ti = NULL;
4676 proto_item *tf = NULL;
4677 proto_tree *dcerpc_tree = NULL;
4678 proto_tree *dg_flags1_tree = NULL;
4679 proto_tree *dg_flags2_tree = NULL;
4680 proto_tree *drep_tree = NULL;
4681 e_dce_dg_common_hdr_t hdr;
4683 conversation_t *conv;
4685 char uuid_str[DCERPC_UUID_STR_LEN];
4689 * Check if this looks like a CL DCERPC call. All dg packets
4690 * have an 80 byte header on them. Which starts with
4691 * version (4), pkt_type.
4693 if (!tvb_bytes_exist (tvb, 0, sizeof (hdr))) {
4697 /* Version must be 4 */
4698 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
4699 if (hdr.rpc_ver != 4)
4702 /* Type must be <=19 or its not DCE/RPC */
4703 hdr.ptype = tvb_get_guint8 (tvb, offset++);
4707 /* flags1 has bit 1 and 8 as reserved so if any of them are set, it is
4708 probably not a DCE/RPC packet
4710 hdr.flags1 = tvb_get_guint8 (tvb, offset++);
4714 /* flags2 has all bits except bit 2 as reserved so if any of them are set
4715 it is probably not DCE/RPC.
4717 hdr.flags2 = tvb_get_guint8 (tvb, offset++);
4722 if (check_col (pinfo->cinfo, COL_PROTOCOL))
4723 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
4724 if (check_col (pinfo->cinfo, COL_INFO))
4725 col_add_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
4727 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
4728 offset += sizeof (hdr.drep);
4729 hdr.serial_hi = tvb_get_guint8 (tvb, offset++);
4730 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.obj_id);
4732 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.if_id);
4734 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.act_id);
4736 hdr.server_boot = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4738 hdr.if_ver = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4740 hdr.seqnum = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4742 hdr.opnum = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4744 hdr.ihint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4746 hdr.ahint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4748 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4750 hdr.frag_num = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4752 hdr.auth_proto = tvb_get_guint8 (tvb, offset++);
4753 hdr.serial_lo = tvb_get_guint8 (tvb, offset++);
4756 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, -1, FALSE);
4758 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
4759 proto_item_append_text(ti, " %s, Seq: %u, Serial: %u, Frag: %u, FragLen: %u",
4760 val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"),
4761 hdr.seqnum, hdr.serial_hi*256+hdr.serial_lo,
4762 hdr.frag_num, hdr.frag_len);
4768 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
4772 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
4776 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
4777 dg_flags1_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags1);
4778 if (dg_flags1_tree) {
4779 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
4780 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
4781 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
4782 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
4783 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
4784 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
4785 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
4786 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
4788 proto_item_append_text(tf, " %s%s%s%s%s%s",
4789 (hdr.flags1 & PFCL1_BROADCAST) ? "\"Broadcast\" " : "",
4790 (hdr.flags1 & PFCL1_IDEMPOTENT) ? "\"Idempotent\" " : "",
4791 (hdr.flags1 & PFCL1_MAYBE) ? "\"Maybe\" " : "",
4792 (hdr.flags1 & PFCL1_NOFACK) ? "\"No Fack\" " : "",
4793 (hdr.flags1 & PFCL1_FRAG) ? "\"Fragment\" " : "",
4794 (hdr.flags1 & PFCL1_LASTFRAG) ? "\"Last Fragment\" " : "");
4801 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
4802 dg_flags2_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags2);
4803 if (dg_flags2_tree) {
4804 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
4805 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
4806 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
4807 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
4808 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
4809 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
4810 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
4811 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
4813 proto_item_append_text(tf, " %s",
4814 (hdr.flags2 & PFCL2_CANCEL_PENDING) ? "\"Cancel Pending\" " : "");
4821 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
4822 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
4824 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
4825 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
4826 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
4827 proto_item_append_text(tf, " (Order: %s, Char: %s, Float: %s)",
4828 val_to_str(hdr.drep[0] >> 4, drep_byteorder_vals, "Unknown"),
4829 val_to_str(hdr.drep[0] & 0x0f, drep_character_vals, "Unknown"),
4830 val_to_str(hdr.drep[1], drep_fp_vals, "Unknown"));
4833 offset += sizeof (hdr.drep);
4836 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
4840 /* XXX - use "dissect_ndr_uuid_t()"? */
4841 uuid_str_len = g_snprintf(uuid_str, DCERPC_UUID_STR_LEN,
4842 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
4843 hdr.obj_id.Data1, hdr.obj_id.Data2, hdr.obj_id.Data3,
4844 hdr.obj_id.Data4[0],
4845 hdr.obj_id.Data4[1],
4846 hdr.obj_id.Data4[2],
4847 hdr.obj_id.Data4[3],
4848 hdr.obj_id.Data4[4],
4849 hdr.obj_id.Data4[5],
4850 hdr.obj_id.Data4[6],
4851 hdr.obj_id.Data4[7]);
4852 if (uuid_str_len == -1 || uuid_str_len >= DCERPC_UUID_STR_LEN)
4853 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
4854 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
4855 offset, 16, uuid_str, "Object UUID: %s", uuid_str);
4860 /* XXX - use "dissect_ndr_uuid_t()"? */
4861 uuid_str_len = g_snprintf(uuid_str, DCERPC_UUID_STR_LEN,
4862 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
4863 hdr.if_id.Data1, hdr.if_id.Data2, hdr.if_id.Data3,
4871 hdr.if_id.Data4[7]);
4872 if (uuid_str_len == -1 || uuid_str_len >= DCERPC_UUID_STR_LEN)
4873 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
4874 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
4875 offset, 16, uuid_str, "Interface: %s", uuid_str);
4880 /* XXX - use "dissect_ndr_uuid_t()"? */
4881 uuid_str_len = g_snprintf(uuid_str, DCERPC_UUID_STR_LEN,
4882 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
4883 hdr.act_id.Data1, hdr.act_id.Data2, hdr.act_id.Data3,
4884 hdr.act_id.Data4[0],
4885 hdr.act_id.Data4[1],
4886 hdr.act_id.Data4[2],
4887 hdr.act_id.Data4[3],
4888 hdr.act_id.Data4[4],
4889 hdr.act_id.Data4[5],
4890 hdr.act_id.Data4[6],
4891 hdr.act_id.Data4[7]);
4892 if (uuid_str_len == -1 || uuid_str_len >= DCERPC_UUID_STR_LEN)
4893 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
4894 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
4895 offset, 16, uuid_str, "Activity: %s", uuid_str);
4900 nstime_t server_boot;
4902 server_boot.secs = hdr.server_boot;
4903 server_boot.nsecs = 0;
4905 if (hdr.server_boot == 0)
4906 proto_tree_add_time_format (dcerpc_tree, hf_dcerpc_dg_server_boot,
4907 tvb, offset, 4, &server_boot,
4908 "Server boot time: Unknown (0)");
4910 proto_tree_add_time (dcerpc_tree, hf_dcerpc_dg_server_boot,
4911 tvb, offset, 4, &server_boot);
4916 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
4920 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
4921 if (check_col (pinfo->cinfo, COL_INFO)) {
4922 col_append_fstr (pinfo->cinfo, COL_INFO, ": seq: %u", hdr.seqnum);
4924 if (check_col (pinfo->cinfo, COL_DCE_CALL)) {
4925 col_append_fstr (pinfo->cinfo, COL_DCE_CALL, "%u", hdr.seqnum);
4930 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
4934 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
4938 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
4942 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
4946 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
4947 if (check_col (pinfo->cinfo, COL_INFO)) {
4948 if (hdr.flags1 & PFCL1_FRAG) {
4949 /* Fragmented - put the fragment number into the Info column */
4950 col_append_fstr (pinfo->cinfo, COL_INFO, " frag: %u",
4957 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
4961 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
4962 if (check_col (pinfo->cinfo, COL_INFO)) {
4963 if (hdr.flags1 & PFCL1_FRAG) {
4964 /* Fragmented - put the serial number into the Info column */
4965 col_append_fstr (pinfo->cinfo, COL_INFO, " serial: %u",
4966 (hdr.serial_hi << 8) | hdr.serial_lo);
4973 * XXX - for Kerberos, we get a protection level; if it's
4974 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
4977 dissect_dcerpc_dg_auth (tvb, offset, dcerpc_tree, &hdr,
4982 * keeping track of the conversation shouldn't really be necessary
4983 * for connectionless packets, because everything we need to know
4984 * to dissect is in the header for each packet. Unfortunately,
4985 * Microsoft's implementation is buggy and often puts the
4986 * completely wrong if_id in the header. go figure. So, keep
4987 * track of the seqnum and use that if possible. Note: that's not
4988 * completely correct. It should really be done based on both the
4989 * activity_id and seqnum. I haven't seen anywhere that it would
4990 * make a difference, but for future reference...
4992 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
4993 pinfo->srcport, pinfo->destport, 0);
4995 conv = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
4996 pinfo->srcport, pinfo->destport, 0);
5000 * Packet type specific stuff is next.
5003 switch (hdr.ptype) {
5005 case PDU_CANCEL_ACK:
5006 /* Body is optional */
5007 /* XXX - we assume "frag_len" is the length of the body */
5008 if (hdr.frag_len != 0)
5009 dissect_dcerpc_dg_cancel_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
5014 * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
5015 * but in at least one capture none of the Cl_cancel PDUs had a
5018 /* XXX - we assume "frag_len" is the length of the body */
5019 if (hdr.frag_len != 0)
5020 dissect_dcerpc_dg_cancel (tvb, offset, pinfo, dcerpc_tree, &hdr);
5024 /* Body is optional; if present, it's the same as PDU_FACK */
5025 /* XXX - we assume "frag_len" is the length of the body */
5026 if (hdr.frag_len != 0)
5027 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
5031 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
5036 dissect_dcerpc_dg_reject_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
5040 dissect_dcerpc_dg_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
5044 dissect_dcerpc_dg_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
5047 /* these requests have no body */
5050 dissect_dcerpc_dg_ping_ack (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
5061 dcerpc_init_protocol (void)
5063 /* structures and data for BIND */
5065 g_hash_table_destroy (dcerpc_binds);
5069 dcerpc_binds = g_hash_table_new (dcerpc_bind_hash, dcerpc_bind_equal);
5072 /* structures and data for CALL */
5073 if (dcerpc_cn_calls){
5074 g_hash_table_destroy (dcerpc_cn_calls);
5076 dcerpc_cn_calls = g_hash_table_new (dcerpc_cn_call_hash, dcerpc_cn_call_equal);
5077 if (dcerpc_dg_calls){
5078 g_hash_table_destroy (dcerpc_dg_calls);
5080 dcerpc_dg_calls = g_hash_table_new (dcerpc_dg_call_hash, dcerpc_dg_call_equal);
5082 /* structure and data for MATCHED */
5083 if (dcerpc_matched){
5084 g_hash_table_destroy (dcerpc_matched);
5086 dcerpc_matched = g_hash_table_new (dcerpc_matched_hash, dcerpc_matched_equal);
5088 /* call the registered hooks */
5089 g_hook_list_invoke(&dcerpc_hooks_init_protos, FALSE /* not may_recurse */);
5093 proto_register_dcerpc (void)
5095 static hf_register_info hf[] = {
5096 { &hf_dcerpc_request_in,
5097 { "Request in frame", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE,
5098 NULL, 0, "This packet is a response to the packet with this number", HFILL }},
5099 { &hf_dcerpc_response_in,
5100 { "Response in frame", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
5101 NULL, 0, "This packet will be responded in the packet with this number", HFILL }},
5102 { &hf_dcerpc_referent_id,
5103 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
5104 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
5106 { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5107 { &hf_dcerpc_ver_minor,
5108 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5109 { &hf_dcerpc_packet_type,
5110 { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS (pckt_vals), 0x0, "", HFILL }},
5111 { &hf_dcerpc_cn_flags,
5112 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
5113 { &hf_dcerpc_cn_flags_first_frag,
5114 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_FIRST_FRAG, "", HFILL }},
5115 { &hf_dcerpc_cn_flags_last_frag,
5116 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_LAST_FRAG, "", HFILL }},
5117 { &hf_dcerpc_cn_flags_cancel_pending,
5118 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_PENDING_CANCEL, "", HFILL }},
5119 { &hf_dcerpc_cn_flags_reserved,
5120 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_RESERVED_1, "", HFILL }},
5121 { &hf_dcerpc_cn_flags_mpx,
5122 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_CONC_MPX, "", HFILL }},
5123 { &hf_dcerpc_cn_flags_dne,
5124 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_DID_NOT_EXECUTE, "", HFILL }},
5125 { &hf_dcerpc_cn_flags_maybe,
5126 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_MAYBE, "", HFILL }},
5127 { &hf_dcerpc_cn_flags_object,
5128 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_OBJECT_UUID, "", HFILL }},
5130 { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
5131 { &hf_dcerpc_drep_byteorder,
5132 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS (drep_byteorder_vals), 0x0, "", HFILL }},
5133 { &hf_dcerpc_drep_character,
5134 { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS (drep_character_vals), 0x0, "", HFILL }},
5135 { &hf_dcerpc_drep_fp,
5136 { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS (drep_fp_vals), 0x0, "", HFILL }},
5137 { &hf_dcerpc_cn_frag_len,
5138 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5139 { &hf_dcerpc_cn_auth_len,
5140 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5141 { &hf_dcerpc_cn_call_id,
5142 { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5143 { &hf_dcerpc_cn_max_xmit,
5144 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5145 { &hf_dcerpc_cn_max_recv,
5146 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5147 { &hf_dcerpc_cn_assoc_group,
5148 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
5149 { &hf_dcerpc_cn_num_ctx_items,
5150 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5151 { &hf_dcerpc_cn_ctx_id,
5152 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5153 { &hf_dcerpc_cn_num_trans_items,
5154 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5155 { &hf_dcerpc_cn_bind_if_id,
5156 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
5157 { &hf_dcerpc_cn_bind_if_ver,
5158 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5159 { &hf_dcerpc_cn_bind_if_ver_minor,
5160 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5161 { &hf_dcerpc_cn_bind_trans_id,
5162 { "Transfer Syntax", "dcerpc.cn_bind_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
5163 { &hf_dcerpc_cn_bind_trans_ver,
5164 { "Syntax ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5165 { &hf_dcerpc_cn_alloc_hint,
5166 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5167 { &hf_dcerpc_cn_sec_addr_len,
5168 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5169 { &hf_dcerpc_cn_sec_addr,
5170 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, "", HFILL }},
5171 { &hf_dcerpc_cn_num_results,
5172 { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5173 { &hf_dcerpc_cn_ack_result,
5174 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, "", HFILL }},
5175 { &hf_dcerpc_cn_ack_reason,
5176 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, "", HFILL }},
5177 { &hf_dcerpc_cn_ack_trans_id,
5178 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
5179 { &hf_dcerpc_cn_ack_trans_ver,
5180 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5181 { &hf_dcerpc_cn_reject_reason,
5182 { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, "", HFILL }},
5183 { &hf_dcerpc_cn_num_protocols,
5184 { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5185 { &hf_dcerpc_cn_protocol_ver_major,
5186 { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5187 { &hf_dcerpc_cn_protocol_ver_minor,
5188 { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5189 { &hf_dcerpc_cn_cancel_count,
5190 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5191 { &hf_dcerpc_cn_status,
5192 { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
5193 { &hf_dcerpc_cn_deseg_req,
5194 { "Desegmentation Required", "dcerpc.cn_deseg_req", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5195 { &hf_dcerpc_auth_type,
5196 { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
5197 { &hf_dcerpc_auth_level,
5198 { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS (authn_level_vals), 0x0, "", HFILL }},
5199 { &hf_dcerpc_auth_pad_len,
5200 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5201 { &hf_dcerpc_auth_rsrvd,
5202 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5203 { &hf_dcerpc_auth_ctx_id,
5204 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5205 { &hf_dcerpc_dg_flags1,
5206 { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
5207 { &hf_dcerpc_dg_flags1_rsrvd_01,
5208 { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_01, "", HFILL }},
5209 { &hf_dcerpc_dg_flags1_last_frag,
5210 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_LASTFRAG, "", HFILL }},
5211 { &hf_dcerpc_dg_flags1_frag,
5212 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_FRAG, "", HFILL }},
5213 { &hf_dcerpc_dg_flags1_nofack,
5214 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_NOFACK, "", HFILL }},
5215 { &hf_dcerpc_dg_flags1_maybe,
5216 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_MAYBE, "", HFILL }},
5217 { &hf_dcerpc_dg_flags1_idempotent,
5218 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_IDEMPOTENT, "", HFILL }},
5219 { &hf_dcerpc_dg_flags1_broadcast,
5220 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_BROADCAST, "", HFILL }},
5221 { &hf_dcerpc_dg_flags1_rsrvd_80,
5222 { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_80, "", HFILL }},
5223 { &hf_dcerpc_dg_flags2,
5224 { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
5225 { &hf_dcerpc_dg_flags2_rsrvd_01,
5226 { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_01, "", HFILL }},
5227 { &hf_dcerpc_dg_flags2_cancel_pending,
5228 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_CANCEL_PENDING, "", HFILL }},
5229 { &hf_dcerpc_dg_flags2_rsrvd_04,
5230 { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_04, "", HFILL }},
5231 { &hf_dcerpc_dg_flags2_rsrvd_08,
5232 { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_08, "", HFILL }},
5233 { &hf_dcerpc_dg_flags2_rsrvd_10,
5234 { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_10, "", HFILL }},
5235 { &hf_dcerpc_dg_flags2_rsrvd_20,
5236 { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_20, "", HFILL }},
5237 { &hf_dcerpc_dg_flags2_rsrvd_40,
5238 { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_40, "", HFILL }},
5239 { &hf_dcerpc_dg_flags2_rsrvd_80,
5240 { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_80, "", HFILL }},
5241 { &hf_dcerpc_dg_serial_lo,
5242 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
5243 { &hf_dcerpc_dg_serial_hi,
5244 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
5245 { &hf_dcerpc_dg_ahint,
5246 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
5247 { &hf_dcerpc_dg_ihint,
5248 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
5249 { &hf_dcerpc_dg_frag_len,
5250 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5251 { &hf_dcerpc_dg_frag_num,
5252 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5253 { &hf_dcerpc_dg_auth_proto,
5254 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
5255 { &hf_dcerpc_dg_seqnum,
5256 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5257 { &hf_dcerpc_dg_server_boot,
5258 { "Server boot time", "dcerpc.dg_server_boot", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0, "", HFILL }},
5259 { &hf_dcerpc_dg_if_ver,
5260 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5261 { &hf_dcerpc_krb5_av_prot_level,
5262 { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, "", HFILL }},
5263 { &hf_dcerpc_krb5_av_key_vers_num,
5264 { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5265 { &hf_dcerpc_krb5_av_key_auth_verifier,
5266 { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
5267 { &hf_dcerpc_obj_id,
5268 { "Object", "dcerpc.obj_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
5269 { &hf_dcerpc_dg_if_id,
5270 { "Interface", "dcerpc.dg_if_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
5271 { &hf_dcerpc_dg_act_id,
5272 { "Activity", "dcerpc.dg_act_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
5274 { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5276 { &hf_dcerpc_dg_cancel_vers,
5277 { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5279 { &hf_dcerpc_dg_cancel_id,
5280 { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5282 { &hf_dcerpc_dg_server_accepting_cancels,
5283 { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
5285 { &hf_dcerpc_dg_fack_vers,
5286 { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5288 { &hf_dcerpc_dg_fack_window_size,
5289 { "Window Size", "dcerpc.fack_window_size", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5291 { &hf_dcerpc_dg_fack_max_tsdu,
5292 { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5294 { &hf_dcerpc_dg_fack_max_frag_size,
5295 { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5297 { &hf_dcerpc_dg_fack_serial_num,
5298 { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5300 { &hf_dcerpc_dg_fack_selack_len,
5301 { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5303 { &hf_dcerpc_dg_fack_selack,
5304 { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
5306 { &hf_dcerpc_dg_status,
5307 { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
5309 { &hf_dcerpc_array_max_count,
5310 { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
5312 { &hf_dcerpc_array_offset,
5313 { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
5315 { &hf_dcerpc_array_actual_count,
5316 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
5318 { &hf_dcerpc_array_buffer,
5319 { "Buffer", "dcerpc.array.buffer", FT_BYTES, BASE_NONE, NULL, 0x0, "Buffer: Buffer containing elements of the array", HFILL }},
5322 { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5324 { &hf_dcerpc_fragments,
5325 { "Reassembled DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
5326 NULL, 0x0, "DCE/RPC Fragments", HFILL }},
5328 { &hf_dcerpc_fragment,
5329 { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM, BASE_NONE,
5330 NULL, 0x0, "DCE/RPC Fragment", HFILL }},
5332 { &hf_dcerpc_fragment_overlap,
5333 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE,
5334 NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
5336 { &hf_dcerpc_fragment_overlap_conflict,
5337 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE,
5338 NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
5340 { &hf_dcerpc_fragment_multiple_tails,
5341 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE,
5342 NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
5344 { &hf_dcerpc_fragment_too_long_fragment,
5345 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE,
5346 NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
5348 { &hf_dcerpc_fragment_error,
5349 { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE,
5350 NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
5353 { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE,
5354 NULL, 0, "Time between Request and Response for DCE-RPC calls", HFILL }},
5356 { &hf_dcerpc_reassembled_in,
5357 { "Reassembled PDU in frame", "dcerpc.reassembled_in", FT_FRAMENUM, BASE_NONE,
5358 NULL, 0x0, "The DCE/RPC PDU is completely reassembled in the packet with this number", HFILL }},
5360 { &hf_dcerpc_unknown_if_id,
5361 { "Unknown DCERPC interface id", "dcerpc.unknown_if_id", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
5363 static gint *ett[] = {
5365 &ett_dcerpc_cn_flags,
5367 &ett_dcerpc_cn_iface,
5369 &ett_dcerpc_dg_flags1,
5370 &ett_dcerpc_dg_flags2,
5371 &ett_dcerpc_pointer_data,
5373 &ett_dcerpc_fragments,
5374 &ett_dcerpc_fragment,
5375 &ett_dcerpc_krb5_auth_verf,
5377 module_t *dcerpc_module;
5379 proto_dcerpc = proto_register_protocol ("DCE RPC", "DCERPC", "dcerpc");
5380 proto_register_field_array (proto_dcerpc, hf, array_length (hf));
5381 proto_register_subtree_array (ett, array_length (ett));
5382 register_init_routine (dcerpc_init_protocol);
5383 dcerpc_module = prefs_register_protocol (proto_dcerpc, NULL);
5384 prefs_register_bool_preference (dcerpc_module,
5386 "Reassemble DCE/RPC messages spanning multiple TCP segments",
5387 "Whether the DCE/RPC dissector should reassemble messages spanning multiple TCP segments."
5388 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
5389 &dcerpc_cn_desegment);
5390 prefs_register_bool_preference (dcerpc_module,
5391 "reassemble_dcerpc",
5392 "Reassemble DCE/RPC fragments",
5393 "Whether the DCE/RPC dissector should reassemble fragmented DCE/RPC PDUs",
5394 &dcerpc_reassemble);
5395 register_init_routine(dcerpc_reassemble_init);
5396 dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
5397 dcerpc_tap=register_tap("dcerpc");
5399 g_hook_list_init(&dcerpc_hooks_init_protos, sizeof(GHook));
5403 proto_reg_handoff_dcerpc (void)
5405 heur_dissector_add ("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
5406 heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
5407 heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
5408 heur_dissector_add ("smb_transact", dissect_dcerpc_cn_smbpipe, proto_dcerpc);
5409 heur_dissector_add ("http", dissect_dcerpc_cn_bs, proto_dcerpc);
5410 dcerpc_smb_init(proto_dcerpc);