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.
35 #include <epan/packet.h>
36 #include <epan/dissectors/packet-dcerpc.h>
37 #include <epan/conversation.h>
38 #include <epan/prefs.h>
39 #include "reassemble.h"
41 #include <epan/dissectors/packet-frame.h>
42 #include <epan/dissectors/packet-dcerpc-nt.h>
44 static int dcerpc_tap = -1;
47 static const value_string pckt_vals[] = {
48 { PDU_REQ, "Request"},
50 { PDU_RESP, "Response"},
51 { PDU_FAULT, "Fault"},
52 { PDU_WORKING, "Working"},
53 { PDU_NOCALL, "Nocall"},
54 { PDU_REJECT, "Reject"},
56 { PDU_CL_CANCEL, "Cl_cancel"},
58 { PDU_CANCEL_ACK, "Cancel_ack"},
60 { PDU_BIND_ACK, "Bind_ack"},
61 { PDU_BIND_NAK, "Bind_nak"},
62 { PDU_ALTER, "Alter_context"},
63 { PDU_ALTER_ACK, "Alter_context_resp"},
64 { PDU_AUTH3, "AUTH3"},
65 { PDU_SHUTDOWN, "Shutdown"},
66 { PDU_CO_CANCEL, "Co_cancel"},
67 { PDU_ORPHANED, "Orphaned"},
71 static const value_string drep_byteorder_vals[] = {
73 { 1, "Little-endian" },
77 static const value_string drep_character_vals[] = {
83 #define DCE_RPC_DREP_FP_IEEE 0
84 #define DCE_RPC_DREP_FP_VAX 1
85 #define DCE_RPC_DREP_FP_CRAY 2
86 #define DCE_RPC_DREP_FP_IBM 3
88 static const value_string drep_fp_vals[] = {
89 { DCE_RPC_DREP_FP_IEEE, "IEEE" },
90 { DCE_RPC_DREP_FP_VAX, "VAX" },
91 { DCE_RPC_DREP_FP_CRAY, "Cray" },
92 { DCE_RPC_DREP_FP_IBM, "IBM" },
97 * Authentication services.
99 static const value_string authn_protocol_vals[] = {
100 { DCE_C_RPC_AUTHN_PROTOCOL_NONE, "None" },
101 { DCE_C_RPC_AUTHN_PROTOCOL_KRB5, "Kerberos 5" },
102 { DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO, "SPNEGO" },
103 { DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP, "NTLMSSP" },
104 { DCE_C_RPC_AUTHN_PROTOCOL_GSS_SCHANNEL, "SCHANNEL SSP" },
105 { DCE_C_RPC_AUTHN_PROTOCOL_GSS_KERBEROS, "Kerberos SSP" },
106 { DCE_C_RPC_AUTHN_PROTOCOL_DPA,
107 "Distributed Password Authentication SSP"},
108 { DCE_C_RPC_AUTHN_PROTOCOL_MSN, "MSN SSP"},
109 { DCE_C_RPC_AUTHN_PROTOCOL_DIGEST, "Digest SSP"},
110 { DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN,"NETLOGON Secure Channel" },
111 { DCE_C_RPC_AUTHN_PROTOCOL_MQ, "MSMQ SSP"},
118 static const value_string authn_level_vals[] = {
119 { DCE_C_AUTHN_LEVEL_NONE, "None" },
120 { DCE_C_AUTHN_LEVEL_CONNECT, "Connect" },
121 { DCE_C_AUTHN_LEVEL_CALL, "Call" },
122 { DCE_C_AUTHN_LEVEL_PKT, "Packet" },
123 { DCE_C_AUTHN_LEVEL_PKT_INTEGRITY, "Packet integrity" },
124 { DCE_C_AUTHN_LEVEL_PKT_PRIVACY, "Packet privacy" },
129 * Flag bits in first flag field in connectionless PDU header.
131 #define PFCL1_RESERVED_01 0x01 /* Reserved for use by implementations */
132 #define PFCL1_LASTFRAG 0x02 /* If set, the PDU is the last
133 * fragment of a multi-PDU
135 #define PFCL1_FRAG 0x04 /* If set, the PDU is a fragment of
136 a multi-PDU transmission */
137 #define PFCL1_NOFACK 0x08 /* If set, the receiver is not
138 * requested to send a `fack' PDU
139 * for the fragment */
140 #define PFCL1_MAYBE 0x10 /* If set, the PDU is for a `maybe'
142 #define PFCL1_IDEMPOTENT 0x20 /* If set, the PDU is for an idempotent
144 #define PFCL1_BROADCAST 0x40 /* If set, the PDU is for a broadcast
146 #define PFCL1_RESERVED_80 0x80 /* Reserved for use by implementations */
149 * Flag bits in second flag field in connectionless PDU header.
151 #define PFCL2_RESERVED_01 0x01 /* Reserved for use by implementations */
152 #define PFCL2_CANCEL_PENDING 0x02 /* Cancel pending at the call end */
153 #define PFCL2_RESERVED_04 0x04 /* Reserved for future use */
154 #define PFCL2_RESERVED_08 0x08 /* Reserved for future use */
155 #define PFCL2_RESERVED_10 0x10 /* Reserved for future use */
156 #define PFCL2_RESERVED_20 0x20 /* Reserved for future use */
157 #define PFCL2_RESERVED_40 0x40 /* Reserved for future use */
158 #define PFCL2_RESERVED_80 0x80 /* Reserved for future use */
161 * Flag bits in connection-oriented PDU header.
163 #define PFC_FIRST_FRAG 0x01 /* First fragment */
164 #define PFC_LAST_FRAG 0x02 /* Last fragment */
165 #define PFC_PENDING_CANCEL 0x04 /* Cancel was pending at sender */
166 #define PFC_RESERVED_1 0x08
167 #define PFC_CONC_MPX 0x10 /* suports concurrent multiplexing
168 * of a single connection. */
169 #define PFC_DID_NOT_EXECUTE 0x20 /* only meaningful on `fault' packet;
170 * if true, guaranteed call did not
172 #define PFC_MAYBE 0x40 /* `maybe' call semantics requested */
173 #define PFC_OBJECT_UUID 0x80 /* if true, a non-nil object UUID
174 * was specified in the handle, and
175 * is present in the optional object
176 * field. If false, the object field
180 * Tests whether a connection-oriented PDU is fragmented; returns TRUE if
181 * it's not fragmented (i.e., this is both the first *and* last fragment),
182 * and FALSE otherwise.
184 #define PFC_NOT_FRAGMENTED(hdr) \
185 ((hdr->flags&(PFC_FIRST_FRAG|PFC_LAST_FRAG))==(PFC_FIRST_FRAG|PFC_LAST_FRAG))
188 * Presentation context negotiation result.
190 static const value_string p_cont_result_vals[] = {
192 { 1, "User rejection" },
193 { 2, "Provider rejection" },
198 * Presentation context negotiation rejection reasons.
200 static const value_string p_provider_reason_vals[] = {
201 { 0, "Reason not specified" },
202 { 1, "Abstract syntax not supported" },
203 { 2, "Proposed transfer syntaxes not supported" },
204 { 3, "Local limit exceeded" },
211 #define REASON_NOT_SPECIFIED 0
212 #define TEMPORARY_CONGESTION 1
213 #define LOCAL_LIMIT_EXCEEDED 2
214 #define CALLED_PADDR_UNKNOWN 3 /* not used */
215 #define PROTOCOL_VERSION_NOT_SUPPORTED 4
216 #define DEFAULT_CONTEXT_NOT_SUPPORTED 5 /* not used */
217 #define USER_DATA_NOT_READABLE 6 /* not used */
218 #define NO_PSAP_AVAILABLE 7 /* not used */
220 static const value_string reject_reason_vals[] = {
221 { REASON_NOT_SPECIFIED, "Reason not specified" },
222 { TEMPORARY_CONGESTION, "Temporary congestion" },
223 { LOCAL_LIMIT_EXCEEDED, "Local limit exceeded" },
224 { CALLED_PADDR_UNKNOWN, "Called paddr unknown" },
225 { PROTOCOL_VERSION_NOT_SUPPORTED, "Protocol version not supported" },
226 { DEFAULT_CONTEXT_NOT_SUPPORTED, "Default context not supported" },
227 { USER_DATA_NOT_READABLE, "User data not readable" },
228 { NO_PSAP_AVAILABLE, "No PSAP available" },
233 * Reject status codes.
235 static const value_string reject_status_vals[] = {
236 { 0, "Stub-defined exception" },
237 { 0x00000005, "logon failure" },
238 { 0x1c000001, "nca_s_fault_int_div_by_zero" },
239 { 0x1c000002, "nca_s_fault_addr_error" },
240 { 0x1c000003, "nca_s_fault_fp_div_zero" },
241 { 0x1c000004, "nca_s_fault_fp_underflow" },
242 { 0x1c000005, "nca_s_fault_fp_overflow" },
243 { 0x1c000006, "nca_s_fault_invalid_tag" },
244 { 0x1c000007, "nca_s_fault_invalid_bound" },
245 { 0x1c000008, "nca_rpc_version_mismatch" },
246 { 0x1c000009, "nca_unspec_reject" },
247 { 0x1c00000a, "nca_s_bad_actid" },
248 { 0x1c00000b, "nca_who_are_you_failed" },
249 { 0x1c00000c, "nca_manager_not_entered" },
250 { 0x1c00000d, "nca_s_fault_cancel" },
251 { 0x1c00000e, "nca_s_fault_ill_inst" },
252 { 0x1c00000f, "nca_s_fault_fp_error" },
253 { 0x1c000010, "nca_s_fault_int_overflow" },
254 { 0x1c000014, "nca_s_fault_pipe_empty" },
255 { 0x1c000015, "nca_s_fault_pipe_closed" },
256 { 0x1c000016, "nca_s_fault_pipe_order" },
257 { 0x1c000017, "nca_s_fault_pipe_discipline" },
258 { 0x1c000018, "nca_s_fault_pipe_comm_error" },
259 { 0x1c000019, "nca_s_fault_pipe_memory" },
260 { 0x1c00001a, "nca_s_fault_context_mismatch" },
261 { 0x1c00001b, "nca_s_fault_remote_no_memory" },
262 { 0x1c00001c, "nca_invalid_pres_context_id" },
263 { 0x1c00001d, "nca_unsupported_authn_level" },
264 { 0x1c00001f, "nca_invalid_checksum" },
265 { 0x1c000020, "nca_invalid_crc" },
266 { 0x1c000021, "ncs_s_fault_user_defined" },
267 { 0x1c000022, "nca_s_fault_tx_open_failed" },
268 { 0x1c000023, "nca_s_fault_codeset_conv_error" },
269 { 0x1c000024, "nca_s_fault_object_not_found" },
270 { 0x1c000025, "nca_s_fault_no_client_stub" },
271 { 0x1c010002, "nca_op_rng_error" },
272 { 0x1c010003, "nca_unk_if"},
273 { 0x1c010006, "nca_wrong_boot_time" },
274 { 0x1c010009, "nca_s_you_crashed" },
275 { 0x1c01000b, "nca_proto_error" },
276 { 0x1c010013, "nca_out_args_too_big" },
277 { 0x1c010014, "nca_server_too_busy" },
278 { 0x1c010017, "nca_unsupported_type" },
283 /* we need to keep track of what transport were used, ie what handle we came
284 * in through so we know what kind of pinfo->private_data was passed to us.
286 /* Value of -1 is reserved for "not DCE packet" in packet_info.dcetransporttype. */
287 #define DCE_TRANSPORT_UNKNOWN 0
288 #define DCE_CN_TRANSPORT_SMBPIPE 1
291 static int proto_dcerpc = -1;
294 static int hf_dcerpc_request_in = -1;
295 static int hf_dcerpc_time = -1;
296 static int hf_dcerpc_response_in = -1;
297 static int hf_dcerpc_ver = -1;
298 static int hf_dcerpc_ver_minor = -1;
299 static int hf_dcerpc_packet_type = -1;
300 static int hf_dcerpc_cn_flags = -1;
301 static int hf_dcerpc_cn_flags_first_frag = -1;
302 static int hf_dcerpc_cn_flags_last_frag = -1;
303 static int hf_dcerpc_cn_flags_cancel_pending = -1;
304 static int hf_dcerpc_cn_flags_reserved = -1;
305 static int hf_dcerpc_cn_flags_mpx = -1;
306 static int hf_dcerpc_cn_flags_dne = -1;
307 static int hf_dcerpc_cn_flags_maybe = -1;
308 static int hf_dcerpc_cn_flags_object = -1;
309 static int hf_dcerpc_drep = -1;
310 static int hf_dcerpc_drep_byteorder = -1;
311 static int hf_dcerpc_drep_character = -1;
312 static int hf_dcerpc_drep_fp = -1;
313 static int hf_dcerpc_cn_frag_len = -1;
314 static int hf_dcerpc_cn_auth_len = -1;
315 static int hf_dcerpc_cn_call_id = -1;
316 static int hf_dcerpc_cn_max_xmit = -1;
317 static int hf_dcerpc_cn_max_recv = -1;
318 static int hf_dcerpc_cn_assoc_group = -1;
319 static int hf_dcerpc_cn_num_ctx_items = -1;
320 static int hf_dcerpc_cn_ctx_id = -1;
321 static int hf_dcerpc_cn_num_trans_items = -1;
322 static int hf_dcerpc_cn_bind_if_id = -1;
323 static int hf_dcerpc_cn_bind_if_ver = -1;
324 static int hf_dcerpc_cn_bind_if_ver_minor = -1;
325 static int hf_dcerpc_cn_bind_trans_id = -1;
326 static int hf_dcerpc_cn_bind_trans_ver = -1;
327 static int hf_dcerpc_cn_alloc_hint = -1;
328 static int hf_dcerpc_cn_sec_addr_len = -1;
329 static int hf_dcerpc_cn_sec_addr = -1;
330 static int hf_dcerpc_cn_num_results = -1;
331 static int hf_dcerpc_cn_ack_result = -1;
332 static int hf_dcerpc_cn_ack_reason = -1;
333 static int hf_dcerpc_cn_ack_trans_id = -1;
334 static int hf_dcerpc_cn_ack_trans_ver = -1;
335 static int hf_dcerpc_cn_reject_reason = -1;
336 static int hf_dcerpc_cn_num_protocols = -1;
337 static int hf_dcerpc_cn_protocol_ver_major = -1;
338 static int hf_dcerpc_cn_protocol_ver_minor = -1;
339 static int hf_dcerpc_cn_cancel_count = -1;
340 static int hf_dcerpc_cn_status = -1;
341 static int hf_dcerpc_auth_type = -1;
342 static int hf_dcerpc_auth_level = -1;
343 static int hf_dcerpc_auth_pad_len = -1;
344 static int hf_dcerpc_auth_rsrvd = -1;
345 static int hf_dcerpc_auth_ctx_id = -1;
346 static int hf_dcerpc_dg_flags1 = -1;
347 static int hf_dcerpc_dg_flags1_rsrvd_01 = -1;
348 static int hf_dcerpc_dg_flags1_last_frag = -1;
349 static int hf_dcerpc_dg_flags1_frag = -1;
350 static int hf_dcerpc_dg_flags1_nofack = -1;
351 static int hf_dcerpc_dg_flags1_maybe = -1;
352 static int hf_dcerpc_dg_flags1_idempotent = -1;
353 static int hf_dcerpc_dg_flags1_broadcast = -1;
354 static int hf_dcerpc_dg_flags1_rsrvd_80 = -1;
355 static int hf_dcerpc_dg_flags2 = -1;
356 static int hf_dcerpc_dg_flags2_rsrvd_01 = -1;
357 static int hf_dcerpc_dg_flags2_cancel_pending = -1;
358 static int hf_dcerpc_dg_flags2_rsrvd_04 = -1;
359 static int hf_dcerpc_dg_flags2_rsrvd_08 = -1;
360 static int hf_dcerpc_dg_flags2_rsrvd_10 = -1;
361 static int hf_dcerpc_dg_flags2_rsrvd_20 = -1;
362 static int hf_dcerpc_dg_flags2_rsrvd_40 = -1;
363 static int hf_dcerpc_dg_flags2_rsrvd_80 = -1;
364 static int hf_dcerpc_dg_serial_hi = -1;
365 static int hf_dcerpc_obj_id = -1;
366 static int hf_dcerpc_dg_if_id = -1;
367 static int hf_dcerpc_dg_act_id = -1;
368 static int hf_dcerpc_dg_serial_lo = -1;
369 static int hf_dcerpc_dg_ahint = -1;
370 static int hf_dcerpc_dg_ihint = -1;
371 static int hf_dcerpc_dg_frag_len = -1;
372 static int hf_dcerpc_dg_frag_num = -1;
373 static int hf_dcerpc_dg_auth_proto = -1;
374 static int hf_dcerpc_opnum = -1;
375 static int hf_dcerpc_dg_seqnum = -1;
376 static int hf_dcerpc_dg_server_boot = -1;
377 static int hf_dcerpc_dg_if_ver = -1;
378 static int hf_dcerpc_krb5_av_prot_level = -1;
379 static int hf_dcerpc_krb5_av_key_vers_num = -1;
380 static int hf_dcerpc_krb5_av_key_auth_verifier = -1;
381 static int hf_dcerpc_dg_cancel_vers = -1;
382 static int hf_dcerpc_dg_cancel_id = -1;
383 static int hf_dcerpc_dg_server_accepting_cancels = -1;
384 static int hf_dcerpc_dg_fack_vers = -1;
385 static int hf_dcerpc_dg_fack_window_size = -1;
386 static int hf_dcerpc_dg_fack_max_tsdu = -1;
387 static int hf_dcerpc_dg_fack_max_frag_size = -1;
388 static int hf_dcerpc_dg_fack_serial_num = -1;
389 static int hf_dcerpc_dg_fack_selack_len = -1;
390 static int hf_dcerpc_dg_fack_selack = -1;
391 static int hf_dcerpc_dg_status = -1;
392 static int hf_dcerpc_array_max_count = -1;
393 static int hf_dcerpc_array_offset = -1;
394 static int hf_dcerpc_array_actual_count = -1;
395 static int hf_dcerpc_array_buffer = -1;
396 static int hf_dcerpc_op = -1;
397 static int hf_dcerpc_referent_id = -1;
398 static int hf_dcerpc_fragments = -1;
399 static int hf_dcerpc_fragment = -1;
400 static int hf_dcerpc_fragment_overlap = -1;
401 static int hf_dcerpc_fragment_overlap_conflict = -1;
402 static int hf_dcerpc_fragment_multiple_tails = -1;
403 static int hf_dcerpc_fragment_too_long_fragment = -1;
404 static int hf_dcerpc_fragment_error = -1;
405 static int hf_dcerpc_reassembled_in = -1;
406 static int hf_dcerpc_unknown_if_id = -1;
408 static gint ett_dcerpc = -1;
409 static gint ett_dcerpc_cn_flags = -1;
410 static gint ett_dcerpc_cn_ctx = -1;
411 static gint ett_dcerpc_cn_iface = -1;
412 static gint ett_dcerpc_drep = -1;
413 static gint ett_dcerpc_dg_flags1 = -1;
414 static gint ett_dcerpc_dg_flags2 = -1;
415 static gint ett_dcerpc_pointer_data = -1;
416 static gint ett_dcerpc_string = -1;
417 static gint ett_dcerpc_fragments = -1;
418 static gint ett_dcerpc_fragment = -1;
419 static gint ett_dcerpc_krb5_auth_verf = -1;
421 static const fragment_items dcerpc_frag_items = {
422 &ett_dcerpc_fragments,
423 &ett_dcerpc_fragment,
425 &hf_dcerpc_fragments,
427 &hf_dcerpc_fragment_overlap,
428 &hf_dcerpc_fragment_overlap_conflict,
429 &hf_dcerpc_fragment_multiple_tails,
430 &hf_dcerpc_fragment_too_long_fragment,
431 &hf_dcerpc_fragment_error,
437 /* list of hooks to be called when init_protocols is done */
438 GHookList dcerpc_hooks_init_protos;
441 int ResolveWin32UUID(e_uuid_t if_id, char *UUID_NAME, int UUID_NAME_MAX_LEN)
443 char REG_UUID_NAME[MAX_PATH];
445 DWORD UUID_MAX_SIZE = MAX_PATH;
446 char REG_UUID_STR[MAX_PATH];
448 if(UUID_NAME_MAX_LEN < 2)
450 REG_UUID_NAME[0] = '\0';
451 snprintf(REG_UUID_STR, MAX_PATH, "SOFTWARE\\Classes\\Interface\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
452 if_id.Data1, if_id.Data2, if_id.Data3,
453 if_id.Data4[0], if_id.Data4[1],
454 if_id.Data4[2], if_id.Data4[3],
455 if_id.Data4[4], if_id.Data4[5],
456 if_id.Data4[6], if_id.Data4[7]);
457 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCSTR)REG_UUID_STR, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
459 if (RegQueryValueEx(hKey, NULL, NULL, NULL, (LPBYTE)REG_UUID_NAME, &UUID_MAX_SIZE) == ERROR_SUCCESS && UUID_MAX_SIZE <= MAX_PATH)
461 snprintf(UUID_NAME, UUID_NAME_MAX_LEN, "%s", REG_UUID_NAME);
463 return strlen(REG_UUID_NAME);
467 return 0; /* we didn't find anything anyhow. Please don't use the string! */
475 static dcerpc_info di[20];
476 static int di_counter=0;
482 return &di[di_counter];
485 /* try to desegment big DCE/RPC packets over TCP? */
486 static gboolean dcerpc_cn_desegment = TRUE;
488 /* reassemble DCE/RPC fragments */
489 /* reassembly of dcerpc fragments will not work for the case where ONE frame
490 might contain multiple dcerpc fragments for different PDUs.
491 this case would be so unusual/weird so if you got captures like that:
494 static gboolean dcerpc_reassemble = FALSE;
495 static GHashTable *dcerpc_co_reassemble_table = NULL;
496 static GHashTable *dcerpc_cl_reassemble_table = NULL;
499 dcerpc_reassemble_init(void)
501 fragment_table_init(&dcerpc_co_reassemble_table);
502 dcerpc_fragment_table_init(&dcerpc_cl_reassemble_table);
506 * Authentication subdissectors. Used to dissect authentication blobs in
507 * DCERPC binds, requests and responses.
510 typedef struct _dcerpc_auth_subdissector {
513 dcerpc_auth_subdissector_fns auth_fns;
514 } dcerpc_auth_subdissector;
516 static GSList *dcerpc_auth_subdissector_list;
518 static dcerpc_auth_subdissector_fns *get_auth_subdissector_fns(
519 guint8 auth_level, guint8 auth_type)
524 for (i = 0; (data = g_slist_nth_data(dcerpc_auth_subdissector_list, i)); i++) {
525 dcerpc_auth_subdissector *asd = (dcerpc_auth_subdissector *)data;
527 if (asd->auth_level == auth_level &&
528 asd->auth_type == auth_type)
529 return &asd->auth_fns;
535 void register_dcerpc_auth_subdissector(guint8 auth_level, guint8 auth_type,
536 dcerpc_auth_subdissector_fns *fns)
538 dcerpc_auth_subdissector *d;
540 if (get_auth_subdissector_fns(auth_level, auth_type))
543 d = (dcerpc_auth_subdissector *)g_malloc(sizeof(dcerpc_auth_subdissector));
545 d->auth_level = auth_level;
546 d->auth_type = auth_type;
547 memcpy(&d->auth_fns, fns, sizeof(dcerpc_auth_subdissector_fns));
549 dcerpc_auth_subdissector_list = g_slist_append(dcerpc_auth_subdissector_list, d);
552 /* Hand off verifier data to a registered dissector */
554 static void dissect_auth_verf(tvbuff_t *auth_tvb, packet_info *pinfo,
556 dcerpc_auth_subdissector_fns *auth_fns,
557 e_dce_cn_common_hdr_t *hdr,
558 dcerpc_auth_info *auth_info)
560 dcerpc_dissect_fnct_t *volatile fn = NULL;
562 switch (hdr->ptype) {
565 fn = auth_fns->bind_fn;
569 fn = auth_fns->bind_ack_fn;
572 fn = auth_fns->auth3_fn;
575 fn = auth_fns->req_verf_fn;
578 fn = auth_fns->resp_verf_fn;
581 /* Don't know how to handle authentication data in this
585 g_warning("attempt to dissect %s pdu authentication data",
586 val_to_str(hdr->ptype, pckt_vals, "Unknown (%u)"));
591 fn(auth_tvb, 0, pinfo, tree, hdr->drep);
593 proto_tree_add_text(tree, auth_tvb, 0, hdr->auth_len,
595 val_to_str(auth_info->auth_type,
600 /* Hand off payload data to a registered dissector */
602 static tvbuff_t *decode_encrypted_data(tvbuff_t *enc_tvb,
604 dcerpc_auth_subdissector_fns *auth_fns,
606 dcerpc_auth_info *auth_info)
608 dcerpc_decode_data_fnct_t *fn;
611 fn = auth_fns->req_data_fn;
613 fn = auth_fns->resp_data_fn;
616 return fn(enc_tvb, 0, pinfo, auth_info);
625 /* the registered subdissectors */
626 GHashTable *dcerpc_uuids=NULL;
629 dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2)
631 const dcerpc_uuid_key *key1 = (const dcerpc_uuid_key *)k1;
632 const dcerpc_uuid_key *key2 = (const dcerpc_uuid_key *)k2;
633 return ((memcmp (&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
634 && (key1->ver == key2->ver));
638 dcerpc_uuid_hash (gconstpointer k)
640 const dcerpc_uuid_key *key = (const dcerpc_uuid_key *)k;
641 /* This isn't perfect, but the Data1 part of these is almost always
643 return key->uuid.Data1;
647 dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver,
648 dcerpc_sub_dissector *procs, int opnum_hf)
650 dcerpc_uuid_key *key = g_malloc (sizeof (*key));
651 dcerpc_uuid_value *value = g_malloc (sizeof (*value));
652 header_field_info *hf_info;
657 value->proto = find_protocol_by_id(proto);
658 value->proto_id = proto;
660 value->name = proto_get_protocol_short_name (value->proto);
661 value->procs = procs;
662 value->opnum_hf = opnum_hf;
664 g_hash_table_insert (dcerpc_uuids, key, value);
666 hf_info = proto_registrar_get_nth(opnum_hf);
667 hf_info->strings = value_string_from_subdissectors(procs);
671 /* try to get registered name for this uuid */
672 gchar *dcerpc_get_uuid_name(e_uuid_t *uuid, guint16 ver)
675 dcerpc_uuid_value *sub_proto;
678 /* try to get registered uuid "name" of if_id */
682 if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) != NULL
683 && proto_is_protocol_enabled(sub_proto->proto)) {
685 return sub_proto->name;
692 /* Function to find the name of a registered protocol
693 * or NULL if the protocol/version is not known to ethereal.
696 dcerpc_get_proto_name(e_uuid_t *uuid, guint16 ver)
699 dcerpc_uuid_value *sub_proto;
703 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
706 return sub_proto->name;
709 /* Function to find the opnum hf-field of a registered protocol
710 * or -1 if the protocol/version is not known to ethereal.
713 dcerpc_get_proto_hf_opnum(e_uuid_t *uuid, guint16 ver)
716 dcerpc_uuid_value *sub_proto;
720 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
723 return sub_proto->opnum_hf;
726 /* Create a value_string consisting of DCERPC opnum and name from a
727 subdissector array. */
729 value_string *value_string_from_subdissectors(dcerpc_sub_dissector *sd)
731 value_string *vs = NULL;
735 for (i = 0; sd[i].name; i++) {
737 vs[i].value = sd[i].num;
738 vs[i].strptr = sd[i].name;
744 vs = g_malloc((num_sd + 1) * sizeof(value_string));
748 vs[num_sd].value = 0;
749 vs[num_sd].strptr = NULL;
754 /* Function to find the subdissector table of a registered protocol
755 * or NULL if the protocol/version is not known to ethereal.
757 dcerpc_sub_dissector *
758 dcerpc_get_proto_sub_dissector(e_uuid_t *uuid, guint16 ver)
761 dcerpc_uuid_value *sub_proto;
765 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
768 return sub_proto->procs;
773 * To keep track of ctx_id mappings.
775 * Everytime we see a bind call we update this table.
776 * Note that we always specify a SMB FID. For non-SMB transports this
779 static GHashTable *dcerpc_binds=NULL;
781 typedef struct _dcerpc_bind_key {
782 conversation_t *conv;
787 typedef struct _dcerpc_bind_value {
792 static GMemChunk *dcerpc_bind_key_chunk=NULL;
793 static GMemChunk *dcerpc_bind_value_chunk=NULL;
796 dcerpc_bind_equal (gconstpointer k1, gconstpointer k2)
798 const dcerpc_bind_key *key1 = (const dcerpc_bind_key *)k1;
799 const dcerpc_bind_key *key2 = (const dcerpc_bind_key *)k2;
800 return (key1->conv == key2->conv
801 && key1->ctx_id == key2->ctx_id
802 && key1->smb_fid == key2->smb_fid);
806 dcerpc_bind_hash (gconstpointer k)
808 const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
809 return GPOINTER_TO_UINT(key->conv) + key->ctx_id + key->smb_fid;
814 * To keep track of callid mappings. Should really use some generic
815 * conversation support instead.
817 static GHashTable *dcerpc_cn_calls=NULL;
818 static GHashTable *dcerpc_dg_calls=NULL;
820 typedef struct _dcerpc_cn_call_key {
821 conversation_t *conv;
824 } dcerpc_cn_call_key;
826 typedef struct _dcerpc_dg_call_key {
827 conversation_t *conv;
830 } dcerpc_dg_call_key;
832 static GMemChunk *dcerpc_cn_call_key_chunk=NULL;
834 static GMemChunk *dcerpc_dg_call_key_chunk=NULL;
836 static GMemChunk *dcerpc_call_value_chunk=NULL;
840 dcerpc_cn_call_equal (gconstpointer k1, gconstpointer k2)
842 const dcerpc_cn_call_key *key1 = (const dcerpc_cn_call_key *)k1;
843 const dcerpc_cn_call_key *key2 = (const dcerpc_cn_call_key *)k2;
844 return (key1->conv == key2->conv
845 && key1->call_id == key2->call_id
846 && key1->smb_fid == key2->smb_fid);
850 dcerpc_dg_call_equal (gconstpointer k1, gconstpointer k2)
852 const dcerpc_dg_call_key *key1 = (const dcerpc_dg_call_key *)k1;
853 const dcerpc_dg_call_key *key2 = (const dcerpc_dg_call_key *)k2;
854 return (key1->conv == key2->conv
855 && key1->seqnum == key2->seqnum
856 && (memcmp (&key1->act_id, &key2->act_id, sizeof (e_uuid_t)) == 0));
860 dcerpc_cn_call_hash (gconstpointer k)
862 const dcerpc_cn_call_key *key = (const dcerpc_cn_call_key *)k;
863 return GPOINTER_TO_UINT(key->conv) + key->call_id + key->smb_fid;
867 dcerpc_dg_call_hash (gconstpointer k)
869 const dcerpc_dg_call_key *key = (const dcerpc_dg_call_key *)k;
870 return (GPOINTER_TO_UINT(key->conv) + key->seqnum + key->act_id.Data1
871 + (key->act_id.Data2 << 16) + key->act_id.Data3
872 + (key->act_id.Data4[0] << 24) + (key->act_id.Data4[1] << 16)
873 + (key->act_id.Data4[2] << 8) + (key->act_id.Data4[3] << 0)
874 + (key->act_id.Data4[4] << 24) + (key->act_id.Data4[5] << 16)
875 + (key->act_id.Data4[6] << 8) + (key->act_id.Data4[7] << 0));
878 /* to keep track of matched calls/responses
879 this one uses the same value struct as calls, but the key is the frame id
880 and call id; there can be more than one call in a frame.
882 XXX - why not just use the same keys as are used for calls?
885 static GHashTable *dcerpc_matched=NULL;
887 typedef struct _dcerpc_matched_key {
890 } dcerpc_matched_key;
892 static GMemChunk *dcerpc_matched_key_chunk=NULL;
895 dcerpc_matched_equal (gconstpointer k1, gconstpointer k2)
897 const dcerpc_matched_key *key1 = (const dcerpc_matched_key *)k1;
898 const dcerpc_matched_key *key2 = (const dcerpc_matched_key *)k2;
899 return (key1->frame == key2->frame
900 && key1->call_id == key2->call_id);
904 dcerpc_matched_hash (gconstpointer k)
906 const dcerpc_matched_key *key = (const dcerpc_matched_key *)k;
913 * Utility functions. Modeled after packet-rpc.c
917 dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
918 proto_tree *tree, guint8 *drep,
919 int hfindex, guint8 *pdata)
923 data = tvb_get_guint8 (tvb, offset);
925 proto_tree_add_item (tree, hfindex, tvb, offset, 1, (drep[0] & 0x10));
933 dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
934 proto_tree *tree, guint8 *drep,
935 int hfindex, guint16 *pdata)
939 data = ((drep[0] & 0x10)
940 ? tvb_get_letohs (tvb, offset)
941 : tvb_get_ntohs (tvb, offset));
944 proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10));
952 dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
953 proto_tree *tree, guint8 *drep,
954 int hfindex, guint32 *pdata)
958 data = ((drep[0] & 0x10)
959 ? tvb_get_letohl (tvb, offset)
960 : tvb_get_ntohl (tvb, offset));
963 proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10));
970 /* handles 32 bit unix time_t */
972 dissect_dcerpc_time_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
973 proto_tree *tree, guint8 *drep,
974 int hfindex, guint32 *pdata)
979 data = ((drep[0] & 0x10)
980 ? tvb_get_letohl (tvb, offset)
981 : tvb_get_ntohl (tvb, offset));
986 if(data==0xffffffff){
987 /* special case, no time specified */
988 proto_tree_add_time_format(tree, hfindex, tvb, offset, 4, &tv, "%s: No time specified", proto_registrar_get_nth(hfindex)->name);
990 proto_tree_add_time (tree, hfindex, tvb, offset, 4, &tv);
1000 dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1001 proto_tree *tree, guint8 *drep,
1002 int hfindex, unsigned char *pdata)
1005 tvb_memcpy(tvb, pdata, offset, 8);
1006 if(drep[0] & 0x10){/* XXX this might be the wrong way around */
1008 data=pdata[0];pdata[0]=pdata[7];pdata[7]=data;
1009 data=pdata[1];pdata[1]=pdata[6];pdata[6]=data;
1010 data=pdata[2];pdata[2]=pdata[5];pdata[5]=data;
1011 data=pdata[3];pdata[3]=pdata[4];pdata[4]=data;
1016 proto_tree_add_item(tree, hfindex, tvb, offset, 8, (drep[0] & 0x10));
1024 dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1025 proto_tree *tree, guint8 *drep,
1026 int hfindex, gfloat *pdata)
1032 case(DCE_RPC_DREP_FP_IEEE):
1033 data = ((drep[0] & 0x10)
1034 ? tvb_get_letohieee_float(tvb, offset)
1035 : tvb_get_ntohieee_float(tvb, offset));
1037 proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
1040 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
1041 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1042 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
1044 /* ToBeDone: non IEEE floating formats */
1045 /* Set data to a negative infinity value */
1048 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep[1]);
1058 dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1059 proto_tree *tree, guint8 *drep,
1060 int hfindex, gdouble *pdata)
1066 case(DCE_RPC_DREP_FP_IEEE):
1067 data = ((drep[0] & 0x10)
1068 ? tvb_get_letohieee_double(tvb, offset)
1069 : tvb_get_ntohieee_double(tvb, offset));
1071 proto_tree_add_double(tree, hfindex, tvb, offset, 8, 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 double formats */
1079 /* Set data to a negative infinity value */
1080 data = -G_MAXDOUBLE;
1082 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep[1]);
1092 * a couple simpler things
1095 dcerpc_tvb_get_ntohs (tvbuff_t *tvb, gint offset, guint8 *drep)
1097 if (drep[0] & 0x10) {
1098 return tvb_get_letohs (tvb, offset);
1100 return tvb_get_ntohs (tvb, offset);
1105 dcerpc_tvb_get_ntohl (tvbuff_t *tvb, gint offset, guint8 *drep)
1107 if (drep[0] & 0x10) {
1108 return tvb_get_letohl (tvb, offset);
1110 return tvb_get_ntohl (tvb, offset);
1115 dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, guint8 *drep, e_uuid_t *uuid)
1118 uuid->Data1 = dcerpc_tvb_get_ntohl (tvb, offset, drep);
1119 uuid->Data2 = dcerpc_tvb_get_ntohs (tvb, offset+4, drep);
1120 uuid->Data3 = dcerpc_tvb_get_ntohs (tvb, offset+6, drep);
1122 for (i=0; i<sizeof (uuid->Data4); i++) {
1123 uuid->Data4[i] = tvb_get_guint8 (tvb, offset+8+i);
1130 /* function to dissect a unidimensional conformant array */
1132 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1133 proto_tree *tree, guint8 *drep,
1134 dcerpc_dissect_fnct_t *fnct)
1140 di=pinfo->private_data;
1141 if(di->conformant_run){
1142 /* conformant run, just dissect the max_count header */
1144 di->conformant_run=0;
1145 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1146 hf_dcerpc_array_max_count, &di->array_max_count);
1147 di->array_max_count_offset=offset-4;
1148 di->conformant_run=1;
1149 di->conformant_eaten=offset-old_offset;
1151 /* we don't remember where in the bytestream this field was */
1152 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1154 /* real run, dissect the elements */
1155 for(i=0;i<di->array_max_count;i++){
1156 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1162 /* function to dissect a unidimensional conformant and varying array */
1164 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1165 proto_tree *tree, guint8 *drep,
1166 dcerpc_dissect_fnct_t *fnct)
1172 di=pinfo->private_data;
1173 if(di->conformant_run){
1174 /* conformant run, just dissect the max_count header */
1176 di->conformant_run=0;
1177 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1178 hf_dcerpc_array_max_count, &di->array_max_count);
1179 di->array_max_count_offset=offset-4;
1180 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1181 hf_dcerpc_array_offset, &di->array_offset);
1182 di->array_offset_offset=offset-4;
1183 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1184 hf_dcerpc_array_actual_count, &di->array_actual_count);
1185 di->array_actual_count_offset=offset-4;
1186 di->conformant_run=1;
1187 di->conformant_eaten=offset-old_offset;
1189 /* we dont dont remember where in the bytestream these fields were */
1190 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1191 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
1192 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
1194 /* real run, dissect the elements */
1195 for(i=0;i<di->array_actual_count;i++){
1196 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1203 /* Dissect an string of bytes. This corresponds to
1204 IDL of the form '[string] byte *foo'.
1206 It can also be used for a conformant varying array of bytes if
1207 the contents of the array should be shown as a big blob, rather
1208 than showing each byte as an individual element.
1210 XXX - which of those is really the IDL type for, for example,
1211 the encrypted data in some MAPI packets? (Microsoft haven't
1214 XXX - does this need to do all the conformant array stuff that
1215 "dissect_ndr_ucvarray()" does? These are presumably for strings
1216 that are conformant and varying - they're stored like conformant
1217 varying arrays of bytes. */
1219 dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo,
1220 proto_tree *tree, guint8 *drep)
1225 di=pinfo->private_data;
1226 if(di->conformant_run){
1227 /* just a run to handle conformant arrays, no scalars to dissect */
1231 /* NDR array header */
1233 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1234 hf_dcerpc_array_max_count, NULL);
1236 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1237 hf_dcerpc_array_offset, NULL);
1239 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1240 hf_dcerpc_array_actual_count, &len);
1243 proto_tree_add_item(tree, hf_dcerpc_array_buffer,
1244 tvb, offset, len, drep[0] & 0x10);
1251 /* For dissecting arrays that are to be interpreted as strings. */
1253 /* Dissect an NDR conformant varying string of elements.
1254 The length of each element is given by the 'size_is' parameter;
1255 the elements are assumed to be characters or wide characters.
1257 XXX - does this need to do all the conformant array stuff that
1258 "dissect_ndr_ucvarray()" does? */
1260 dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1261 proto_tree *tree, guint8 *drep, int size_is,
1262 int hfindex, gboolean add_subtree, char **data)
1265 proto_item *string_item;
1266 proto_tree *string_tree;
1267 guint32 len, buffer_len;
1269 header_field_info *hfinfo;
1271 di=pinfo->private_data;
1272 if(di->conformant_run){
1273 /* just a run to handle conformant arrays, no scalars to dissect */
1278 string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1279 proto_registrar_get_name(hfindex));
1280 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1286 /* NDR array header */
1288 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1289 hf_dcerpc_array_max_count, NULL);
1291 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1292 hf_dcerpc_array_offset, NULL);
1294 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1295 hf_dcerpc_array_actual_count, &len);
1297 buffer_len = size_is * len;
1300 if (offset % size_is)
1301 offset += size_is - (offset % size_is);
1303 if (size_is == sizeof(guint16)) {
1304 /* XXX - use drep to determine the byte order? */
1305 s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
1307 * XXX - we don't support a string type with Unicode
1308 * characters, so if this is a string item, we make
1309 * its value be the "fake Unicode" string.
1311 if (tree && buffer_len) {
1312 hfinfo = proto_registrar_get_nth(hfindex);
1313 if (hfinfo->type == FT_STRING) {
1314 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1317 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1318 buffer_len, drep[0] & 0x10);
1323 * "tvb_get_string()" throws an exception if the entire string
1324 * isn't in the tvbuff. If the length is bogus, this should
1325 * keep us from trying to allocate an immensely large buffer.
1326 * (It won't help if the length is *valid* but immensely large,
1327 * but that's another matter; in any case, that would happen only
1328 * if we had an immensely large tvbuff....)
1330 s = tvb_get_string(tvb, offset, buffer_len);
1331 if (tree && buffer_len)
1332 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1333 buffer_len, drep[0] & 0x10);
1336 if (string_item != NULL)
1337 proto_item_append_text(string_item, ": %s", s);
1344 offset += buffer_len;
1346 proto_item_set_end(string_item, tvb, offset);
1351 /* Dissect an conformant varying string of chars.
1352 This corresponds to IDL of the form '[string] char *foo'.
1354 XXX - at least according to the DCE RPC 1.1 spec, a string has
1355 a null terminator, which isn't necessary as a terminator for
1356 the transfer language (as there's a length), but is presumably
1357 there for the benefit of null-terminated-string languages
1358 such as C. Is this ever used for purely counted strings?
1359 (Not that it matters if it is.) */
1361 dissect_ndr_char_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1362 proto_tree *tree, guint8 *drep)
1365 di=pinfo->private_data;
1367 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1368 sizeof(guint8), di->hf_index,
1372 /* Dissect a conformant varying string of wchars (wide characters).
1373 This corresponds to IDL of the form '[string] wchar *foo'
1375 XXX - at least according to the DCE RPC 1.1 spec, a string has
1376 a null terminator, which isn't necessary as a terminator for
1377 the transfer language (as there's a length), but is presumably
1378 there for the benefit of null-terminated-string languages
1379 such as C. Is this ever used for purely counted strings?
1380 (Not that it matters if it is.) */
1382 dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1383 proto_tree *tree, guint8 *drep)
1386 di=pinfo->private_data;
1388 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1389 sizeof(guint16), di->hf_index,
1393 /* ndr pointer handling */
1394 /* list of pointers encountered so far */
1395 static GSList *ndr_pointer_list = NULL;
1397 /* position where in the list to insert newly encountered pointers */
1398 static int ndr_pointer_list_pos=0;
1400 /* boolean controlling whether pointers are top-level or embedded */
1401 static gboolean pointers_are_top_level = TRUE;
1403 /* as a kludge, we represent all embedded reference pointers as id==-1
1404 hoping that his will not collide with any non-ref pointers */
1405 typedef struct ndr_pointer_data {
1407 proto_item *item; /* proto_item for pointer */
1408 proto_tree *tree; /* subtree of above item */
1409 dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
1411 dcerpc_callback_fnct_t *callback;
1412 void *callback_args;
1413 } ndr_pointer_data_t;
1416 init_ndr_pointer_list(packet_info *pinfo)
1420 di=pinfo->private_data;
1421 di->conformant_run=0;
1423 while(ndr_pointer_list){
1424 ndr_pointer_data_t *npd;
1426 npd=g_slist_nth_data(ndr_pointer_list, 0);
1427 ndr_pointer_list=g_slist_remove(ndr_pointer_list, npd);
1433 ndr_pointer_list=NULL;
1434 ndr_pointer_list_pos=0;
1435 pointers_are_top_level=TRUE;
1439 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, guint8 *drep)
1441 int found_new_pointer;
1447 di=pinfo->private_data;
1451 found_new_pointer=0;
1452 len=g_slist_length(ndr_pointer_list);
1453 for(i=next_pointer;i<len;i++){
1454 ndr_pointer_data_t *tnpd;
1455 tnpd=g_slist_nth_data(ndr_pointer_list, i);
1457 dcerpc_dissect_fnct_t *fnct;
1460 found_new_pointer=1;
1463 ndr_pointer_list_pos=i+1;
1464 di->hf_index=tnpd->hf_index;
1465 /* first a run to handle any conformant
1467 di->conformant_run=1;
1468 di->conformant_eaten=0;
1469 old_offset = offset;
1470 offset = (*(fnct))(tvb, offset, pinfo, NULL, drep);
1472 g_assert((offset-old_offset)==di->conformant_eaten);
1473 /* This is to check for any bugs in the dissectors.
1475 * Basically, the NDR representation will store all
1476 * arrays in two blocks, one block with the dimension
1477 * discreption, like size, number of elements and such,
1478 * and another block that contains the actual data stored
1480 * If the array is embedded directly inside another,
1481 * encapsulating aggregate type, like a union or struct,
1482 * then these two blocks will be stored at different places
1483 * in the bytestream, with other data between the blocks.
1485 * For this reason, all pointers to types (both aggregate
1486 * and scalar, for simplicity no distinction is made)
1487 * will have its dissector called twice.
1488 * The dissector will first be called with conformant_run==1
1489 * in which mode the dissector MUST NOT consume any data from
1490 * the tvbuff (i.e. may not dissect anything) except the
1491 * initial control block for arrays.
1492 * The second time the dissector is called, with
1493 * conformant_run==0, all other data for the type will be
1496 * All dissect_ndr_<type> dissectors are already prepared
1497 * for this and knows when it should eat data from the tvb
1498 * and when not to, so implementors of dissectors will
1499 * normally not need to worry about this or even know about
1500 * it. However, if a dissector for an aggregate type calls
1501 * a subdissector from outside packet-dcerpc.c, such as
1502 * the dissector in packet-smb.c for NT Security Descriptors
1503 * as an example, then it is VERY important to encapsulate
1504 * this call to an external subdissector with the appropriate
1505 * test for conformant_run, i.e. it will need something like
1509 * di=pinfo->private_data;
1510 * if(di->conformant_run){
1514 * to make sure it makes the right thing.
1515 * This assert will signal when someone has forgotten to
1516 * make the dissector aware of this requirement.
1519 /* now we dissect the actual pointer */
1520 di->conformant_run=0;
1521 old_offset = offset;
1522 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, drep);
1524 tnpd->callback(pinfo, tnpd->tree, tnpd->item, tvb, old_offset, offset, tnpd->callback_args);
1528 } while(found_new_pointer);
1535 add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
1536 dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index,
1537 dcerpc_callback_fnct_t *callback, void *callback_args)
1539 ndr_pointer_data_t *npd;
1541 /* check if this pointer is valid */
1544 dcerpc_call_value *value;
1546 di=pinfo->private_data;
1547 value=di->call_data;
1549 if(di->ptype == PDU_REQ){
1550 if(!(pinfo->fd->flags.visited)){
1551 if(id>value->max_ptr){
1556 /* if we havent seen the request bail out since we cant
1557 know whether this is the first non-NULL instance
1559 if(value->req_frame==0){
1560 /* XXX THROW EXCEPTION */
1563 /* We saw this one in the request frame, nothing to
1565 if(id<=value->max_ptr){
1571 npd=g_malloc(sizeof(ndr_pointer_data_t));
1576 npd->hf_index=hf_index;
1577 npd->callback=callback;
1578 npd->callback_args=callback_args;
1579 ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
1580 ndr_pointer_list_pos);
1581 ndr_pointer_list_pos++;
1586 find_pointer_index(guint32 id)
1588 ndr_pointer_data_t *npd;
1591 len=g_slist_length(ndr_pointer_list);
1593 npd=g_slist_nth_data(ndr_pointer_list, i);
1604 /* This function dissects an NDR pointer and stores the callback for later
1605 * deferred dissection.
1607 * fnct is the callback function for when we have reached this object in
1610 * type is what type of pointer.
1612 * this is text is what text we should put in any created tree node.
1614 * hf_index is what hf value we want to pass to the callback function when
1615 * it is called, the callback can later pich this one up from di->hf_index.
1617 * callback is executed after the pointer has been dereferenced.
1619 * callback_args is passed as an argument to the callback function
1621 * See packet-dcerpc-samr.c for examples
1624 dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1625 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
1626 int type, char *text, int hf_index,
1627 dcerpc_callback_fnct_t *callback, void *callback_args)
1631 di=pinfo->private_data;
1632 if(di->conformant_run){
1633 /* this call was only for dissecting the header for any
1634 embedded conformant array. we will not parse any
1635 pointers in this mode.
1640 /*TOP LEVEL REFERENCE POINTER*/
1641 if( pointers_are_top_level
1642 &&(type==NDR_POINTER_REF) ){
1646 /* we must find out a nice way to do the length here */
1647 item=proto_tree_add_text(tree, tvb, offset, 0,
1649 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1651 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1652 hf_index, callback, callback_args);
1656 /*TOP LEVEL FULL POINTER*/
1657 if( pointers_are_top_level
1658 && (type==NDR_POINTER_PTR) ){
1664 /* get the referent id */
1665 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1667 /* we got a NULL pointer */
1669 proto_tree_add_text(tree, tvb, offset-4, 4,
1670 "(NULL pointer) %s",text);
1674 /* see if we have seen this pointer before */
1675 idx=find_pointer_index(id);
1677 /* we have seen this pointer before */
1679 proto_tree_add_text(tree, tvb, offset-4, 4,
1680 "(duplicate PTR) %s",text);
1685 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1687 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1688 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1689 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
1690 callback, callback_args);
1693 /*TOP LEVEL UNIQUE POINTER*/
1694 if( pointers_are_top_level
1695 && (type==NDR_POINTER_UNIQUE) ){
1700 /* get the referent id */
1701 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1703 /* we got a NULL pointer */
1705 proto_tree_add_text(tree, tvb, offset-4, 4,
1706 "(NULL pointer) %s",text);
1711 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1713 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1714 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1715 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1716 hf_index, callback, callback_args);
1720 /*EMBEDDED REFERENCE POINTER*/
1721 if( (!pointers_are_top_level)
1722 && (type==NDR_POINTER_REF) ){
1727 /* get the referent id */
1728 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1731 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1733 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1734 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1735 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1736 hf_index, callback, callback_args);
1740 /*EMBEDDED UNIQUE POINTER*/
1741 if( (!pointers_are_top_level)
1742 && (type==NDR_POINTER_UNIQUE) ){
1747 /* get the referent id */
1748 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1750 /* we got a NULL pointer */
1752 proto_tree_add_text(tree, tvb, offset-4, 4,
1753 "(NULL pointer) %s", text);
1758 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1760 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1761 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1762 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1763 hf_index, callback, callback_args);
1767 /*EMBEDDED FULL POINTER*/
1768 if( (!pointers_are_top_level)
1769 && (type==NDR_POINTER_PTR) ){
1775 /* get the referent id */
1776 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1778 /* we got a NULL pointer */
1780 proto_tree_add_text(tree, tvb, offset-4, 4,
1781 "(NULL pointer) %s",text);
1785 /* see if we have seen this pointer before */
1786 idx=find_pointer_index(id);
1788 /* we have seen this pointer before */
1790 proto_tree_add_text(tree, tvb, offset-4, 4,
1791 "(duplicate PTR) %s",text);
1796 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1798 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1799 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1800 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
1801 callback, callback_args);
1807 /* After each top level pointer we have dissected we have to
1808 dissect all deferrals before we move on to the next top level
1810 if(pointers_are_top_level==TRUE){
1811 pointers_are_top_level=FALSE;
1812 offset = dissect_deferred_pointers(pinfo, tvb, offset, drep);
1813 pointers_are_top_level=TRUE;
1820 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1821 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
1822 int type, char *text, int hf_index)
1824 return dissect_ndr_pointer_cb(
1825 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
1830 show_stub_data (tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
1831 dcerpc_auth_info *auth_info, gboolean is_encrypted)
1836 * We don't show stub data unless we have some in the tvbuff;
1837 * however, in the protocol tree, we show, as the number of
1838 * bytes, the reported number of bytes, not the number of bytes
1839 * that happen to be in the tvbuff.
1841 if (tvb_length_remaining (tvb, offset) > 0) {
1842 length = tvb_reported_length_remaining (tvb, offset);
1843 if (auth_info != NULL &&
1844 auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
1846 proto_tree_add_text(dcerpc_tree, tvb, offset, -1,
1847 "Encrypted stub data (%d byte%s)",
1848 length, plurality(length, "", "s"));
1850 proto_tree_add_text(dcerpc_tree, tvb, offset, -1,
1851 "Decrypted stub data (%d byte%s)",
1852 length, plurality(length, "", "s"));
1855 proto_tree_add_text (dcerpc_tree, tvb, offset, -1,
1856 "Stub data (%d byte%s)", length,
1857 plurality(length, "", "s"));
1863 dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
1864 proto_tree *dcerpc_tree,
1865 tvbuff_t *volatile tvb, tvbuff_t *decrypted_tvb,
1866 guint8 *drep, dcerpc_info *info,
1867 dcerpc_auth_info *auth_info)
1869 volatile gint offset = 0;
1870 dcerpc_uuid_key key;
1871 dcerpc_uuid_value *sub_proto;
1872 proto_tree *volatile sub_tree = NULL;
1873 dcerpc_sub_dissector *proc;
1875 dcerpc_dissect_fnct_t *volatile sub_dissect;
1876 const char *volatile saved_proto;
1877 void *volatile saved_private_data;
1878 guint length, reported_length;
1879 tvbuff_t *volatile stub_tvb;
1880 volatile guint auth_pad_len;
1881 volatile int auth_pad_offset;
1883 char UUID_NAME[MAX_PATH];
1886 key.uuid = info->call_data->uuid;
1887 key.ver = info->call_data->ver;
1890 if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == NULL
1891 || !proto_is_protocol_enabled(sub_proto->proto)) {
1893 * We don't have a dissector for this UUID, or the protocol
1894 * for that UUID is disabled.
1897 proto_tree_add_boolean_hidden(dcerpc_tree, hf_dcerpc_unknown_if_id,
1898 tvb, offset, 0, TRUE);
1899 if (check_col (pinfo->cinfo, COL_INFO)) {
1901 if(ResolveWin32UUID(info->call_data->uuid, UUID_NAME, MAX_PATH))
1902 col_append_fstr (pinfo->cinfo, COL_INFO, " [%s] UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x rpcver: %u",
1903 UUID_NAME, info->call_data->uuid.Data1, info->call_data->uuid.Data2, info->call_data->uuid.Data3, info->call_data->uuid.Data4[0],
1904 info->call_data->uuid.Data4[1], info->call_data->uuid.Data4[2], info->call_data->uuid.Data4[3],
1905 info->call_data->uuid.Data4[4], info->call_data->uuid.Data4[5], info->call_data->uuid.Data4[6],
1906 info->call_data->uuid.Data4[7], info->call_data->ver);
1909 col_append_fstr (pinfo->cinfo, COL_INFO, " UNKUUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x rpcver: %u",
1910 info->call_data->uuid.Data1, info->call_data->uuid.Data2, info->call_data->uuid.Data3, info->call_data->uuid.Data4[0],
1911 info->call_data->uuid.Data4[1], info->call_data->uuid.Data4[2], info->call_data->uuid.Data4[3],
1912 info->call_data->uuid.Data4[4], info->call_data->uuid.Data4[5], info->call_data->uuid.Data4[6],
1913 info->call_data->uuid.Data4[7], info->call_data->ver);
1916 if (decrypted_tvb != NULL) {
1917 show_stub_data (decrypted_tvb, 0, dcerpc_tree, auth_info,
1920 show_stub_data (tvb, 0, dcerpc_tree, auth_info, TRUE);
1924 for (proc = sub_proto->procs; proc->name; proc++) {
1925 if (proc->num == info->call_data->opnum) {
1934 if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
1935 col_set_str (pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
1938 if (check_col (pinfo->cinfo, COL_INFO)) {
1939 col_add_fstr (pinfo->cinfo, COL_INFO, "%s %s",
1940 name, (info->ptype == PDU_REQ) ? "request" : "response");
1944 proto_item *sub_item;
1945 sub_item = proto_tree_add_item (tree, sub_proto->proto_id, tvb, 0,
1949 sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
1950 proto_item_append_text(sub_item, ", %s", name);
1954 * Put the operation number into the tree along with
1955 * the operation's name.
1958 if (sub_proto->opnum_hf != -1)
1959 proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
1960 tvb, 0, 0, info->call_data->opnum,
1961 "Operation: %s (%u)",
1962 name, info->call_data->opnum);
1964 proto_tree_add_uint_format(sub_tree, hf_dcerpc_op, tvb,
1965 0, 0, info->call_data->opnum,
1966 "Operation: %s (%u)",
1967 name, info->call_data->opnum);
1970 sub_dissect = (info->ptype == PDU_REQ) ?
1971 proc->dissect_rqst : proc->dissect_resp;
1973 if (decrypted_tvb != NULL) {
1974 /* Either there was no encryption or we successfully decrypted
1975 the entrypted payload. */
1977 /* We have a subdissector - call it. */
1978 saved_proto = pinfo->current_proto;
1979 saved_private_data = pinfo->private_data;
1980 pinfo->current_proto = sub_proto->name;
1981 pinfo->private_data = (void *)info;
1983 init_ndr_pointer_list(pinfo);
1986 * Remove the authentication padding from the stub data.
1988 if (auth_info != NULL && auth_info->auth_pad_len != 0) {
1989 length = tvb_length(decrypted_tvb);
1990 reported_length = tvb_reported_length(decrypted_tvb);
1991 if (reported_length >= auth_info->auth_pad_len) {
1993 * OK, the padding length isn't so big that it
1994 * exceeds the stub length. Trim the reported
1995 * length of the tvbuff.
1997 reported_length -= auth_info->auth_pad_len;
2000 * If that exceeds the actual amount of data in
2001 * the tvbuff (which means we have at least one
2002 * byte of authentication padding in the tvbuff),
2003 * trim the actual amount.
2005 if (length > reported_length)
2006 length = reported_length;
2008 stub_tvb = tvb_new_subset(tvb, 0, length, reported_length);
2009 auth_pad_len = auth_info->auth_pad_len;
2010 auth_pad_offset = reported_length;
2013 * The padding length exceeds the stub length.
2014 * Don't bother dissecting the stub, trim the padding
2015 * length to what's in the stub data, and show the
2016 * entire stub as authentication padding.
2019 auth_pad_len = reported_length;
2020 auth_pad_offset = 0;
2024 * No authentication padding.
2026 stub_tvb = decrypted_tvb;
2028 auth_pad_offset = 0;
2031 if (stub_tvb != NULL) {
2033 * Catch all exceptions other than BoundsError, so that even
2034 * if the stub data is bad, we still show the authentication
2037 * If we get BoundsError, it means the frame was cut short
2038 * by a snapshot length, so there's nothing more to
2039 * dissect; just re-throw that exception.
2042 offset = sub_dissect (decrypted_tvb, 0, pinfo, sub_tree,
2045 /* If we have a subdissector and it didn't dissect all
2046 data in the tvb, make a note of it. */
2048 if (tvb_reported_length_remaining(stub_tvb, offset) > 0) {
2049 if (check_col(pinfo->cinfo, COL_INFO))
2050 col_append_fstr(pinfo->cinfo, COL_INFO,
2051 "[Long frame (%d bytes)]",
2052 tvb_reported_length_remaining(stub_tvb, offset));
2054 } CATCH(BoundsError) {
2057 show_exception(decrypted_tvb, pinfo, tree, EXCEPT_CODE);
2061 /* If there is auth padding at the end of the stub, display it */
2062 if (auth_pad_len != 0) {
2063 proto_tree_add_text (sub_tree, decrypted_tvb, auth_pad_offset,
2065 "Auth Padding (%u byte%s)",
2067 plurality(auth_pad_len, "", "s"));
2070 pinfo->current_proto = saved_proto;
2071 pinfo->private_data = saved_private_data;
2073 /* No subdissector - show it as stub data. */
2075 show_stub_data (decrypted_tvb, 0, sub_tree, auth_info, FALSE);
2077 show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
2081 show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
2083 tap_queue_packet(dcerpc_tap, pinfo, info);
2088 dissect_dcerpc_verifier (tvbuff_t *tvb, packet_info *pinfo,
2089 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
2090 dcerpc_auth_info *auth_info)
2094 auth_info->auth_data = NULL;
2096 if (auth_info->auth_size != 0) {
2097 dcerpc_auth_subdissector_fns *auth_fns;
2100 auth_offset = hdr->frag_len - hdr->auth_len;
2102 auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
2105 auth_info->auth_data = auth_tvb;
2107 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
2108 auth_info->auth_type))) {
2110 * Catch all exceptions, so that even if the verifier is bad
2111 * or we don't have all of it, we still show the stub data.
2114 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
2117 show_exception(auth_tvb, pinfo, dcerpc_tree, EXCEPT_CODE);
2120 proto_tree_add_text (dcerpc_tree, auth_tvb, 0, hdr->auth_len,
2125 return hdr->auth_len;
2129 dissect_dcerpc_cn_auth (tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
2130 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
2131 gboolean are_credentials, dcerpc_auth_info *auth_info)
2133 volatile int offset;
2136 * Initially set auth_level and auth_type to zero to indicate that we
2137 * haven't yet seen any authentication level information.
2139 auth_info->auth_level = 0;
2140 auth_info->auth_type = 0;
2141 auth_info->auth_size = 0;
2142 auth_info->auth_pad_len = 0;
2145 * The authentication information is at the *end* of the PDU; in
2146 * request and response PDUs, the request and response stub data
2149 * Is there any authentication data (i.e., is the authentication length
2150 * non-zero), and is the authentication length valid (i.e., is it, plus
2151 * 8 bytes for the type/level/pad length/reserved/context id, less than
2152 * or equal to the fragment length minus the starting offset of the
2157 && (hdr->auth_len + 8 <= hdr->frag_len - stub_offset)) {
2160 * Yes, there is authentication data, and the length is valid.
2161 * Do we have all the bytes of stub data?
2162 * (If not, we'd throw an exception dissecting *that*, so don't
2163 * bother trying to dissect the authentication information and
2164 * throwing another exception there.)
2166 offset = hdr->frag_len - (hdr->auth_len + 8);
2167 if (offset == 0 || tvb_offset_exists(tvb, offset - 1)) {
2169 * Either there's no stub data, or the last byte of the stub
2170 * data is present in the captured data, so we shouldn't
2171 * get a BoundsError dissecting the stub data.
2173 * Try dissecting the authentication data.
2174 * Catch all exceptions, so that even if the auth info is bad
2175 * or we don't have all of it, we still show the stuff we
2176 * dissect after this, such as stub data.
2179 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2180 hf_dcerpc_auth_type,
2181 &auth_info->auth_type);
2182 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2183 hf_dcerpc_auth_level,
2184 &auth_info->auth_level);
2186 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2187 hf_dcerpc_auth_pad_len,
2188 &auth_info->auth_pad_len);
2189 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2190 hf_dcerpc_auth_rsrvd, NULL);
2191 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2192 hf_dcerpc_auth_ctx_id, NULL);
2195 * Dissect the authentication data.
2197 if (are_credentials) {
2199 dcerpc_auth_subdissector_fns *auth_fns;
2201 auth_tvb = tvb_new_subset(tvb, offset, hdr->auth_len,
2204 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
2205 auth_info->auth_type)))
2206 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
2209 proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len,
2210 "Auth Credentials");
2213 /* Compute the size of the auth block. Note that this should not
2214 include auth padding, since when NTLMSSP encryption is used, the
2215 padding is actually inside the encrypted stub */
2216 auth_info->auth_size = hdr->auth_len + 8;
2218 show_exception(tvb, pinfo, dcerpc_tree, EXCEPT_CODE);
2225 /* We need to hash in the SMB fid number to generate a unique hash table
2226 * key as DCERPC over SMB allows several pipes over the same TCP/IP
2228 * We pass this function the transport type here to make sure we only look
2229 * at this function if it came across an SMB pipe.
2230 * Other transports might need to mix in their own extra multiplexing data
2231 * as well in the future.
2234 guint16 dcerpc_get_transport_salt (packet_info *pinfo, int transport_type)
2236 dcerpc_private_info *priv = (dcerpc_private_info *)pinfo->private_data;
2239 return 0; /* Nothing to see here */
2241 switch(transport_type){
2242 case DCE_CN_TRANSPORT_SMBPIPE:
2243 /* DCERPC over smb */
2247 /* Some other transport... */
2252 * Connection oriented packet types
2256 dissect_dcerpc_cn_bind (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2257 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
2260 conversation_t *conv = NULL;
2261 guint8 num_ctx_items = 0;
2263 gboolean saw_ctx_item = FALSE;
2265 guint8 num_trans_items;
2270 guint16 if_ver, if_ver_minor;
2271 char uuid_str[DCERPC_UUID_STR_LEN];
2273 dcerpc_auth_info auth_info;
2275 char UUID_NAME[MAX_PATH];
2278 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2279 hf_dcerpc_cn_max_xmit, NULL);
2281 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2282 hf_dcerpc_cn_max_recv, NULL);
2284 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2285 hf_dcerpc_cn_assoc_group, NULL);
2287 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2288 hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
2293 for (i = 0; i < num_ctx_items; i++) {
2294 proto_tree *ctx_tree = NULL, *iface_tree = NULL;
2296 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, NULL, hdr->drep,
2297 hf_dcerpc_cn_ctx_id, &ctx_id);
2299 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
2300 /* (if we have multiple contexts, this might cause "decode as"
2301 * to behave unpredictably) */
2302 pinfo->dcectxid = ctx_id;
2303 pinfo->dcetransporttype = transport_type;
2306 proto_item *ctx_item;
2308 ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_id,
2310 hdr->drep[0] & 0x10);
2312 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
2315 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, ctx_tree, hdr->drep,
2316 hf_dcerpc_cn_num_trans_items, &num_trans_items);
2321 /* XXX - use "dissect_ndr_uuid_t()"? */
2322 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
2324 proto_item *iface_item;
2326 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2327 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2328 if_id.Data1, if_id.Data2, if_id.Data3,
2329 if_id.Data4[0], if_id.Data4[1],
2330 if_id.Data4[2], if_id.Data4[3],
2331 if_id.Data4[4], if_id.Data4[5],
2332 if_id.Data4[6], if_id.Data4[7]);
2334 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2335 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2337 if(ResolveWin32UUID(if_id, UUID_NAME, MAX_PATH))
2338 iface_item = proto_tree_add_string_format (ctx_tree, hf_dcerpc_cn_bind_if_id, tvb,
2339 offset, 16, uuid_str, "Interface [%s] UUID: %s", UUID_NAME, uuid_str);
2342 iface_item = proto_tree_add_string_format (ctx_tree, hf_dcerpc_cn_bind_if_id, tvb,
2343 offset, 16, uuid_str, "Interface UUID: %s", uuid_str);
2344 iface_tree = proto_item_add_subtree(iface_item, ett_dcerpc_cn_iface);
2348 if (hdr->drep[0] & 0x10) {
2349 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2350 hf_dcerpc_cn_bind_if_ver, &if_ver);
2351 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2352 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2354 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2355 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2356 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2357 hf_dcerpc_cn_bind_if_ver, &if_ver);
2360 if (!saw_ctx_item) {
2361 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2362 pinfo->srcport, pinfo->destport, 0);
2364 conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
2365 pinfo->srcport, pinfo->destport, 0);
2369 /* if this is the first time we see this packet, we need to
2370 update the dcerpc_binds table so that any later calls can
2371 match to the interface.
2372 XXX We assume that BINDs will NEVER be fragmented.
2374 if(!(pinfo->fd->flags.visited)){
2375 dcerpc_bind_key *key;
2376 dcerpc_bind_value *value;
2378 key = g_mem_chunk_alloc (dcerpc_bind_key_chunk);
2380 key->ctx_id = ctx_id;
2381 key->smb_fid = dcerpc_get_transport_salt(pinfo, transport_type);
2383 value = g_mem_chunk_alloc (dcerpc_bind_value_chunk);
2384 value->uuid = if_id;
2385 value->ver = if_ver;
2387 /* add this entry to the bind table, first removing any
2388 previous ones that are identical
2390 if(g_hash_table_lookup(dcerpc_binds, key)){
2391 g_hash_table_remove(dcerpc_binds, key);
2393 g_hash_table_insert (dcerpc_binds, key, value);
2396 if (check_col (pinfo->cinfo, COL_INFO)) {
2397 dcerpc_uuid_key key;
2398 dcerpc_uuid_value *value;
2403 if (num_ctx_items > 1)
2404 col_append_fstr(pinfo->cinfo, COL_INFO, ", %u context items, 1st", num_ctx_items);
2406 if ((value = g_hash_table_lookup(dcerpc_uuids, &key)))
2407 col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %s", value->name);
2410 if(ResolveWin32UUID(if_id, UUID_NAME, MAX_PATH))
2411 col_append_fstr(pinfo->cinfo, COL_INFO, " [%s] UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
2412 UUID_NAME, if_id.Data1, if_id.Data2, if_id.Data3,
2413 if_id.Data4[0], if_id.Data4[1],
2414 if_id.Data4[2], if_id.Data4[3],
2415 if_id.Data4[4], if_id.Data4[5],
2416 if_id.Data4[6], if_id.Data4[7],
2417 if_ver, if_ver_minor);
2420 col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
2421 if_id.Data1, if_id.Data2, if_id.Data3,
2422 if_id.Data4[0], if_id.Data4[1],
2423 if_id.Data4[2], if_id.Data4[3],
2424 if_id.Data4[4], if_id.Data4[5],
2425 if_id.Data4[6], if_id.Data4[7],
2426 if_ver, if_ver_minor);
2428 saw_ctx_item = TRUE;
2431 for (j = 0; j < num_trans_items; j++) {
2432 /* XXX - use "dissect_ndr_uuid_t()"? */
2433 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2435 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2436 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2437 trans_id.Data1, trans_id.Data2, trans_id.Data3,
2438 trans_id.Data4[0], trans_id.Data4[1],
2439 trans_id.Data4[2], trans_id.Data4[3],
2440 trans_id.Data4[4], trans_id.Data4[5],
2441 trans_id.Data4[6], trans_id.Data4[7]);
2442 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2443 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2444 proto_tree_add_string_format (iface_tree, hf_dcerpc_cn_bind_trans_id, tvb,
2445 offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2449 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, iface_tree, hdr->drep,
2450 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
2455 * XXX - we should save the authentication type *if* we have
2456 * an authentication header, and associate it with an authentication
2457 * context, so subsequent PDUs can use that context.
2459 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2463 dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2464 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2466 guint16 max_xmit, max_recv;
2467 guint16 sec_addr_len;
2474 char uuid_str[DCERPC_UUID_STR_LEN];
2476 dcerpc_auth_info auth_info;
2478 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2479 hf_dcerpc_cn_max_xmit, &max_xmit);
2481 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2482 hf_dcerpc_cn_max_recv, &max_recv);
2484 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2485 hf_dcerpc_cn_assoc_group, NULL);
2487 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2488 hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
2489 if (sec_addr_len != 0) {
2490 proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
2491 sec_addr_len, FALSE);
2492 offset += sec_addr_len;
2496 offset += 4 - offset % 4;
2499 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2500 hf_dcerpc_cn_num_results, &num_results);
2505 for (i = 0; i < num_results; i++) {
2506 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2507 hdr->drep, hf_dcerpc_cn_ack_result,
2510 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2511 hdr->drep, hf_dcerpc_cn_ack_reason,
2515 * The reason for rejection isn't meaningful, and often isn't
2516 * set, when the syntax was accepted.
2521 /* XXX - use "dissect_ndr_uuid_t()"? */
2522 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2524 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2525 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2526 trans_id.Data1, trans_id.Data2, trans_id.Data3,
2527 trans_id.Data4[0], trans_id.Data4[1],
2528 trans_id.Data4[2], trans_id.Data4[3],
2529 trans_id.Data4[4], trans_id.Data4[5],
2530 trans_id.Data4[6], trans_id.Data4[7]);
2531 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2532 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2533 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_ack_trans_id, tvb,
2534 offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2538 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2539 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
2543 * XXX - do we need to do anything with the authentication level
2544 * we get back from this?
2546 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2548 if (check_col (pinfo->cinfo, COL_INFO)) {
2549 if (num_results != 0 && result == 0) {
2550 /* XXX - only checks the last result */
2551 col_append_fstr (pinfo->cinfo, COL_INFO,
2552 " accept max_xmit: %u max_recv: %u",
2553 max_xmit, max_recv);
2555 /* XXX - only shows the last result and reason */
2556 col_append_fstr (pinfo->cinfo, COL_INFO, " %s, reason: %s",
2557 val_to_str(result, p_cont_result_vals,
2558 "Unknown result (%u)"),
2559 val_to_str(reason, p_provider_reason_vals,
2566 dissect_dcerpc_cn_bind_nak (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2567 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2570 guint8 num_protocols;
2573 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2574 hdr->drep, hf_dcerpc_cn_reject_reason,
2577 if (check_col (pinfo->cinfo, COL_INFO)) {
2578 col_append_fstr (pinfo->cinfo, COL_INFO, " reason: %s",
2579 val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
2582 if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
2583 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2584 hf_dcerpc_cn_num_protocols,
2587 for (i = 0; i < num_protocols; i++) {
2588 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2589 hdr->drep, hf_dcerpc_cn_protocol_ver_major,
2591 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2592 hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
2598 /* Return a string describing a DCE/RPC fragment as first, middle, or end
2601 #define PFC_FRAG_MASK 0x03
2604 fragment_type(guint8 flags)
2606 flags = flags & PFC_FRAG_MASK;
2608 if (flags == PFC_FIRST_FRAG)
2614 if (flags == PFC_LAST_FRAG)
2617 if (flags == (PFC_FIRST_FRAG | PFC_LAST_FRAG))
2623 /* Dissect stub data (payload) of a DCERPC packet. */
2626 dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
2627 proto_tree *dcerpc_tree, proto_tree *tree,
2628 e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
2629 dcerpc_auth_info *auth_info, guint32 alloc_hint,
2632 gint length, reported_length;
2633 gboolean save_fragmented;
2634 fragment_data *fd_head=NULL;
2636 tvbuff_t *payload_tvb, *decrypted_tvb;
2639 save_fragmented = pinfo->fragmented;
2641 length = tvb_length_remaining(tvb, offset);
2642 reported_length = tvb_reported_length_remaining(tvb, offset);
2643 if (reported_length < 0 ||
2644 (guint32)reported_length < auth_info->auth_size) {
2645 /* We don't even have enough bytes for the authentication
2649 reported_length -= auth_info->auth_size;
2650 if (length > reported_length)
2651 length = reported_length;
2652 payload_tvb = tvb_new_subset(tvb, offset, length, reported_length);
2654 /* Decrypt the PDU if it is encrypted */
2656 if (auth_info->auth_type &&
2657 auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
2659 * We know the authentication type, and the authentication
2660 * level is "Packet privacy", meaning the payload is
2661 * encrypted; attempt to decrypt it.
2663 dcerpc_auth_subdissector_fns *auth_fns;
2665 /* Start out assuming we won't succeed in decrypting. */
2666 decrypted_tvb = NULL;
2668 if ((auth_fns = get_auth_subdissector_fns(
2669 auth_info->auth_level, auth_info->auth_type))) {
2672 result = decode_encrypted_data(
2673 payload_tvb, pinfo, auth_fns,
2674 hdr->ptype == PDU_REQ, auth_info);
2678 proto_tree_add_text(
2679 dcerpc_tree, payload_tvb, 0, -1,
2680 "Encrypted stub data (%d byte%s)",
2681 tvb_reported_length(payload_tvb),
2683 plurality(tvb_length(payload_tvb), "", "s"));
2685 add_new_data_source(
2686 pinfo, result, "Decrypted stub data");
2689 decrypted_tvb = result;
2693 decrypted_tvb = payload_tvb;
2695 /* if this packet is not fragmented, just dissect it and exit */
2696 if(PFC_NOT_FRAGMENTED(hdr)){
2697 pinfo->fragmented = FALSE;
2700 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
2701 hdr->drep, di, auth_info);
2703 pinfo->fragmented = save_fragmented;
2707 /* The packet is fragmented. */
2708 pinfo->fragmented = TRUE;
2710 /* if we are not doing reassembly and this is the first fragment
2711 then just dissect it and exit
2712 XXX - if we're not doing reassembly, can we decrypt an
2715 if( (!dcerpc_reassemble) && hdr->flags&PFC_FIRST_FRAG ){
2718 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
2719 hdr->drep, di, auth_info);
2721 if (check_col(pinfo->cinfo, COL_INFO)) {
2722 col_append_fstr(pinfo->cinfo, COL_INFO,
2723 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
2725 pinfo->fragmented = save_fragmented;
2729 /* if we have already seen this packet, see if it was reassembled
2730 and if so dissect the full pdu.
2733 if(pinfo->fd->flags.visited){
2734 fd_head=fragment_get(pinfo, frame, dcerpc_co_reassemble_table);
2738 /* if we are not doing reassembly and it was neither a complete PDU
2739 nor the first fragment then there is nothing more we can do
2740 so we just have to exit
2742 if( !dcerpc_reassemble )
2745 /* if we didnt get 'frame' we dont know where the PDU started and thus
2746 it is pointless to continue
2751 /* from now on we must attempt to reassemble the PDU
2754 /* if we get here we know it is the first time we see the packet
2755 and we also know it is only a fragment and not a full PDU,
2756 thus we must reassemble it.
2759 /* Do we have any non-encrypted data to reassemble? */
2760 if (decrypted_tvb == NULL) {
2761 /* No. We can't even try to reassemble. */
2765 /* if this is the first fragment we need to start reassembly
2767 if(hdr->flags&PFC_FIRST_FRAG){
2768 fragment_add(decrypted_tvb, 0, pinfo, frame, dcerpc_co_reassemble_table,
2769 0, tvb_length(decrypted_tvb), TRUE);
2770 fragment_set_tot_len(pinfo, frame,
2771 dcerpc_co_reassemble_table, alloc_hint);
2776 /* if this is a middle fragment, just add it and exit */
2777 if(!(hdr->flags&PFC_LAST_FRAG)){
2778 tot_len = fragment_get_tot_len(pinfo, frame,
2779 dcerpc_co_reassemble_table);
2780 fragment_add(decrypted_tvb, 0, pinfo, frame,
2781 dcerpc_co_reassemble_table,
2782 tot_len-alloc_hint, tvb_length(decrypted_tvb),
2788 /* this was the last fragment add it to reassembly
2790 tot_len = fragment_get_tot_len(pinfo, frame,
2791 dcerpc_co_reassemble_table);
2792 fd_head = fragment_add(decrypted_tvb, 0, pinfo,
2794 dcerpc_co_reassemble_table,
2795 tot_len-alloc_hint, tvb_length(decrypted_tvb),
2800 /* if reassembly is complete, dissect the full PDU
2802 if(fd_head && (fd_head->flags&FD_DEFRAGMENTED) ){
2804 if(pinfo->fd->num==fd_head->reassembled_in){
2807 next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
2808 tvb_set_child_real_data_tvbuff(decrypted_tvb, next_tvb);
2809 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
2810 show_fragment_tree(fd_head, &dcerpc_frag_items,
2811 dcerpc_tree, pinfo, next_tvb);
2813 pinfo->fragmented = FALSE;
2815 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
2816 next_tvb, hdr->drep, di, auth_info);
2819 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
2820 decrypted_tvb, 0, 0, fd_head->reassembled_in);
2821 PROTO_ITEM_SET_GENERATED(pi);
2822 if (check_col(pinfo->cinfo, COL_INFO)) {
2823 col_append_fstr(pinfo->cinfo, COL_INFO,
2824 " [DCE/RPC %s fragment, reas: #%u]", fragment_type(hdr->flags), fd_head->reassembled_in);
2828 /* Reassembly not complete - some fragments
2829 are missing. Just show the stub data. */
2831 if (check_col(pinfo->cinfo, COL_INFO)) {
2832 col_append_fstr(pinfo->cinfo, COL_INFO,
2833 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
2837 show_stub_data (decrypted_tvb, 0, tree, auth_info, FALSE);
2839 show_stub_data (payload_tvb, 0, tree, auth_info, TRUE);
2843 pinfo->fragmented = save_fragmented;
2847 * Registers a conversation/UUID binding association, so that
2848 * we can invoke the proper sub-dissector for a given DCERPC
2851 * @param binding all values needed to create and bind a new conversation
2853 * @return Pointer to newly-added UUID/conversation binding.
2855 struct _dcerpc_bind_value *
2856 dcerpc_add_conv_to_bind_table(decode_dcerpc_bind_values_t *binding)
2858 dcerpc_bind_value *bind_value;
2859 dcerpc_bind_key *key;
2860 conversation_t *conv;
2862 conv = find_conversation (
2871 conv = conversation_new (
2880 bind_value = g_mem_chunk_alloc (dcerpc_bind_value_chunk);
2881 bind_value->uuid = binding->uuid;
2882 bind_value->ver = binding->ver;
2884 key = g_mem_chunk_alloc(dcerpc_bind_key_chunk);
2886 key->ctx_id = binding->ctx_id;
2887 key->smb_fid = binding->smb_fid;
2889 /* add this entry to the bind table, first removing any
2890 previous ones that are identical
2892 if(g_hash_table_lookup(dcerpc_binds, key)){
2893 g_hash_table_remove(dcerpc_binds, key);
2895 g_hash_table_insert(dcerpc_binds, key, bind_value);
2902 dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2903 proto_tree *dcerpc_tree, proto_tree *tree,
2904 e_dce_cn_common_hdr_t *hdr, int transport_type)
2906 conversation_t *conv;
2910 dcerpc_auth_info auth_info;
2912 char uuid_str[DCERPC_UUID_STR_LEN];
2916 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2917 hf_dcerpc_cn_alloc_hint, &alloc_hint);
2919 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2920 hf_dcerpc_cn_ctx_id, &ctx_id);
2922 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2923 hf_dcerpc_opnum, &opnum);
2925 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
2926 pinfo->dcectxid = ctx_id;
2927 pinfo->dcetransporttype = transport_type;
2929 if (check_col (pinfo->cinfo, COL_INFO)) {
2930 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u ctx_id: %u",
2934 if (hdr->flags & PFC_OBJECT_UUID) {
2935 /* XXX - use "dissect_ndr_uuid_t()"? */
2936 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id);
2938 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2939 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2940 obj_id.Data1, obj_id.Data2, obj_id.Data3,
2949 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2950 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2951 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
2952 offset, 16, uuid_str, "Object UUID: %s", uuid_str);
2958 * XXX - what if this was set when the connection was set up,
2959 * and we just have a security context?
2961 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
2963 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2964 pinfo->srcport, pinfo->destport, 0);
2966 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
2968 dcerpc_matched_key matched_key, *new_matched_key;
2969 dcerpc_call_value *value;
2971 /* !!! we can NOT check flags.visited here since this will interact
2972 badly with when SMB handles (i.e. calls the subdissector)
2973 and desegmented pdu's .
2974 Instead we check if this pdu is already in the matched table or not
2976 matched_key.frame = pinfo->fd->num;
2977 matched_key.call_id = hdr->call_id;
2978 value = g_hash_table_lookup(dcerpc_matched, &matched_key);
2980 dcerpc_bind_key bind_key;
2981 dcerpc_bind_value *bind_value;
2984 bind_key.ctx_id=ctx_id;
2985 bind_key.smb_fid=dcerpc_get_transport_salt(pinfo, transport_type);
2987 if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key)) ){
2988 if(!(hdr->flags&PFC_FIRST_FRAG)){
2989 dcerpc_cn_call_key call_key;
2990 dcerpc_call_value *call_value;
2993 call_key.call_id=hdr->call_id;
2994 call_key.smb_fid=dcerpc_get_transport_salt(pinfo, transport_type);
2995 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
2996 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
2997 *new_matched_key = matched_key;
2998 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3002 dcerpc_cn_call_key *call_key;
3003 dcerpc_call_value *call_value;
3005 /* We found the binding and it is the first fragment
3006 (or a complete PDU) of a dcerpc pdu so just add
3007 the call to both the call table and the
3010 call_key=g_mem_chunk_alloc (dcerpc_cn_call_key_chunk);
3011 call_key->conv=conv;
3012 call_key->call_id=hdr->call_id;
3013 call_key->smb_fid=dcerpc_get_transport_salt(pinfo, transport_type);
3015 /* if there is already a matching call in the table
3016 remove it so it is replaced with the new one */
3017 if(g_hash_table_lookup(dcerpc_cn_calls, call_key)){
3018 g_hash_table_remove(dcerpc_cn_calls, call_key);
3021 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
3022 call_value->uuid = bind_value->uuid;
3023 call_value->ver = bind_value->ver;
3024 call_value->opnum = opnum;
3025 call_value->req_frame=pinfo->fd->num;
3026 call_value->req_time.secs=pinfo->fd->abs_secs;
3027 call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000;
3028 call_value->rep_frame=0;
3029 call_value->max_ptr=0;
3030 call_value->private_data = NULL;
3031 g_hash_table_insert (dcerpc_cn_calls, call_key, call_value);
3033 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3034 *new_matched_key = matched_key;
3035 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3045 /* handoff this call */
3047 di->call_id = hdr->call_id;
3048 di->smb_fid = dcerpc_get_transport_salt(pinfo, transport_type);
3049 di->ptype = PDU_REQ;
3050 di->call_data = value;
3053 if(value->rep_frame!=0){
3054 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
3055 tvb, 0, 0, value->rep_frame);
3056 PROTO_ITEM_SET_GENERATED(pi);
3059 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
3060 hdr, di, &auth_info, alloc_hint,
3063 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3066 /* Dissect the verifier */
3067 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
3072 dissect_dcerpc_cn_resp (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3073 proto_tree *dcerpc_tree, proto_tree *tree,
3074 e_dce_cn_common_hdr_t *hdr, int transport_type)
3076 dcerpc_call_value *value = NULL;
3077 conversation_t *conv;
3079 dcerpc_auth_info auth_info;
3083 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3084 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3086 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3087 hf_dcerpc_cn_ctx_id, &ctx_id);
3089 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3090 pinfo->dcectxid = ctx_id;
3091 pinfo->dcetransporttype = transport_type;
3093 if (check_col (pinfo->cinfo, COL_INFO)) {
3094 col_append_fstr (pinfo->cinfo, COL_INFO, " ctx_id: %u", ctx_id);
3097 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3098 hf_dcerpc_cn_cancel_count, NULL);
3103 * XXX - what if this was set when the connection was set up,
3104 * and we just have a security context?
3106 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3108 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
3109 pinfo->srcport, pinfo->destport, 0);
3112 /* no point in creating one here, really */
3113 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3115 dcerpc_matched_key matched_key, *new_matched_key;
3117 /* !!! we can NOT check flags.visited here since this will interact
3118 badly with when SMB handles (i.e. calls the subdissector)
3119 and desegmented pdu's .
3120 Instead we check if this pdu is already in the matched table or not
3122 matched_key.frame = pinfo->fd->num;
3123 matched_key.call_id = hdr->call_id;
3124 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3126 dcerpc_cn_call_key call_key;
3127 dcerpc_call_value *call_value;
3130 call_key.call_id=hdr->call_id;
3131 call_key.smb_fid=dcerpc_get_transport_salt(pinfo, transport_type);
3133 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3134 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3135 *new_matched_key = matched_key;
3136 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3138 if(call_value->rep_frame==0){
3139 call_value->rep_frame=pinfo->fd->num;
3148 /* handoff this call */
3150 di->call_id = hdr->call_id;
3151 di->smb_fid = dcerpc_get_transport_salt(pinfo, transport_type);
3152 di->ptype = PDU_RESP;
3153 di->call_data = value;
3155 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
3156 if(value->req_frame!=0){
3158 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3159 tvb, 0, 0, value->req_frame);
3160 PROTO_ITEM_SET_GENERATED(pi);
3161 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
3162 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
3164 ns.nsecs+=1000000000;
3167 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
3168 PROTO_ITEM_SET_GENERATED(pi);
3171 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
3172 hdr, di, &auth_info, alloc_hint,
3175 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3178 /* Dissect the verifier */
3179 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
3183 dissect_dcerpc_cn_fault (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3184 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
3187 dcerpc_call_value *value = NULL;
3188 conversation_t *conv;
3192 dcerpc_auth_info auth_info;
3195 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3196 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3198 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3199 hf_dcerpc_cn_ctx_id, &ctx_id);
3201 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3202 hf_dcerpc_cn_cancel_count, NULL);
3206 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3207 hf_dcerpc_cn_status, &status);
3209 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3210 pinfo->dcectxid = ctx_id;
3211 pinfo->dcetransporttype = transport_type;
3213 if (check_col (pinfo->cinfo, COL_INFO)) {
3214 col_append_fstr (pinfo->cinfo, COL_INFO,
3215 " ctx_id: %u status: %s", ctx_id,
3216 val_to_str(status, reject_status_vals,
3217 "Unknown (0x%08x)"));
3224 * XXX - what if this was set when the connection was set up,
3225 * and we just have a security context?
3227 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3229 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
3230 pinfo->srcport, pinfo->destport, 0);
3232 /* no point in creating one here, really */
3234 dcerpc_matched_key matched_key, *new_matched_key;
3236 /* !!! we can NOT check flags.visited here since this will interact
3237 badly with when SMB handles (i.e. calls the subdissector)
3238 and desegmented pdu's .
3239 Instead we check if this pdu is already in the matched table or not
3241 matched_key.frame = pinfo->fd->num;
3242 matched_key.call_id = hdr->call_id;
3243 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3245 dcerpc_cn_call_key call_key;
3246 dcerpc_call_value *call_value;
3249 call_key.call_id=hdr->call_id;
3250 call_key.smb_fid=dcerpc_get_transport_salt(pinfo, transport_type);
3252 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3253 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3254 *new_matched_key = matched_key;
3255 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3257 if(call_value->rep_frame==0){
3258 call_value->rep_frame=pinfo->fd->num;
3265 int length, reported_length, stub_length;
3269 /* handoff this call */
3271 di->call_id = hdr->call_id;
3272 di->smb_fid = dcerpc_get_transport_salt(pinfo, transport_type);
3273 di->ptype = PDU_FAULT;
3274 di->call_data = value;
3276 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
3277 if(value->req_frame!=0){
3279 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3280 tvb, 0, 0, value->req_frame);
3281 PROTO_ITEM_SET_GENERATED(pi);
3282 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
3283 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
3285 ns.nsecs+=1000000000;
3288 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
3289 PROTO_ITEM_SET_GENERATED(pi);
3292 length = tvb_length_remaining(tvb, offset);
3293 reported_length = tvb_reported_length_remaining(tvb, offset);
3294 stub_length = hdr->frag_len - offset - auth_info.auth_size;
3295 if (length > stub_length)
3296 length = stub_length;
3297 if (reported_length > stub_length)
3298 reported_length = stub_length;
3300 /* If we don't have reassembly enabled, or this packet contains
3301 the entire PDU, or if we don't have all the data in this
3302 fragment, just call the handoff directly if this is the
3303 first fragment or the PDU isn't fragmented. */
3304 if( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
3305 !tvb_bytes_exist(tvb, offset, stub_length) ){
3306 if(hdr->flags&PFC_FIRST_FRAG){
3307 /* First fragment, possibly the only fragment */
3309 * XXX - should there be a third routine for each
3310 * function in an RPC subdissector, to handle
3311 * fault responses? The DCE RPC 1.1 spec says
3312 * three's "stub data" here, which I infer means
3313 * that it's protocol-specific and call-specific.
3315 * It should probably get passed the status code
3316 * as well, as that might be protocol-specific.
3319 if (stub_length > 0) {
3320 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3321 "Fault stub data (%d byte%s)",
3323 plurality(stub_length, "", "s"));
3327 /* PDU is fragmented and this isn't the first fragment */
3328 if (check_col(pinfo->cinfo, COL_INFO)) {
3329 col_append_fstr(pinfo->cinfo, COL_INFO,
3330 " [DCE/RPC fragment]");
3333 if (stub_length > 0) {
3334 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3335 "Fragment data (%d byte%s)",
3337 plurality(stub_length, "", "s"));
3342 /* Reassembly is enabled, the PDU is fragmented, and
3343 we have all the data in the fragment; the first two
3344 of those mean we should attempt reassembly, and the
3345 third means we can attempt reassembly. */
3348 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3349 "Fragment data (%d byte%s)",
3351 plurality(stub_length, "", "s"));
3354 if(hdr->flags&PFC_FIRST_FRAG){ /* FIRST fragment */
3355 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
3356 fragment_add(tvb, offset, pinfo, value->rep_frame,
3357 dcerpc_co_reassemble_table,
3361 fragment_set_tot_len(pinfo, value->rep_frame,
3362 dcerpc_co_reassemble_table, alloc_hint);
3364 if (check_col(pinfo->cinfo, COL_INFO)) {
3365 col_append_fstr(pinfo->cinfo, COL_INFO,
3366 " [DCE/RPC fragment]");
3368 } else if(hdr->flags&PFC_LAST_FRAG){ /* LAST fragment */
3369 if( value->rep_frame ){
3370 fragment_data *fd_head;
3373 tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
3374 dcerpc_co_reassemble_table);
3375 fd_head = fragment_add(tvb, offset, pinfo,
3377 dcerpc_co_reassemble_table,
3383 /* We completed reassembly */
3386 next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
3387 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
3388 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3389 show_fragment_tree(fd_head, &dcerpc_frag_items,
3390 dcerpc_tree, pinfo, next_tvb);
3393 * XXX - should there be a third routine for each
3394 * function in an RPC subdissector, to handle
3395 * fault responses? The DCE RPC 1.1 spec says
3396 * three's "stub data" here, which I infer means
3397 * that it's protocol-specific and call-specific.
3399 * It should probably get passed the status code
3400 * as well, as that might be protocol-specific.
3404 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3405 "Fault stub data (%d byte%s)",
3407 plurality(stub_length, "", "s"));
3411 /* Reassembly not complete - some fragments
3413 if (check_col(pinfo->cinfo, COL_INFO)) {
3414 col_append_fstr(pinfo->cinfo, COL_INFO,
3415 " [DCE/RPC fragment]");
3419 } else { /* MIDDLE fragment(s) */
3420 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
3422 tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
3423 dcerpc_co_reassemble_table);
3424 fragment_add(tvb, offset, pinfo, value->rep_frame,
3425 dcerpc_co_reassemble_table,
3430 if (check_col(pinfo->cinfo, COL_INFO)) {
3431 col_append_fstr(pinfo->cinfo, COL_INFO,
3432 " [DCE/RPC fragment]");
3441 * DCERPC dissector for connection oriented calls.
3442 * We use transport type to later multiplex between what kind of
3443 * pinfo->private_data structure to expect.
3446 dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
3447 proto_tree *tree, gboolean can_desegment, int *pkt_len,
3450 static const guint8 nulls[4] = { 0 };
3453 proto_item *ti = NULL;
3454 proto_item *tf = NULL;
3455 proto_tree *dcerpc_tree = NULL;
3456 proto_tree *cn_flags_tree = NULL;
3457 proto_tree *drep_tree = NULL;
3458 e_dce_cn_common_hdr_t hdr;
3459 dcerpc_auth_info auth_info;
3462 * when done over nbt, dcerpc requests are padded with 4 bytes of null
3463 * data for some reason.
3465 * XXX - if that's always the case, the right way to do this would
3466 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
3467 * the 4 bytes of null padding, and make that the dissector
3468 * used for "netbios".
3470 if (tvb_memeql (tvb, offset, nulls, 4) == 0) {
3480 * Check if this looks like a C/O DCERPC call
3482 if (!tvb_bytes_exist (tvb, offset, sizeof (hdr))) {
3483 return FALSE; /* not enough information to check */
3485 start_offset = offset;
3486 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
3487 if (hdr.rpc_ver != 5)
3489 hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
3490 if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
3492 hdr.ptype = tvb_get_guint8 (tvb, offset++);
3496 hdr.flags = tvb_get_guint8 (tvb, offset++);
3497 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
3498 offset += sizeof (hdr.drep);
3500 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3502 hdr.auth_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3504 hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3507 if (can_desegment && pinfo->can_desegment
3508 && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
3509 pinfo->desegment_offset = start_offset;
3510 pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, start_offset);
3511 *pkt_len = 0; /* desegmentation required */
3515 if (check_col (pinfo->cinfo, COL_PROTOCOL))
3516 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
3517 if (check_col (pinfo->cinfo, COL_INFO))
3518 col_add_fstr (pinfo->cinfo, COL_INFO, "%s: call_id: %u",
3519 pckt_vals[hdr.ptype].strptr, hdr.call_id);
3522 offset = start_offset;
3523 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE);
3525 dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
3527 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver);
3528 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset++, 1, hdr.rpc_ver_minor);
3529 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype);
3530 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
3531 cn_flags_tree = proto_item_add_subtree (tf, ett_dcerpc_cn_flags);
3532 if (cn_flags_tree) {
3533 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
3534 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
3535 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
3536 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
3537 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
3538 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
3539 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
3540 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
3544 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
3545 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
3547 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
3548 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
3549 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
3551 offset += sizeof (hdr.drep);
3553 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
3556 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
3559 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
3564 * None of the stuff done above should throw an exception, because
3565 * we would have rejected this as "not DCE RPC" if we didn't have all
3566 * of it. (XXX - perhaps we should request reassembly if we have
3567 * enough of the header to consider it DCE RPC but not enough to
3568 * get the fragment length; in that case the stuff still wouldn't
3569 * throw an exception.)
3571 * The rest of the stuff might, so return the PDU length to our caller.
3572 * XXX - should we construct a tvbuff containing only the PDU and
3573 * use that? Or should we have separate "is this a DCE RPC PDU",
3574 * "how long is it", and "dissect it" routines - which might let us
3575 * do most of the work in "tcp_dissect_pdus()"?
3577 if (pkt_len != NULL)
3578 *pkt_len = hdr.frag_len + padding;
3581 * Packet type specific stuff is next.
3583 switch (hdr.ptype) {
3586 dissect_dcerpc_cn_bind (tvb, offset, pinfo, dcerpc_tree, &hdr, transport_type);
3591 dissect_dcerpc_cn_bind_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3596 * Nothing after the common header other than credentials.
3598 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, TRUE,
3603 dissect_dcerpc_cn_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, transport_type);
3607 dissect_dcerpc_cn_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, transport_type);
3611 dissect_dcerpc_cn_fault (tvb, offset, pinfo, dcerpc_tree, &hdr, transport_type);
3615 dissect_dcerpc_cn_bind_nak (tvb, offset, pinfo, dcerpc_tree, &hdr);
3621 * Nothing after the common header other than an authentication
3624 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
3630 * Nothing after the common header, not even an authentication
3636 /* might as well dissect the auth info */
3637 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
3645 * DCERPC dissector for connection oriented calls over packet-oriented
3649 dissect_dcerpc_cn_pk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3652 * Only one PDU per transport packet, and only one transport
3655 if (!dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE, NULL, DCE_TRANSPORT_UNKNOWN)) {
3657 * It wasn't a DCERPC PDU.
3669 * DCERPC dissector for connection oriented calls over byte-stream
3671 * we need to distinguish here between SMB and non-TCP (more in the future?)
3672 * to be able to know what kind of private_data structure to expect.
3675 dissect_dcerpc_cn_bs_body (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int transport_type)
3677 volatile int offset = 0;
3679 volatile gboolean is_dcerpc_pdu;
3680 volatile gboolean ret = FALSE;
3683 * There may be multiple PDUs per transport packet; keep
3686 while (tvb_reported_length_remaining(tvb, offset) != 0) {
3688 * Catch ReportedBoundsError, so that even if the stub data is bad,
3689 * we don't abort the full DCE RPC dissection - there might be more
3690 * than one DCE RPC PDU in the data being dissected.
3692 * If we get BoundsError, it means the frame was cut short by a
3693 * snapshot length, so there's nothing more to dissect; just
3694 * re-throw that exception.
3696 is_dcerpc_pdu = FALSE;
3698 is_dcerpc_pdu = dissect_dcerpc_cn (tvb, offset, pinfo, tree,
3699 dcerpc_cn_desegment, &pdu_len,
3701 } CATCH(BoundsError) {
3703 } CATCH(ReportedBoundsError) {
3704 show_reported_bounds_error(tvb, pinfo, tree);
3707 if (!is_dcerpc_pdu) {
3715 * Well, we've seen at least one DCERPC PDU.
3721 * Desegmentation required - bail now.
3727 * Step to the next PDU.
3735 dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3737 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree, DCE_TRANSPORT_UNKNOWN);
3741 dissect_dcerpc_cn_smbpipe (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3743 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree, DCE_CN_TRANSPORT_SMBPIPE);
3749 dissect_dcerpc_dg_auth (tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
3750 e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
3752 proto_item *ti = NULL;
3753 proto_tree *auth_tree = NULL;
3754 guint8 protection_level;
3757 * Initially set "*auth_level_p" to -1 to indicate that we haven't
3758 * yet seen any authentication level information.
3760 if (auth_level_p != NULL)
3764 * The authentication information is at the *end* of the PDU; in
3765 * request and response PDUs, the request and response stub data
3768 * If the full packet is here, and there's data past the end of the
3769 * packet body, then dissect the auth info.
3771 offset += hdr->frag_len;
3772 if (tvb_length_remaining(tvb, offset) > 0) {
3773 switch (hdr->auth_proto) {
3775 case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
3776 ti = proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Kerberos authentication verifier");
3777 auth_tree = proto_item_add_subtree (ti, ett_dcerpc_krb5_auth_verf);
3778 protection_level = tvb_get_guint8 (tvb, offset);
3779 if (auth_level_p != NULL)
3780 *auth_level_p = protection_level;
3781 proto_tree_add_uint (auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
3783 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, FALSE);
3785 if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
3786 offset += 6; /* 6 bytes of padding */
3788 offset += 2; /* 6 bytes of padding */
3789 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, FALSE);
3794 proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Authentication verifier");
3801 dissect_dcerpc_dg_cancel_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
3802 proto_tree *dcerpc_tree,
3803 e_dce_dg_common_hdr_t *hdr)
3807 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3808 hdr->drep, hf_dcerpc_dg_cancel_vers,
3814 /* The only version we know about */
3815 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3816 hdr->drep, hf_dcerpc_dg_cancel_id,
3818 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
3819 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
3826 dissect_dcerpc_dg_cancel (tvbuff_t *tvb, int offset, packet_info *pinfo,
3827 proto_tree *dcerpc_tree,
3828 e_dce_dg_common_hdr_t *hdr)
3832 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3833 hdr->drep, hf_dcerpc_dg_cancel_vers,
3839 /* The only version we know about */
3840 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3841 hdr->drep, hf_dcerpc_dg_cancel_id,
3843 /* XXX - are NDR booleans 32 bits? */
3845 /* XXX - the RPC reference in chapter: "the cancel PDU" doesn't mention
3846 the accepting_cancels field (it's only in the cancel_ack PDU)! */
3847 /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3848 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
3855 dissect_dcerpc_dg_fack (tvbuff_t *tvb, int offset, packet_info *pinfo,
3856 proto_tree *dcerpc_tree,
3857 e_dce_dg_common_hdr_t *hdr)
3864 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
3865 hdr->drep, hf_dcerpc_dg_fack_vers,
3872 case 0: /* The only version documented in the DCE RPC 1.1 spec */
3873 case 1: /* This appears to be the same */
3874 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
3875 hdr->drep, hf_dcerpc_dg_fack_window_size,
3877 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3878 hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
3880 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3881 hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
3883 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
3884 hdr->drep, hf_dcerpc_dg_fack_serial_num,
3886 if (check_col (pinfo->cinfo, COL_INFO)) {
3887 col_append_fstr (pinfo->cinfo, COL_INFO, " serial: %u",
3890 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
3891 hdr->drep, hf_dcerpc_dg_fack_selack_len,
3893 for (i = 0; i < selack_len; i++) {
3894 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3895 hdr->drep, hf_dcerpc_dg_fack_selack,
3904 dissect_dcerpc_dg_reject_fault (tvbuff_t *tvb, int offset, packet_info *pinfo,
3905 proto_tree *dcerpc_tree,
3906 e_dce_dg_common_hdr_t *hdr)
3910 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3911 hdr->drep, hf_dcerpc_dg_status,
3914 if (check_col (pinfo->cinfo, COL_INFO)) {
3915 col_append_fstr (pinfo->cinfo, COL_INFO,
3917 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
3922 dissect_dcerpc_dg_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
3923 proto_tree *dcerpc_tree, proto_tree *tree,
3924 e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
3926 int length, reported_length, stub_length;
3927 gboolean save_fragmented;
3928 fragment_data *fd_head;
3932 if (check_col (pinfo->cinfo, COL_INFO))
3933 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u len: %u",
3934 di->call_data->opnum, hdr->frag_len );
3936 length = tvb_length_remaining (tvb, offset);
3937 reported_length = tvb_reported_length_remaining (tvb, offset);
3938 stub_length = hdr->frag_len;
3939 if (length > stub_length)
3940 length = stub_length;
3941 if (reported_length > stub_length)
3942 reported_length = stub_length;
3944 save_fragmented = pinfo->fragmented;
3946 /* If we don't have reassembly enabled, or this packet contains
3947 the entire PDU, or if this is a short frame (or a frame
3948 not reassembled at a lower layer) that doesn't include all
3949 the data in the fragment, just call the handoff directly if
3950 this is the first fragment or the PDU isn't fragmented. */
3951 if( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
3952 !tvb_bytes_exist(tvb, offset, stub_length) ){
3953 if(hdr->frag_num == 0) {
3956 /* First fragment, possibly the only fragment */
3959 * XXX - authentication info?
3961 pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
3962 next_tvb = tvb_new_subset (tvb, offset, length,
3964 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
3965 next_tvb, hdr->drep, di, NULL);
3967 /* PDU is fragmented and this isn't the first fragment */
3968 if (check_col(pinfo->cinfo, COL_INFO)) {
3969 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
3973 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3974 "Fragment data (%d byte%s)",
3976 plurality(stub_length, "", "s"));
3981 /* Reassembly is enabled, the PDU is fragmented, and
3982 we have all the data in the fragment; the first two
3983 of those mean we should attempt reassembly, and the
3984 third means we can attempt reassembly. */
3987 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3988 "Fragment data (%d byte%s)", stub_length,
3989 plurality(stub_length, "", "s"));
3993 fd_head = fragment_add_dcerpc(tvb, offset, pinfo,
3994 hdr->seqnum, &hdr->act_id, dcerpc_cl_reassemble_table,
3995 hdr->frag_num, stub_length,
3996 !(hdr->flags1 & PFCL1_LASTFRAG));
3997 if (fd_head != NULL) {
3998 /* We completed reassembly... */
3999 if(pinfo->fd->num==fd_head->reassembled_in) {
4000 /* ...and this is the reassembled RPC PDU */
4001 next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
4002 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
4003 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
4004 show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
4005 dcerpc_tree, pinfo, next_tvb);
4008 * XXX - authentication info?
4010 pinfo->fragmented = FALSE;
4011 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
4012 next_tvb, hdr->drep, di, NULL);
4014 /* ...and this isn't the reassembled RPC PDU */
4015 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
4016 tvb, 0, 0, fd_head->reassembled_in);
4017 PROTO_ITEM_SET_GENERATED(pi);
4018 if (check_col(pinfo->cinfo, COL_INFO)) {
4019 col_append_fstr(pinfo->cinfo, COL_INFO,
4020 " [DCE/RPC fragment, reas: #%u]", fd_head->reassembled_in);
4024 /* Reassembly isn't completed yet */
4025 if (check_col(pinfo->cinfo, COL_INFO)) {
4026 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
4030 pinfo->fragmented = save_fragmented;
4034 dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo,
4035 proto_tree *dcerpc_tree, proto_tree *tree,
4036 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4039 dcerpc_call_value *value, v;
4040 dcerpc_matched_key matched_key, *new_matched_key;
4044 if(!(pinfo->fd->flags.visited)){
4045 dcerpc_call_value *call_value;
4046 dcerpc_dg_call_key *call_key;
4048 call_key=g_mem_chunk_alloc (dcerpc_dg_call_key_chunk);
4049 call_key->conv=conv;
4050 call_key->seqnum=hdr->seqnum;
4051 call_key->act_id=hdr->act_id;
4053 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
4054 call_value->uuid = hdr->if_id;
4055 call_value->ver = hdr->if_ver;
4056 call_value->opnum = hdr->opnum;
4057 call_value->req_frame=pinfo->fd->num;
4058 call_value->req_time.secs=pinfo->fd->abs_secs;
4059 call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000;
4060 call_value->rep_frame=0;
4061 call_value->max_ptr=0;
4062 call_value->private_data = NULL;
4063 g_hash_table_insert (dcerpc_dg_calls, call_key, call_value);
4065 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
4066 new_matched_key->frame = pinfo->fd->num;
4067 new_matched_key->call_id = hdr->seqnum;
4068 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
4071 matched_key.frame = pinfo->fd->num;
4072 matched_key.call_id = hdr->seqnum;
4073 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
4075 v.uuid = hdr->if_id;
4076 v.ver = hdr->if_ver;
4077 v.opnum = hdr->opnum;
4078 v.req_frame = pinfo->fd->num;
4081 v.private_data=NULL;
4086 di->call_id = hdr->seqnum;
4088 di->ptype = PDU_REQ;
4089 di->call_data = value;
4091 if(value->rep_frame!=0){
4092 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
4093 tvb, 0, 0, value->rep_frame);
4094 PROTO_ITEM_SET_GENERATED(pi);
4096 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
4100 dissect_dcerpc_dg_resp (tvbuff_t *tvb, int offset, packet_info *pinfo,
4101 proto_tree *dcerpc_tree, proto_tree *tree,
4102 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4105 dcerpc_call_value *value, v;
4106 dcerpc_matched_key matched_key, *new_matched_key;
4110 if(!(pinfo->fd->flags.visited)){
4111 dcerpc_call_value *call_value;
4112 dcerpc_dg_call_key call_key;
4115 call_key.seqnum=hdr->seqnum;
4116 call_key.act_id=hdr->act_id;
4118 if((call_value=g_hash_table_lookup(dcerpc_dg_calls, &call_key))){
4119 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
4120 new_matched_key->frame = pinfo->fd->num;
4121 new_matched_key->call_id = hdr->seqnum;
4122 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
4123 if(call_value->rep_frame==0){
4124 call_value->rep_frame=pinfo->fd->num;
4129 matched_key.frame = pinfo->fd->num;
4130 matched_key.call_id = hdr->seqnum;
4131 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
4133 v.uuid = hdr->if_id;
4134 v.ver = hdr->if_ver;
4135 v.opnum = hdr->opnum;
4137 v.rep_frame=pinfo->fd->num;
4138 v.private_data=NULL;
4145 di->ptype = PDU_RESP;
4146 di->call_data = value;
4148 if(value->req_frame!=0){
4150 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4151 tvb, 0, 0, value->req_frame);
4152 PROTO_ITEM_SET_GENERATED(pi);
4153 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
4154 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
4156 ns.nsecs+=1000000000;
4159 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
4160 PROTO_ITEM_SET_GENERATED(pi);
4162 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
4166 * DCERPC dissector for connectionless calls
4169 dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4171 proto_item *ti = NULL;
4172 proto_item *tf = NULL;
4173 proto_tree *dcerpc_tree = NULL;
4174 proto_tree *dg_flags1_tree = NULL;
4175 proto_tree *dg_flags2_tree = NULL;
4176 proto_tree *drep_tree = NULL;
4177 e_dce_dg_common_hdr_t hdr;
4179 conversation_t *conv;
4181 char uuid_str[DCERPC_UUID_STR_LEN];
4185 * Check if this looks like a CL DCERPC call. All dg packets
4186 * have an 80 byte header on them. Which starts with
4187 * version (4), pkt_type.
4189 if (!tvb_bytes_exist (tvb, 0, sizeof (hdr))) {
4192 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
4193 if (hdr.rpc_ver != 4)
4195 hdr.ptype = tvb_get_guint8 (tvb, offset++);
4199 if (check_col (pinfo->cinfo, COL_PROTOCOL))
4200 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
4201 if (check_col (pinfo->cinfo, COL_INFO))
4202 col_add_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
4204 hdr.flags1 = tvb_get_guint8 (tvb, offset++);
4205 hdr.flags2 = tvb_get_guint8 (tvb, offset++);
4206 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
4207 offset += sizeof (hdr.drep);
4208 hdr.serial_hi = tvb_get_guint8 (tvb, offset++);
4209 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.obj_id);
4211 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.if_id);
4213 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.act_id);
4215 hdr.server_boot = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4217 hdr.if_ver = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4219 hdr.seqnum = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4221 hdr.opnum = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4223 hdr.ihint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4225 hdr.ahint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4227 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4229 hdr.frag_num = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4231 hdr.auth_proto = tvb_get_guint8 (tvb, offset++);
4232 hdr.serial_lo = tvb_get_guint8 (tvb, offset++);
4235 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, -1, FALSE);
4237 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
4243 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
4247 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
4251 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
4252 dg_flags1_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags1);
4253 if (dg_flags1_tree) {
4254 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
4255 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
4256 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
4257 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
4258 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
4259 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
4260 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
4261 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
4267 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
4268 dg_flags2_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags2);
4269 if (dg_flags2_tree) {
4270 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
4271 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
4272 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
4273 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
4274 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
4275 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
4276 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
4277 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
4283 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
4284 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
4286 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
4287 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
4288 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
4291 offset += sizeof (hdr.drep);
4294 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
4298 /* XXX - use "dissect_ndr_uuid_t()"? */
4299 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
4300 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
4301 hdr.obj_id.Data1, hdr.obj_id.Data2, hdr.obj_id.Data3,
4302 hdr.obj_id.Data4[0],
4303 hdr.obj_id.Data4[1],
4304 hdr.obj_id.Data4[2],
4305 hdr.obj_id.Data4[3],
4306 hdr.obj_id.Data4[4],
4307 hdr.obj_id.Data4[5],
4308 hdr.obj_id.Data4[6],
4309 hdr.obj_id.Data4[7]);
4310 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
4311 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
4312 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
4313 offset, 16, uuid_str, "Object UUID: %s", uuid_str);
4318 /* XXX - use "dissect_ndr_uuid_t()"? */
4319 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
4320 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
4321 hdr.if_id.Data1, hdr.if_id.Data2, hdr.if_id.Data3,
4329 hdr.if_id.Data4[7]);
4330 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
4331 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
4332 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
4333 offset, 16, uuid_str, "Interface: %s", uuid_str);
4338 /* XXX - use "dissect_ndr_uuid_t()"? */
4339 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
4340 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
4341 hdr.act_id.Data1, hdr.act_id.Data2, hdr.act_id.Data3,
4342 hdr.act_id.Data4[0],
4343 hdr.act_id.Data4[1],
4344 hdr.act_id.Data4[2],
4345 hdr.act_id.Data4[3],
4346 hdr.act_id.Data4[4],
4347 hdr.act_id.Data4[5],
4348 hdr.act_id.Data4[6],
4349 hdr.act_id.Data4[7]);
4350 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
4351 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
4352 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
4353 offset, 16, uuid_str, "Activity: %s", uuid_str);
4358 nstime_t server_boot;
4360 server_boot.secs = hdr.server_boot;
4361 server_boot.nsecs = 0;
4363 if (hdr.server_boot == 0)
4364 proto_tree_add_time_format (dcerpc_tree, hf_dcerpc_dg_server_boot,
4365 tvb, offset, 4, &server_boot,
4366 "Server boot time: Unknown (0)");
4368 proto_tree_add_time (dcerpc_tree, hf_dcerpc_dg_server_boot,
4369 tvb, offset, 4, &server_boot);
4374 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
4378 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
4379 if (check_col (pinfo->cinfo, COL_INFO)) {
4380 col_append_fstr (pinfo->cinfo, COL_INFO, ": seq: %u", hdr.seqnum);
4385 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
4389 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
4393 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
4397 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
4401 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
4402 if (check_col (pinfo->cinfo, COL_INFO)) {
4403 if (hdr.flags1 & PFCL1_FRAG) {
4404 /* Fragmented - put the fragment number into the Info column */
4405 col_append_fstr (pinfo->cinfo, COL_INFO, " frag: %u",
4412 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
4416 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
4417 if (check_col (pinfo->cinfo, COL_INFO)) {
4418 if (hdr.flags1 & PFCL1_FRAG) {
4419 /* Fragmented - put the serial number into the Info column */
4420 col_append_fstr (pinfo->cinfo, COL_INFO, " serial: %u",
4421 (hdr.serial_hi << 8) | hdr.serial_lo);
4428 * XXX - for Kerberos, we get a protection level; if it's
4429 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
4432 dissect_dcerpc_dg_auth (tvb, offset, dcerpc_tree, &hdr,
4437 * keeping track of the conversation shouldn't really be necessary
4438 * for connectionless packets, because everything we need to know
4439 * to dissect is in the header for each packet. Unfortunately,
4440 * Microsoft's implementation is buggy and often puts the
4441 * completely wrong if_id in the header. go figure. So, keep
4442 * track of the seqnum and use that if possible. Note: that's not
4443 * completely correct. It should really be done based on both the
4444 * activity_id and seqnum. I haven't seen anywhere that it would
4445 * make a difference, but for future reference...
4447 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
4448 pinfo->srcport, pinfo->destport, 0);
4450 conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
4451 pinfo->srcport, pinfo->destport, 0);
4455 * Packet type specific stuff is next.
4458 switch (hdr.ptype) {
4460 case PDU_CANCEL_ACK:
4461 /* Body is optional */
4462 /* XXX - we assume "frag_len" is the length of the body */
4463 if (hdr.frag_len != 0)
4464 dissect_dcerpc_dg_cancel_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
4469 * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
4470 * but in at least one capture none of the Cl_cancel PDUs had a
4473 /* XXX - we assume "frag_len" is the length of the body */
4474 if (hdr.frag_len != 0)
4475 dissect_dcerpc_dg_cancel (tvb, offset, pinfo, dcerpc_tree, &hdr);
4479 /* Body is optional; if present, it's the same as PDU_FACK */
4480 /* XXX - we assume "frag_len" is the length of the body */
4481 if (hdr.frag_len != 0)
4482 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
4486 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
4491 dissect_dcerpc_dg_reject_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
4495 dissect_dcerpc_dg_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
4499 dissect_dcerpc_dg_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
4502 /* these requests have no body */
4514 dcerpc_init_protocol (void)
4516 /* structures and data for BIND */
4518 g_hash_table_destroy (dcerpc_binds);
4520 dcerpc_binds = g_hash_table_new (dcerpc_bind_hash, dcerpc_bind_equal);
4522 if (dcerpc_bind_key_chunk){
4523 g_mem_chunk_destroy (dcerpc_bind_key_chunk);
4525 dcerpc_bind_key_chunk = g_mem_chunk_new ("dcerpc_bind_key_chunk",
4526 sizeof (dcerpc_bind_key),
4527 200 * sizeof (dcerpc_bind_key),
4529 if (dcerpc_bind_value_chunk){
4530 g_mem_chunk_destroy (dcerpc_bind_value_chunk);
4532 dcerpc_bind_value_chunk = g_mem_chunk_new ("dcerpc_bind_value_chunk",
4533 sizeof (dcerpc_bind_value),
4534 200 * sizeof (dcerpc_bind_value),
4536 /* structures and data for CALL */
4537 if (dcerpc_cn_calls){
4538 g_hash_table_destroy (dcerpc_cn_calls);
4540 dcerpc_cn_calls = g_hash_table_new (dcerpc_cn_call_hash, dcerpc_cn_call_equal);
4541 if (dcerpc_dg_calls){
4542 g_hash_table_destroy (dcerpc_dg_calls);
4544 dcerpc_dg_calls = g_hash_table_new (dcerpc_dg_call_hash, dcerpc_dg_call_equal);
4545 if (dcerpc_cn_call_key_chunk){
4546 g_mem_chunk_destroy (dcerpc_cn_call_key_chunk);
4548 dcerpc_cn_call_key_chunk = g_mem_chunk_new ("dcerpc_cn_call_key_chunk",
4549 sizeof (dcerpc_cn_call_key),
4550 200 * sizeof (dcerpc_cn_call_key),
4552 if (dcerpc_dg_call_key_chunk){
4553 g_mem_chunk_destroy (dcerpc_dg_call_key_chunk);
4555 dcerpc_dg_call_key_chunk = g_mem_chunk_new ("dcerpc_dg_call_key_chunk",
4556 sizeof (dcerpc_dg_call_key),
4557 200 * sizeof (dcerpc_dg_call_key),
4560 if (dcerpc_call_value_chunk){
4561 g_mem_chunk_destroy (dcerpc_call_value_chunk);
4563 dcerpc_call_value_chunk = g_mem_chunk_new ("dcerpc_call_value_chunk",
4564 sizeof (dcerpc_call_value),
4565 200 * sizeof (dcerpc_call_value),
4568 /* structure and data for MATCHED */
4569 if (dcerpc_matched){
4570 g_hash_table_destroy (dcerpc_matched);
4572 dcerpc_matched = g_hash_table_new (dcerpc_matched_hash, dcerpc_matched_equal);
4573 if (dcerpc_matched_key_chunk){
4574 g_mem_chunk_destroy (dcerpc_matched_key_chunk);
4576 dcerpc_matched_key_chunk = g_mem_chunk_new ("dcerpc_matched_key_chunk",
4577 sizeof (dcerpc_matched_key),
4578 200 * sizeof (dcerpc_matched_key),
4581 /* call the registered hooks */
4582 g_hook_list_invoke(&dcerpc_hooks_init_protos, FALSE /* not may_recurse */);
4586 proto_register_dcerpc (void)
4588 static hf_register_info hf[] = {
4589 { &hf_dcerpc_request_in,
4590 { "Request in frame", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE,
4591 NULL, 0, "This packet is a response to the packet with this number", HFILL }},
4592 { &hf_dcerpc_response_in,
4593 { "Response in frame", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
4594 NULL, 0, "This packet will be responded in the packet with this number", HFILL }},
4595 { &hf_dcerpc_referent_id,
4596 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
4597 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
4599 { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4600 { &hf_dcerpc_ver_minor,
4601 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4602 { &hf_dcerpc_packet_type,
4603 { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS (pckt_vals), 0x0, "", HFILL }},
4604 { &hf_dcerpc_cn_flags,
4605 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4606 { &hf_dcerpc_cn_flags_first_frag,
4607 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_FIRST_FRAG, "", HFILL }},
4608 { &hf_dcerpc_cn_flags_last_frag,
4609 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_LAST_FRAG, "", HFILL }},
4610 { &hf_dcerpc_cn_flags_cancel_pending,
4611 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_PENDING_CANCEL, "", HFILL }},
4612 { &hf_dcerpc_cn_flags_reserved,
4613 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_RESERVED_1, "", HFILL }},
4614 { &hf_dcerpc_cn_flags_mpx,
4615 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_CONC_MPX, "", HFILL }},
4616 { &hf_dcerpc_cn_flags_dne,
4617 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_DID_NOT_EXECUTE, "", HFILL }},
4618 { &hf_dcerpc_cn_flags_maybe,
4619 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_MAYBE, "", HFILL }},
4620 { &hf_dcerpc_cn_flags_object,
4621 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_OBJECT_UUID, "", HFILL }},
4623 { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
4624 { &hf_dcerpc_drep_byteorder,
4625 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS (drep_byteorder_vals), 0x0, "", HFILL }},
4626 { &hf_dcerpc_drep_character,
4627 { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS (drep_character_vals), 0x0, "", HFILL }},
4628 { &hf_dcerpc_drep_fp,
4629 { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS (drep_fp_vals), 0x0, "", HFILL }},
4630 { &hf_dcerpc_cn_frag_len,
4631 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4632 { &hf_dcerpc_cn_auth_len,
4633 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4634 { &hf_dcerpc_cn_call_id,
4635 { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4636 { &hf_dcerpc_cn_max_xmit,
4637 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4638 { &hf_dcerpc_cn_max_recv,
4639 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4640 { &hf_dcerpc_cn_assoc_group,
4641 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
4642 { &hf_dcerpc_cn_num_ctx_items,
4643 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4644 { &hf_dcerpc_cn_ctx_id,
4645 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4646 { &hf_dcerpc_cn_num_trans_items,
4647 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4648 { &hf_dcerpc_cn_bind_if_id,
4649 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4650 { &hf_dcerpc_cn_bind_if_ver,
4651 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4652 { &hf_dcerpc_cn_bind_if_ver_minor,
4653 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4654 { &hf_dcerpc_cn_bind_trans_id,
4655 { "Transfer Syntax", "dcerpc.cn_bind_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4656 { &hf_dcerpc_cn_bind_trans_ver,
4657 { "Syntax ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4658 { &hf_dcerpc_cn_alloc_hint,
4659 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4660 { &hf_dcerpc_cn_sec_addr_len,
4661 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4662 { &hf_dcerpc_cn_sec_addr,
4663 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, "", HFILL }},
4664 { &hf_dcerpc_cn_num_results,
4665 { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4666 { &hf_dcerpc_cn_ack_result,
4667 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, "", HFILL }},
4668 { &hf_dcerpc_cn_ack_reason,
4669 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, "", HFILL }},
4670 { &hf_dcerpc_cn_ack_trans_id,
4671 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4672 { &hf_dcerpc_cn_ack_trans_ver,
4673 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4674 { &hf_dcerpc_cn_reject_reason,
4675 { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, "", HFILL }},
4676 { &hf_dcerpc_cn_num_protocols,
4677 { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4678 { &hf_dcerpc_cn_protocol_ver_major,
4679 { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4680 { &hf_dcerpc_cn_protocol_ver_minor,
4681 { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4682 { &hf_dcerpc_cn_cancel_count,
4683 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4684 { &hf_dcerpc_cn_status,
4685 { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
4686 { &hf_dcerpc_auth_type,
4687 { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
4688 { &hf_dcerpc_auth_level,
4689 { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS (authn_level_vals), 0x0, "", HFILL }},
4690 { &hf_dcerpc_auth_pad_len,
4691 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4692 { &hf_dcerpc_auth_rsrvd,
4693 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4694 { &hf_dcerpc_auth_ctx_id,
4695 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4696 { &hf_dcerpc_dg_flags1,
4697 { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4698 { &hf_dcerpc_dg_flags1_rsrvd_01,
4699 { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_01, "", HFILL }},
4700 { &hf_dcerpc_dg_flags1_last_frag,
4701 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_LASTFRAG, "", HFILL }},
4702 { &hf_dcerpc_dg_flags1_frag,
4703 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_FRAG, "", HFILL }},
4704 { &hf_dcerpc_dg_flags1_nofack,
4705 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_NOFACK, "", HFILL }},
4706 { &hf_dcerpc_dg_flags1_maybe,
4707 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_MAYBE, "", HFILL }},
4708 { &hf_dcerpc_dg_flags1_idempotent,
4709 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_IDEMPOTENT, "", HFILL }},
4710 { &hf_dcerpc_dg_flags1_broadcast,
4711 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_BROADCAST, "", HFILL }},
4712 { &hf_dcerpc_dg_flags1_rsrvd_80,
4713 { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_80, "", HFILL }},
4714 { &hf_dcerpc_dg_flags2,
4715 { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4716 { &hf_dcerpc_dg_flags2_rsrvd_01,
4717 { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_01, "", HFILL }},
4718 { &hf_dcerpc_dg_flags2_cancel_pending,
4719 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_CANCEL_PENDING, "", HFILL }},
4720 { &hf_dcerpc_dg_flags2_rsrvd_04,
4721 { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_04, "", HFILL }},
4722 { &hf_dcerpc_dg_flags2_rsrvd_08,
4723 { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_08, "", HFILL }},
4724 { &hf_dcerpc_dg_flags2_rsrvd_10,
4725 { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_10, "", HFILL }},
4726 { &hf_dcerpc_dg_flags2_rsrvd_20,
4727 { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_20, "", HFILL }},
4728 { &hf_dcerpc_dg_flags2_rsrvd_40,
4729 { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_40, "", HFILL }},
4730 { &hf_dcerpc_dg_flags2_rsrvd_80,
4731 { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_80, "", HFILL }},
4732 { &hf_dcerpc_dg_serial_lo,
4733 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4734 { &hf_dcerpc_dg_serial_hi,
4735 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4736 { &hf_dcerpc_dg_ahint,
4737 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
4738 { &hf_dcerpc_dg_ihint,
4739 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
4740 { &hf_dcerpc_dg_frag_len,
4741 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4742 { &hf_dcerpc_dg_frag_num,
4743 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4744 { &hf_dcerpc_dg_auth_proto,
4745 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
4746 { &hf_dcerpc_dg_seqnum,
4747 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4748 { &hf_dcerpc_dg_server_boot,
4749 { "Server boot time", "dcerpc.dg_server_boot", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0, "", HFILL }},
4750 { &hf_dcerpc_dg_if_ver,
4751 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4752 { &hf_dcerpc_krb5_av_prot_level,
4753 { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, "", HFILL }},
4754 { &hf_dcerpc_krb5_av_key_vers_num,
4755 { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4756 { &hf_dcerpc_krb5_av_key_auth_verifier,
4757 { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
4758 { &hf_dcerpc_obj_id,
4759 { "Object", "dcerpc.obj_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4760 { &hf_dcerpc_dg_if_id,
4761 { "Interface", "dcerpc.dg_if_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4762 { &hf_dcerpc_dg_act_id,
4763 { "Activity", "dcerpc.dg_act_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4765 { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4767 { &hf_dcerpc_dg_cancel_vers,
4768 { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4770 { &hf_dcerpc_dg_cancel_id,
4771 { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4773 { &hf_dcerpc_dg_server_accepting_cancels,
4774 { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
4776 { &hf_dcerpc_dg_fack_vers,
4777 { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4779 { &hf_dcerpc_dg_fack_window_size,
4780 { "Window Size", "dcerpc.fack_window_size", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4782 { &hf_dcerpc_dg_fack_max_tsdu,
4783 { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4785 { &hf_dcerpc_dg_fack_max_frag_size,
4786 { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4788 { &hf_dcerpc_dg_fack_serial_num,
4789 { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4791 { &hf_dcerpc_dg_fack_selack_len,
4792 { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4794 { &hf_dcerpc_dg_fack_selack,
4795 { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
4797 { &hf_dcerpc_dg_status,
4798 { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
4800 { &hf_dcerpc_array_max_count,
4801 { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
4803 { &hf_dcerpc_array_offset,
4804 { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
4806 { &hf_dcerpc_array_actual_count,
4807 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
4809 { &hf_dcerpc_array_buffer,
4810 { "Buffer", "dcerpc.array.buffer", FT_BYTES, BASE_NONE, NULL, 0x0, "Buffer: Buffer containing elements of the array", HFILL }},
4813 { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4815 { &hf_dcerpc_fragments,
4816 { "DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
4817 NULL, 0x0, "DCE/RPC Fragments", HFILL }},
4819 { &hf_dcerpc_fragment,
4820 { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM, BASE_NONE,
4821 NULL, 0x0, "DCE/RPC Fragment", HFILL }},
4823 { &hf_dcerpc_fragment_overlap,
4824 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE,
4825 NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
4827 { &hf_dcerpc_fragment_overlap_conflict,
4828 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE,
4829 NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
4831 { &hf_dcerpc_fragment_multiple_tails,
4832 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE,
4833 NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
4835 { &hf_dcerpc_fragment_too_long_fragment,
4836 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE,
4837 NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
4839 { &hf_dcerpc_fragment_error,
4840 { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE,
4841 NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
4844 { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE,
4845 NULL, 0, "Time between Request and Response for DCE-RPC calls", HFILL }},
4847 { &hf_dcerpc_reassembled_in,
4848 { "Reassembled PDU in frame", "dcerpc.reassembled_in", FT_FRAMENUM, BASE_NONE,
4849 NULL, 0x0, "The DCE/RPC PDU is completely reassembled in the packet with this number", HFILL }},
4851 { &hf_dcerpc_unknown_if_id,
4852 { "Unknown DCERPC interface id", "dcerpc.unknown_if_id", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
4854 static gint *ett[] = {
4856 &ett_dcerpc_cn_flags,
4858 &ett_dcerpc_cn_iface,
4860 &ett_dcerpc_dg_flags1,
4861 &ett_dcerpc_dg_flags2,
4862 &ett_dcerpc_pointer_data,
4864 &ett_dcerpc_fragments,
4865 &ett_dcerpc_fragment,
4866 &ett_dcerpc_krb5_auth_verf,
4868 module_t *dcerpc_module;
4870 proto_dcerpc = proto_register_protocol ("DCE RPC", "DCERPC", "dcerpc");
4871 proto_register_field_array (proto_dcerpc, hf, array_length (hf));
4872 proto_register_subtree_array (ett, array_length (ett));
4873 register_init_routine (dcerpc_init_protocol);
4874 dcerpc_module = prefs_register_protocol (proto_dcerpc, NULL);
4875 prefs_register_bool_preference (dcerpc_module,
4877 "Reassemble DCE/RPC messages spanning multiple TCP segments",
4878 "Whether the DCE/RPC dissector should reassemble messages spanning multiple TCP segments."
4879 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
4880 &dcerpc_cn_desegment);
4881 prefs_register_bool_preference (dcerpc_module,
4882 "reassemble_dcerpc",
4883 "Reassemble DCE/RPC fragments",
4884 "Whether the DCE/RPC dissector should reassemble fragmented DCE/RPC PDUs",
4885 &dcerpc_reassemble);
4886 register_init_routine(dcerpc_reassemble_init);
4887 dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
4888 dcerpc_tap=register_tap("dcerpc");
4890 g_hook_list_init(&dcerpc_hooks_init_protos, sizeof(GHook));
4894 proto_reg_handoff_dcerpc (void)
4896 heur_dissector_add ("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
4897 heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
4898 heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
4899 heur_dissector_add ("smb_transact", dissect_dcerpc_cn_smbpipe, proto_dcerpc);
4900 heur_dissector_add ("http", dissect_dcerpc_cn_bs, proto_dcerpc);
4901 dcerpc_smb_init(proto_dcerpc);