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 { 0x1c000001, "nca_s_fault_int_div_by_zero" },
238 { 0x1c000002, "nca_s_fault_addr_error" },
239 { 0x1c000003, "nca_s_fault_fp_div_zero" },
240 { 0x1c000004, "nca_s_fault_fp_underflow" },
241 { 0x1c000005, "nca_s_fault_fp_overflow" },
242 { 0x1c000006, "nca_s_fault_invalid_tag" },
243 { 0x1c000007, "nca_s_fault_invalid_bound" },
244 { 0x1c000008, "nca_rpc_version_mismatch" },
245 { 0x1c000009, "nca_unspec_reject" },
246 { 0x1c00000a, "nca_s_bad_actid" },
247 { 0x1c00000b, "nca_who_are_you_failed" },
248 { 0x1c00000c, "nca_manager_not_entered" },
249 { 0x1c00000d, "nca_s_fault_cancel" },
250 { 0x1c00000e, "nca_s_fault_ill_inst" },
251 { 0x1c00000f, "nca_s_fault_fp_error" },
252 { 0x1c000010, "nca_s_fault_int_overflow" },
253 { 0x1c000014, "nca_s_fault_pipe_empty" },
254 { 0x1c000015, "nca_s_fault_pipe_closed" },
255 { 0x1c000016, "nca_s_fault_pipe_order" },
256 { 0x1c000017, "nca_s_fault_pipe_discipline" },
257 { 0x1c000018, "nca_s_fault_pipe_comm_error" },
258 { 0x1c000019, "nca_s_fault_pipe_memory" },
259 { 0x1c00001a, "nca_s_fault_context_mismatch" },
260 { 0x1c00001b, "nca_s_fault_remote_no_memory" },
261 { 0x1c00001c, "nca_invalid_pres_context_id" },
262 { 0x1c00001d, "nca_unsupported_authn_level" },
263 { 0x1c00001f, "nca_invalid_checksum" },
264 { 0x1c000020, "nca_invalid_crc" },
265 { 0x1c000021, "ncs_s_fault_user_defined" },
266 { 0x1c000022, "nca_s_fault_tx_open_failed" },
267 { 0x1c000023, "nca_s_fault_codeset_conv_error" },
268 { 0x1c000024, "nca_s_fault_object_not_found" },
269 { 0x1c000025, "nca_s_fault_no_client_stub" },
270 { 0x1c010002, "nca_op_rng_error" },
271 { 0x1c010003, "nca_unk_if"},
272 { 0x1c010006, "nca_wrong_boot_time" },
273 { 0x1c010009, "nca_s_you_crashed" },
274 { 0x1c01000b, "nca_proto_error" },
275 { 0x1c010013, "nca_out_args_too_big" },
276 { 0x1c010014, "nca_server_too_busy" },
277 { 0x1c010017, "nca_unsupported_type" },
282 /* we need to keep track of what transport were used, ie what handle we came
283 * in through so we know what kind of pinfo->private_data was passed to us.
285 /* Value of -1 is reserved for "not DCE packet" in packet_info.dcetransporttype. */
286 #define DCE_TRANSPORT_UNKNOWN 0
287 #define DCE_CN_TRANSPORT_SMBPIPE 1
290 static int proto_dcerpc = -1;
293 static int hf_dcerpc_request_in = -1;
294 static int hf_dcerpc_time = -1;
295 static int hf_dcerpc_response_in = -1;
296 static int hf_dcerpc_ver = -1;
297 static int hf_dcerpc_ver_minor = -1;
298 static int hf_dcerpc_packet_type = -1;
299 static int hf_dcerpc_cn_flags = -1;
300 static int hf_dcerpc_cn_flags_first_frag = -1;
301 static int hf_dcerpc_cn_flags_last_frag = -1;
302 static int hf_dcerpc_cn_flags_cancel_pending = -1;
303 static int hf_dcerpc_cn_flags_reserved = -1;
304 static int hf_dcerpc_cn_flags_mpx = -1;
305 static int hf_dcerpc_cn_flags_dne = -1;
306 static int hf_dcerpc_cn_flags_maybe = -1;
307 static int hf_dcerpc_cn_flags_object = -1;
308 static int hf_dcerpc_drep = -1;
309 static int hf_dcerpc_drep_byteorder = -1;
310 static int hf_dcerpc_drep_character = -1;
311 static int hf_dcerpc_drep_fp = -1;
312 static int hf_dcerpc_cn_frag_len = -1;
313 static int hf_dcerpc_cn_auth_len = -1;
314 static int hf_dcerpc_cn_call_id = -1;
315 static int hf_dcerpc_cn_max_xmit = -1;
316 static int hf_dcerpc_cn_max_recv = -1;
317 static int hf_dcerpc_cn_assoc_group = -1;
318 static int hf_dcerpc_cn_num_ctx_items = -1;
319 static int hf_dcerpc_cn_ctx_id = -1;
320 static int hf_dcerpc_cn_num_trans_items = -1;
321 static int hf_dcerpc_cn_bind_if_id = -1;
322 static int hf_dcerpc_cn_bind_if_ver = -1;
323 static int hf_dcerpc_cn_bind_if_ver_minor = -1;
324 static int hf_dcerpc_cn_bind_trans_id = -1;
325 static int hf_dcerpc_cn_bind_trans_ver = -1;
326 static int hf_dcerpc_cn_alloc_hint = -1;
327 static int hf_dcerpc_cn_sec_addr_len = -1;
328 static int hf_dcerpc_cn_sec_addr = -1;
329 static int hf_dcerpc_cn_num_results = -1;
330 static int hf_dcerpc_cn_ack_result = -1;
331 static int hf_dcerpc_cn_ack_reason = -1;
332 static int hf_dcerpc_cn_ack_trans_id = -1;
333 static int hf_dcerpc_cn_ack_trans_ver = -1;
334 static int hf_dcerpc_cn_reject_reason = -1;
335 static int hf_dcerpc_cn_num_protocols = -1;
336 static int hf_dcerpc_cn_protocol_ver_major = -1;
337 static int hf_dcerpc_cn_protocol_ver_minor = -1;
338 static int hf_dcerpc_cn_cancel_count = -1;
339 static int hf_dcerpc_cn_status = -1;
340 static int hf_dcerpc_auth_type = -1;
341 static int hf_dcerpc_auth_level = -1;
342 static int hf_dcerpc_auth_pad_len = -1;
343 static int hf_dcerpc_auth_rsrvd = -1;
344 static int hf_dcerpc_auth_ctx_id = -1;
345 static int hf_dcerpc_dg_flags1 = -1;
346 static int hf_dcerpc_dg_flags1_rsrvd_01 = -1;
347 static int hf_dcerpc_dg_flags1_last_frag = -1;
348 static int hf_dcerpc_dg_flags1_frag = -1;
349 static int hf_dcerpc_dg_flags1_nofack = -1;
350 static int hf_dcerpc_dg_flags1_maybe = -1;
351 static int hf_dcerpc_dg_flags1_idempotent = -1;
352 static int hf_dcerpc_dg_flags1_broadcast = -1;
353 static int hf_dcerpc_dg_flags1_rsrvd_80 = -1;
354 static int hf_dcerpc_dg_flags2 = -1;
355 static int hf_dcerpc_dg_flags2_rsrvd_01 = -1;
356 static int hf_dcerpc_dg_flags2_cancel_pending = -1;
357 static int hf_dcerpc_dg_flags2_rsrvd_04 = -1;
358 static int hf_dcerpc_dg_flags2_rsrvd_08 = -1;
359 static int hf_dcerpc_dg_flags2_rsrvd_10 = -1;
360 static int hf_dcerpc_dg_flags2_rsrvd_20 = -1;
361 static int hf_dcerpc_dg_flags2_rsrvd_40 = -1;
362 static int hf_dcerpc_dg_flags2_rsrvd_80 = -1;
363 static int hf_dcerpc_dg_serial_hi = -1;
364 static int hf_dcerpc_obj_id = -1;
365 static int hf_dcerpc_dg_if_id = -1;
366 static int hf_dcerpc_dg_act_id = -1;
367 static int hf_dcerpc_dg_serial_lo = -1;
368 static int hf_dcerpc_dg_ahint = -1;
369 static int hf_dcerpc_dg_ihint = -1;
370 static int hf_dcerpc_dg_frag_len = -1;
371 static int hf_dcerpc_dg_frag_num = -1;
372 static int hf_dcerpc_dg_auth_proto = -1;
373 static int hf_dcerpc_opnum = -1;
374 static int hf_dcerpc_dg_seqnum = -1;
375 static int hf_dcerpc_dg_server_boot = -1;
376 static int hf_dcerpc_dg_if_ver = -1;
377 static int hf_dcerpc_krb5_av_prot_level = -1;
378 static int hf_dcerpc_krb5_av_key_vers_num = -1;
379 static int hf_dcerpc_krb5_av_key_auth_verifier = -1;
380 static int hf_dcerpc_dg_cancel_vers = -1;
381 static int hf_dcerpc_dg_cancel_id = -1;
382 static int hf_dcerpc_dg_server_accepting_cancels = -1;
383 static int hf_dcerpc_dg_fack_vers = -1;
384 static int hf_dcerpc_dg_fack_window_size = -1;
385 static int hf_dcerpc_dg_fack_max_tsdu = -1;
386 static int hf_dcerpc_dg_fack_max_frag_size = -1;
387 static int hf_dcerpc_dg_fack_serial_num = -1;
388 static int hf_dcerpc_dg_fack_selack_len = -1;
389 static int hf_dcerpc_dg_fack_selack = -1;
390 static int hf_dcerpc_dg_status = -1;
391 static int hf_dcerpc_array_max_count = -1;
392 static int hf_dcerpc_array_offset = -1;
393 static int hf_dcerpc_array_actual_count = -1;
394 static int hf_dcerpc_array_buffer = -1;
395 static int hf_dcerpc_op = -1;
396 static int hf_dcerpc_referent_id = -1;
397 static int hf_dcerpc_fragments = -1;
398 static int hf_dcerpc_fragment = -1;
399 static int hf_dcerpc_fragment_overlap = -1;
400 static int hf_dcerpc_fragment_overlap_conflict = -1;
401 static int hf_dcerpc_fragment_multiple_tails = -1;
402 static int hf_dcerpc_fragment_too_long_fragment = -1;
403 static int hf_dcerpc_fragment_error = -1;
404 static int hf_dcerpc_reassembled_in = -1;
405 static int hf_dcerpc_unknown_if_id = -1;
407 static gint ett_dcerpc = -1;
408 static gint ett_dcerpc_cn_flags = -1;
409 static gint ett_dcerpc_cn_ctx = -1;
410 static gint ett_dcerpc_cn_iface = -1;
411 static gint ett_dcerpc_drep = -1;
412 static gint ett_dcerpc_dg_flags1 = -1;
413 static gint ett_dcerpc_dg_flags2 = -1;
414 static gint ett_dcerpc_pointer_data = -1;
415 static gint ett_dcerpc_string = -1;
416 static gint ett_dcerpc_fragments = -1;
417 static gint ett_dcerpc_fragment = -1;
418 static gint ett_dcerpc_krb5_auth_verf = -1;
420 static const fragment_items dcerpc_frag_items = {
421 &ett_dcerpc_fragments,
422 &ett_dcerpc_fragment,
424 &hf_dcerpc_fragments,
426 &hf_dcerpc_fragment_overlap,
427 &hf_dcerpc_fragment_overlap_conflict,
428 &hf_dcerpc_fragment_multiple_tails,
429 &hf_dcerpc_fragment_too_long_fragment,
430 &hf_dcerpc_fragment_error,
436 /* list of hooks to be called when init_protocols is done */
437 GHookList dcerpc_hooks_init_protos;
440 int ResolveWin32UUID(e_uuid_t if_id, char *UUID_NAME, int UUID_NAME_MAX_LEN)
442 char REG_UUID_NAME[MAX_PATH];
444 DWORD UUID_MAX_SIZE = MAX_PATH;
445 char REG_UUID_STR[MAX_PATH];
447 if(UUID_NAME_MAX_LEN < 2)
449 REG_UUID_NAME[0] = '\0';
450 snprintf(REG_UUID_STR, MAX_PATH, "SOFTWARE\\Classes\\Interface\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
451 if_id.Data1, if_id.Data2, if_id.Data3,
452 if_id.Data4[0], if_id.Data4[1],
453 if_id.Data4[2], if_id.Data4[3],
454 if_id.Data4[4], if_id.Data4[5],
455 if_id.Data4[6], if_id.Data4[7]);
456 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCSTR)REG_UUID_STR, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
458 if (RegQueryValueEx(hKey, NULL, NULL, NULL, (LPBYTE)REG_UUID_NAME, &UUID_MAX_SIZE) == ERROR_SUCCESS && UUID_MAX_SIZE <= MAX_PATH)
460 snprintf(UUID_NAME, UUID_NAME_MAX_LEN, "%s", REG_UUID_NAME);
462 return strlen(REG_UUID_NAME);
466 return 0; /* we didn't find anything anyhow. Please don't use the string! */
474 static dcerpc_info di[20];
475 static int di_counter=0;
481 return &di[di_counter];
484 /* try to desegment big DCE/RPC packets over TCP? */
485 static gboolean dcerpc_cn_desegment = TRUE;
487 /* reassemble DCE/RPC fragments */
488 /* reassembly of dcerpc fragments will not work for the case where ONE frame
489 might contain multiple dcerpc fragments for different PDUs.
490 this case would be so unusual/weird so if you got captures like that:
493 static gboolean dcerpc_reassemble = FALSE;
494 static GHashTable *dcerpc_co_reassemble_table = NULL;
495 static GHashTable *dcerpc_cl_reassemble_table = NULL;
498 dcerpc_reassemble_init(void)
500 fragment_table_init(&dcerpc_co_reassemble_table);
501 dcerpc_fragment_table_init(&dcerpc_cl_reassemble_table);
505 * Authentication subdissectors. Used to dissect authentication blobs in
506 * DCERPC binds, requests and responses.
509 typedef struct _dcerpc_auth_subdissector {
512 dcerpc_auth_subdissector_fns auth_fns;
513 } dcerpc_auth_subdissector;
515 static GSList *dcerpc_auth_subdissector_list;
517 static dcerpc_auth_subdissector_fns *get_auth_subdissector_fns(
518 guint8 auth_level, guint8 auth_type)
523 for (i = 0; (data = g_slist_nth_data(dcerpc_auth_subdissector_list, i)); i++) {
524 dcerpc_auth_subdissector *asd = (dcerpc_auth_subdissector *)data;
526 if (asd->auth_level == auth_level &&
527 asd->auth_type == auth_type)
528 return &asd->auth_fns;
534 void register_dcerpc_auth_subdissector(guint8 auth_level, guint8 auth_type,
535 dcerpc_auth_subdissector_fns *fns)
537 dcerpc_auth_subdissector *d;
539 if (get_auth_subdissector_fns(auth_level, auth_type))
542 d = (dcerpc_auth_subdissector *)g_malloc(sizeof(dcerpc_auth_subdissector));
544 d->auth_level = auth_level;
545 d->auth_type = auth_type;
546 memcpy(&d->auth_fns, fns, sizeof(dcerpc_auth_subdissector_fns));
548 dcerpc_auth_subdissector_list = g_slist_append(dcerpc_auth_subdissector_list, d);
551 /* Hand off verifier data to a registered dissector */
553 static void dissect_auth_verf(tvbuff_t *auth_tvb, packet_info *pinfo,
555 dcerpc_auth_subdissector_fns *auth_fns,
556 e_dce_cn_common_hdr_t *hdr,
557 dcerpc_auth_info *auth_info)
559 dcerpc_dissect_fnct_t *volatile fn = NULL;
561 switch (hdr->ptype) {
564 fn = auth_fns->bind_fn;
568 fn = auth_fns->bind_ack_fn;
571 fn = auth_fns->auth3_fn;
574 fn = auth_fns->req_verf_fn;
577 fn = auth_fns->resp_verf_fn;
580 /* Don't know how to handle authentication data in this
584 g_warning("attempt to dissect %s pdu authentication data",
585 val_to_str(hdr->ptype, pckt_vals, "Unknown (%u)"));
590 fn(auth_tvb, 0, pinfo, tree, hdr->drep);
592 proto_tree_add_text(tree, auth_tvb, 0, hdr->auth_len,
594 val_to_str(auth_info->auth_type,
599 /* Hand off payload data to a registered dissector */
601 static tvbuff_t *decode_encrypted_data(tvbuff_t *enc_tvb,
603 dcerpc_auth_subdissector_fns *auth_fns,
605 dcerpc_auth_info *auth_info)
607 dcerpc_decode_data_fnct_t *fn;
610 fn = auth_fns->req_data_fn;
612 fn = auth_fns->resp_data_fn;
615 return fn(enc_tvb, 0, pinfo, auth_info);
624 /* the registered subdissectors */
625 GHashTable *dcerpc_uuids=NULL;
628 dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2)
630 const dcerpc_uuid_key *key1 = (const dcerpc_uuid_key *)k1;
631 const dcerpc_uuid_key *key2 = (const dcerpc_uuid_key *)k2;
632 return ((memcmp (&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
633 && (key1->ver == key2->ver));
637 dcerpc_uuid_hash (gconstpointer k)
639 const dcerpc_uuid_key *key = (const dcerpc_uuid_key *)k;
640 /* This isn't perfect, but the Data1 part of these is almost always
642 return key->uuid.Data1;
646 dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver,
647 dcerpc_sub_dissector *procs, int opnum_hf)
649 dcerpc_uuid_key *key = g_malloc (sizeof (*key));
650 dcerpc_uuid_value *value = g_malloc (sizeof (*value));
651 header_field_info *hf_info;
656 value->proto = find_protocol_by_id(proto);
657 value->proto_id = proto;
659 value->name = proto_get_protocol_short_name (value->proto);
660 value->procs = procs;
661 value->opnum_hf = opnum_hf;
663 g_hash_table_insert (dcerpc_uuids, key, value);
665 hf_info = proto_registrar_get_nth(opnum_hf);
666 hf_info->strings = value_string_from_subdissectors(procs);
669 /* Function to find the name of a registered protocol
670 * or NULL if the protocol/version is not known to ethereal.
673 dcerpc_get_proto_name(e_uuid_t *uuid, guint16 ver)
676 dcerpc_uuid_value *sub_proto;
680 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
683 return sub_proto->name;
686 /* Function to find the opnum hf-field of a registered protocol
687 * or -1 if the protocol/version is not known to ethereal.
690 dcerpc_get_proto_hf_opnum(e_uuid_t *uuid, guint16 ver)
693 dcerpc_uuid_value *sub_proto;
697 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
700 return sub_proto->opnum_hf;
703 /* Create a value_string consisting of DCERPC opnum and name from a
704 subdissector array. */
706 value_string *value_string_from_subdissectors(dcerpc_sub_dissector *sd)
708 value_string *vs = NULL;
712 for (i = 0; sd[i].name; i++) {
714 vs[i].value = sd[i].num;
715 vs[i].strptr = sd[i].name;
721 vs = g_malloc((num_sd + 1) * sizeof(value_string));
725 vs[num_sd].value = 0;
726 vs[num_sd].strptr = NULL;
731 /* Function to find the subdissector table of a registered protocol
732 * or NULL if the protocol/version is not known to ethereal.
734 dcerpc_sub_dissector *
735 dcerpc_get_proto_sub_dissector(e_uuid_t *uuid, guint16 ver)
738 dcerpc_uuid_value *sub_proto;
742 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
745 return sub_proto->procs;
750 * To keep track of ctx_id mappings.
752 * Everytime we see a bind call we update this table.
753 * Note that we always specify a SMB FID. For non-SMB transports this
756 static GHashTable *dcerpc_binds=NULL;
758 typedef struct _dcerpc_bind_key {
759 conversation_t *conv;
764 typedef struct _dcerpc_bind_value {
769 static GMemChunk *dcerpc_bind_key_chunk=NULL;
770 static GMemChunk *dcerpc_bind_value_chunk=NULL;
773 dcerpc_bind_equal (gconstpointer k1, gconstpointer k2)
775 const dcerpc_bind_key *key1 = (const dcerpc_bind_key *)k1;
776 const dcerpc_bind_key *key2 = (const dcerpc_bind_key *)k2;
777 return (key1->conv == key2->conv
778 && key1->ctx_id == key2->ctx_id
779 && key1->smb_fid == key2->smb_fid);
783 dcerpc_bind_hash (gconstpointer k)
785 const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
786 return GPOINTER_TO_UINT(key->conv) + key->ctx_id + key->smb_fid;
791 * To keep track of callid mappings. Should really use some generic
792 * conversation support instead.
794 static GHashTable *dcerpc_cn_calls=NULL;
795 static GHashTable *dcerpc_dg_calls=NULL;
797 typedef struct _dcerpc_cn_call_key {
798 conversation_t *conv;
801 } dcerpc_cn_call_key;
803 typedef struct _dcerpc_dg_call_key {
804 conversation_t *conv;
807 } dcerpc_dg_call_key;
809 static GMemChunk *dcerpc_cn_call_key_chunk=NULL;
811 static GMemChunk *dcerpc_dg_call_key_chunk=NULL;
813 static GMemChunk *dcerpc_call_value_chunk=NULL;
817 dcerpc_cn_call_equal (gconstpointer k1, gconstpointer k2)
819 const dcerpc_cn_call_key *key1 = (const dcerpc_cn_call_key *)k1;
820 const dcerpc_cn_call_key *key2 = (const dcerpc_cn_call_key *)k2;
821 return (key1->conv == key2->conv
822 && key1->call_id == key2->call_id
823 && key1->smb_fid == key2->smb_fid);
827 dcerpc_dg_call_equal (gconstpointer k1, gconstpointer k2)
829 const dcerpc_dg_call_key *key1 = (const dcerpc_dg_call_key *)k1;
830 const dcerpc_dg_call_key *key2 = (const dcerpc_dg_call_key *)k2;
831 return (key1->conv == key2->conv
832 && key1->seqnum == key2->seqnum
833 && (memcmp (&key1->act_id, &key2->act_id, sizeof (e_uuid_t)) == 0));
837 dcerpc_cn_call_hash (gconstpointer k)
839 const dcerpc_cn_call_key *key = (const dcerpc_cn_call_key *)k;
840 return ((guint32)key->conv) + key->call_id + key->smb_fid;
844 dcerpc_dg_call_hash (gconstpointer k)
846 const dcerpc_dg_call_key *key = (const dcerpc_dg_call_key *)k;
847 return (((guint32)key->conv) + key->seqnum + key->act_id.Data1
848 + (key->act_id.Data2 << 16) + key->act_id.Data3
849 + (key->act_id.Data4[0] << 24) + (key->act_id.Data4[1] << 16)
850 + (key->act_id.Data4[2] << 8) + (key->act_id.Data4[3] << 0)
851 + (key->act_id.Data4[4] << 24) + (key->act_id.Data4[5] << 16)
852 + (key->act_id.Data4[6] << 8) + (key->act_id.Data4[7] << 0));
855 /* to keep track of matched calls/responses
856 this one uses the same value struct as calls, but the key is the frame id
857 and call id; there can be more than one call in a frame.
859 XXX - why not just use the same keys as are used for calls?
862 static GHashTable *dcerpc_matched=NULL;
864 typedef struct _dcerpc_matched_key {
867 } dcerpc_matched_key;
869 static GMemChunk *dcerpc_matched_key_chunk=NULL;
872 dcerpc_matched_equal (gconstpointer k1, gconstpointer k2)
874 const dcerpc_matched_key *key1 = (const dcerpc_matched_key *)k1;
875 const dcerpc_matched_key *key2 = (const dcerpc_matched_key *)k2;
876 return (key1->frame == key2->frame
877 && key1->call_id == key2->call_id);
881 dcerpc_matched_hash (gconstpointer k)
883 const dcerpc_matched_key *key = (const dcerpc_matched_key *)k;
890 * Utility functions. Modeled after packet-rpc.c
894 dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
895 proto_tree *tree, guint8 *drep,
896 int hfindex, guint8 *pdata)
900 data = tvb_get_guint8 (tvb, offset);
902 proto_tree_add_item (tree, hfindex, tvb, offset, 1, (drep[0] & 0x10));
910 dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
911 proto_tree *tree, guint8 *drep,
912 int hfindex, guint16 *pdata)
916 data = ((drep[0] & 0x10)
917 ? tvb_get_letohs (tvb, offset)
918 : tvb_get_ntohs (tvb, offset));
921 proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10));
929 dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
930 proto_tree *tree, guint8 *drep,
931 int hfindex, guint32 *pdata)
935 data = ((drep[0] & 0x10)
936 ? tvb_get_letohl (tvb, offset)
937 : tvb_get_ntohl (tvb, offset));
940 proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10));
947 /* handles 32 bit unix time_t */
949 dissect_dcerpc_time_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
950 proto_tree *tree, guint8 *drep,
951 int hfindex, guint32 *pdata)
956 data = ((drep[0] & 0x10)
957 ? tvb_get_letohl (tvb, offset)
958 : tvb_get_ntohl (tvb, offset));
963 if(data==0xffffffff){
964 /* special case, no time specified */
965 proto_tree_add_time_format(tree, hfindex, tvb, offset, 4, &tv, "%s: No time specified", proto_registrar_get_nth(hfindex)->name);
967 proto_tree_add_time (tree, hfindex, tvb, offset, 4, &tv);
977 dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
978 proto_tree *tree, guint8 *drep,
979 int hfindex, unsigned char *pdata)
982 tvb_memcpy(tvb, pdata, offset, 8);
983 if(drep[0] & 0x10){/* XXX this might be the wrong way around */
985 data=pdata[0];pdata[0]=pdata[7];pdata[7]=data;
986 data=pdata[1];pdata[1]=pdata[6];pdata[6]=data;
987 data=pdata[2];pdata[2]=pdata[5];pdata[5]=data;
988 data=pdata[3];pdata[3]=pdata[4];pdata[4]=data;
993 proto_tree_add_item(tree, hfindex, tvb, offset, 8, (drep[0] & 0x10));
1001 dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1002 proto_tree *tree, guint8 *drep,
1003 int hfindex, gfloat *pdata)
1009 case(DCE_RPC_DREP_FP_IEEE):
1010 data = ((drep[0] & 0x10)
1011 ? tvb_get_letohieee_float(tvb, offset)
1012 : tvb_get_ntohieee_float(tvb, offset));
1014 proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
1017 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
1018 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1019 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
1021 /* ToBeDone: non IEEE floating formats */
1022 /* Set data to a negative infinity value */
1025 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep[1]);
1035 dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1036 proto_tree *tree, guint8 *drep,
1037 int hfindex, gdouble *pdata)
1043 case(DCE_RPC_DREP_FP_IEEE):
1044 data = ((drep[0] & 0x10)
1045 ? tvb_get_letohieee_double(tvb, offset)
1046 : tvb_get_ntohieee_double(tvb, offset));
1048 proto_tree_add_double(tree, hfindex, tvb, offset, 8, data);
1051 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
1052 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1053 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
1055 /* ToBeDone: non IEEE double formats */
1056 /* Set data to a negative infinity value */
1057 data = -G_MAXDOUBLE;
1059 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep[1]);
1069 * a couple simpler things
1072 dcerpc_tvb_get_ntohs (tvbuff_t *tvb, gint offset, guint8 *drep)
1074 if (drep[0] & 0x10) {
1075 return tvb_get_letohs (tvb, offset);
1077 return tvb_get_ntohs (tvb, offset);
1082 dcerpc_tvb_get_ntohl (tvbuff_t *tvb, gint offset, guint8 *drep)
1084 if (drep[0] & 0x10) {
1085 return tvb_get_letohl (tvb, offset);
1087 return tvb_get_ntohl (tvb, offset);
1092 dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, guint8 *drep, e_uuid_t *uuid)
1095 uuid->Data1 = dcerpc_tvb_get_ntohl (tvb, offset, drep);
1096 uuid->Data2 = dcerpc_tvb_get_ntohs (tvb, offset+4, drep);
1097 uuid->Data3 = dcerpc_tvb_get_ntohs (tvb, offset+6, drep);
1099 for (i=0; i<sizeof (uuid->Data4); i++) {
1100 uuid->Data4[i] = tvb_get_guint8 (tvb, offset+8+i);
1107 /* function to dissect a unidimensional conformant array */
1109 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1110 proto_tree *tree, guint8 *drep,
1111 dcerpc_dissect_fnct_t *fnct)
1117 di=pinfo->private_data;
1118 if(di->conformant_run){
1119 /* conformant run, just dissect the max_count header */
1121 di->conformant_run=0;
1122 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1123 hf_dcerpc_array_max_count, &di->array_max_count);
1124 di->array_max_count_offset=offset-4;
1125 di->conformant_run=1;
1126 di->conformant_eaten=offset-old_offset;
1128 /* we don't remember where in the bytestream this field was */
1129 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1131 /* real run, dissect the elements */
1132 for(i=0;i<di->array_max_count;i++){
1133 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1139 /* function to dissect a unidimensional conformant and varying array */
1141 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1142 proto_tree *tree, guint8 *drep,
1143 dcerpc_dissect_fnct_t *fnct)
1149 di=pinfo->private_data;
1150 if(di->conformant_run){
1151 /* conformant run, just dissect the max_count header */
1153 di->conformant_run=0;
1154 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1155 hf_dcerpc_array_max_count, &di->array_max_count);
1156 di->array_max_count_offset=offset-4;
1157 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1158 hf_dcerpc_array_offset, &di->array_offset);
1159 di->array_offset_offset=offset-4;
1160 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1161 hf_dcerpc_array_actual_count, &di->array_actual_count);
1162 di->array_actual_count_offset=offset-4;
1163 di->conformant_run=1;
1164 di->conformant_eaten=offset-old_offset;
1166 /* we dont dont remember where in the bytestream these fields were */
1167 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1168 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
1169 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
1171 /* real run, dissect the elements */
1172 for(i=0;i<di->array_actual_count;i++){
1173 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1180 /* Dissect an string of bytes. This corresponds to
1181 IDL of the form '[string] byte *foo'.
1183 It can also be used for a conformant varying array of bytes if
1184 the contents of the array should be shown as a big blob, rather
1185 than showing each byte as an individual element.
1187 XXX - which of those is really the IDL type for, for example,
1188 the encrypted data in some MAPI packets? (Microsoft haven't
1191 XXX - does this need to do all the conformant array stuff that
1192 "dissect_ndr_ucvarray()" does? These are presumably for strings
1193 that are conformant and varying - they're stored like conformant
1194 varying arrays of bytes. */
1196 dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo,
1197 proto_tree *tree, guint8 *drep)
1202 di=pinfo->private_data;
1203 if(di->conformant_run){
1204 /* just a run to handle conformant arrays, no scalars to dissect */
1208 /* NDR array header */
1210 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1211 hf_dcerpc_array_max_count, NULL);
1213 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1214 hf_dcerpc_array_offset, NULL);
1216 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1217 hf_dcerpc_array_actual_count, &len);
1220 proto_tree_add_item(tree, hf_dcerpc_array_buffer,
1221 tvb, offset, len, drep[0] & 0x10);
1228 /* For dissecting arrays that are to be interpreted as strings. */
1230 /* Dissect an NDR conformant varying string of elements.
1231 The length of each element is given by the 'size_is' parameter;
1232 the elements are assumed to be characters or wide characters.
1234 XXX - does this need to do all the conformant array stuff that
1235 "dissect_ndr_ucvarray()" does? */
1237 dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1238 proto_tree *tree, guint8 *drep, int size_is,
1239 int hfindex, gboolean add_subtree, char **data)
1242 proto_item *string_item;
1243 proto_tree *string_tree;
1244 guint32 len, buffer_len;
1246 header_field_info *hfinfo;
1248 di=pinfo->private_data;
1249 if(di->conformant_run){
1250 /* just a run to handle conformant arrays, no scalars to dissect */
1255 string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1256 proto_registrar_get_name(hfindex));
1257 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1263 /* NDR array header */
1265 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1266 hf_dcerpc_array_max_count, NULL);
1268 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1269 hf_dcerpc_array_offset, NULL);
1271 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1272 hf_dcerpc_array_actual_count, &len);
1274 buffer_len = size_is * len;
1277 if (offset % size_is)
1278 offset += size_is - (offset % size_is);
1280 if (size_is == sizeof(guint16)) {
1281 /* XXX - use drep to determine the byte order? */
1282 s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
1284 * XXX - we don't support a string type with Unicode
1285 * characters, so if this is a string item, we make
1286 * its value be the "fake Unicode" string.
1288 if (tree && buffer_len) {
1289 hfinfo = proto_registrar_get_nth(hfindex);
1290 if (hfinfo->type == FT_STRING) {
1291 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1294 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1295 buffer_len, drep[0] & 0x10);
1300 * "tvb_get_string()" throws an exception if the entire string
1301 * isn't in the tvbuff. If the length is bogus, this should
1302 * keep us from trying to allocate an immensely large buffer.
1303 * (It won't help if the length is *valid* but immensely large,
1304 * but that's another matter; in any case, that would happen only
1305 * if we had an immensely large tvbuff....)
1307 s = tvb_get_string(tvb, offset, buffer_len);
1308 if (tree && buffer_len)
1309 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1310 buffer_len, drep[0] & 0x10);
1313 if (string_item != NULL)
1314 proto_item_append_text(string_item, ": %s", s);
1321 offset += buffer_len;
1323 proto_item_set_end(string_item, tvb, offset);
1328 /* Dissect an conformant varying string of chars.
1329 This corresponds to IDL of the form '[string] char *foo'.
1331 XXX - at least according to the DCE RPC 1.1 spec, a string has
1332 a null terminator, which isn't necessary as a terminator for
1333 the transfer language (as there's a length), but is presumably
1334 there for the benefit of null-terminated-string languages
1335 such as C. Is this ever used for purely counted strings?
1336 (Not that it matters if it is.) */
1338 dissect_ndr_char_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1339 proto_tree *tree, guint8 *drep)
1342 di=pinfo->private_data;
1344 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1345 sizeof(guint8), di->hf_index,
1349 /* Dissect a conformant varying string of wchars (wide characters).
1350 This corresponds to IDL of the form '[string] wchar *foo'
1352 XXX - at least according to the DCE RPC 1.1 spec, a string has
1353 a null terminator, which isn't necessary as a terminator for
1354 the transfer language (as there's a length), but is presumably
1355 there for the benefit of null-terminated-string languages
1356 such as C. Is this ever used for purely counted strings?
1357 (Not that it matters if it is.) */
1359 dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1360 proto_tree *tree, guint8 *drep)
1363 di=pinfo->private_data;
1365 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1366 sizeof(guint16), di->hf_index,
1370 /* ndr pointer handling */
1371 /* list of pointers encountered so far */
1372 static GSList *ndr_pointer_list = NULL;
1374 /* position where in the list to insert newly encountered pointers */
1375 static int ndr_pointer_list_pos=0;
1377 /* boolean controlling whether pointers are top-level or embedded */
1378 static gboolean pointers_are_top_level = TRUE;
1380 /* as a kludge, we represent all embedded reference pointers as id==-1
1381 hoping that his will not collide with any non-ref pointers */
1382 typedef struct ndr_pointer_data {
1384 proto_item *item; /* proto_item for pointer */
1385 proto_tree *tree; /* subtree of above item */
1386 dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
1388 dcerpc_callback_fnct_t *callback;
1389 void *callback_args;
1390 } ndr_pointer_data_t;
1393 init_ndr_pointer_list(packet_info *pinfo)
1397 di=pinfo->private_data;
1398 di->conformant_run=0;
1400 while(ndr_pointer_list){
1401 ndr_pointer_data_t *npd;
1403 npd=g_slist_nth_data(ndr_pointer_list, 0);
1404 ndr_pointer_list=g_slist_remove(ndr_pointer_list, npd);
1410 ndr_pointer_list=NULL;
1411 ndr_pointer_list_pos=0;
1412 pointers_are_top_level=TRUE;
1416 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, guint8 *drep)
1418 int found_new_pointer;
1424 di=pinfo->private_data;
1428 found_new_pointer=0;
1429 len=g_slist_length(ndr_pointer_list);
1430 for(i=next_pointer;i<len;i++){
1431 ndr_pointer_data_t *tnpd;
1432 tnpd=g_slist_nth_data(ndr_pointer_list, i);
1434 dcerpc_dissect_fnct_t *fnct;
1437 found_new_pointer=1;
1440 ndr_pointer_list_pos=i+1;
1441 di->hf_index=tnpd->hf_index;
1442 /* first a run to handle any conformant
1444 di->conformant_run=1;
1445 di->conformant_eaten=0;
1446 old_offset = offset;
1447 offset = (*(fnct))(tvb, offset, pinfo, NULL, drep);
1449 g_assert((offset-old_offset)==di->conformant_eaten);
1450 /* This is to check for any bugs in the dissectors.
1452 * Basically, the NDR representation will store all
1453 * arrays in two blocks, one block with the dimension
1454 * discreption, like size, number of elements and such,
1455 * and another block that contains the actual data stored
1457 * If the array is embedded directly inside another,
1458 * encapsulating aggregate type, like a union or struct,
1459 * then these two blocks will be stored at different places
1460 * in the bytestream, with other data between the blocks.
1462 * For this reason, all pointers to types (both aggregate
1463 * and scalar, for simplicity no distinction is made)
1464 * will have its dissector called twice.
1465 * The dissector will first be called with conformant_run==1
1466 * in which mode the dissector MUST NOT consume any data from
1467 * the tvbuff (i.e. may not dissect anything) except the
1468 * initial control block for arrays.
1469 * The second time the dissector is called, with
1470 * conformant_run==0, all other data for the type will be
1473 * All dissect_ndr_<type> dissectors are already prepared
1474 * for this and knows when it should eat data from the tvb
1475 * and when not to, so implementors of dissectors will
1476 * normally not need to worry about this or even know about
1477 * it. However, if a dissector for an aggregate type calls
1478 * a subdissector from outside packet-dcerpc.c, such as
1479 * the dissector in packet-smb.c for NT Security Descriptors
1480 * as an example, then it is VERY important to encapsulate
1481 * this call to an external subdissector with the appropriate
1482 * test for conformant_run, i.e. it will need something like
1486 * di=pinfo->private_data;
1487 * if(di->conformant_run){
1491 * to make sure it makes the right thing.
1492 * This assert will signal when someone has forgotten to
1493 * make the dissector aware of this requirement.
1496 /* now we dissect the actual pointer */
1497 di->conformant_run=0;
1498 old_offset = offset;
1499 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, drep);
1501 tnpd->callback(pinfo, tnpd->tree, tnpd->item, tvb, old_offset, offset, tnpd->callback_args);
1505 } while(found_new_pointer);
1512 add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
1513 dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index,
1514 dcerpc_callback_fnct_t *callback, void *callback_args)
1516 ndr_pointer_data_t *npd;
1518 /* check if this pointer is valid */
1521 dcerpc_call_value *value;
1523 di=pinfo->private_data;
1524 value=di->call_data;
1526 if(di->ptype == PDU_REQ){
1527 if(!(pinfo->fd->flags.visited)){
1528 if(id>value->max_ptr){
1533 /* if we havent seen the request bail out since we cant
1534 know whether this is the first non-NULL instance
1536 if(value->req_frame==0){
1537 /* XXX THROW EXCEPTION */
1540 /* We saw this one in the request frame, nothing to
1542 if(id<=value->max_ptr){
1548 npd=g_malloc(sizeof(ndr_pointer_data_t));
1553 npd->hf_index=hf_index;
1554 npd->callback=callback;
1555 npd->callback_args=callback_args;
1556 ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
1557 ndr_pointer_list_pos);
1558 ndr_pointer_list_pos++;
1563 find_pointer_index(guint32 id)
1565 ndr_pointer_data_t *npd;
1568 len=g_slist_length(ndr_pointer_list);
1570 npd=g_slist_nth_data(ndr_pointer_list, i);
1581 /* This function dissects an NDR pointer and stores the callback for later
1582 * deferred dissection.
1584 * fnct is the callback function for when we have reached this object in
1587 * type is what type of pointer.
1589 * this is text is what text we should put in any created tree node.
1591 * hf_index is what hf value we want to pass to the callback function when
1592 * it is called, the callback can later pich this one up from di->hf_index.
1594 * callback is executed after the pointer has been dereferenced.
1596 * callback_args is passed as an argument to the callback function
1598 * See packet-dcerpc-samr.c for examples
1601 dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1602 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
1603 int type, char *text, int hf_index,
1604 dcerpc_callback_fnct_t *callback, void *callback_args)
1608 di=pinfo->private_data;
1609 if(di->conformant_run){
1610 /* this call was only for dissecting the header for any
1611 embedded conformant array. we will not parse any
1612 pointers in this mode.
1617 /*TOP LEVEL REFERENCE POINTER*/
1618 if( pointers_are_top_level
1619 &&(type==NDR_POINTER_REF) ){
1623 /* we must find out a nice way to do the length here */
1624 item=proto_tree_add_text(tree, tvb, offset, 0,
1626 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1628 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1629 hf_index, callback, callback_args);
1633 /*TOP LEVEL FULL POINTER*/
1634 if( pointers_are_top_level
1635 && (type==NDR_POINTER_PTR) ){
1641 /* get the referent id */
1642 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1644 /* we got a NULL pointer */
1646 proto_tree_add_text(tree, tvb, offset-4, 4,
1647 "(NULL pointer) %s",text);
1651 /* see if we have seen this pointer before */
1652 idx=find_pointer_index(id);
1654 /* we have seen this pointer before */
1656 proto_tree_add_text(tree, tvb, offset-4, 4,
1657 "(duplicate PTR) %s",text);
1662 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1664 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1665 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1666 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
1667 callback, callback_args);
1670 /*TOP LEVEL UNIQUE POINTER*/
1671 if( pointers_are_top_level
1672 && (type==NDR_POINTER_UNIQUE) ){
1677 /* get the referent id */
1678 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1680 /* we got a NULL pointer */
1682 proto_tree_add_text(tree, tvb, offset-4, 4,
1683 "(NULL pointer) %s",text);
1688 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1690 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1691 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1692 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1693 hf_index, callback, callback_args);
1697 /*EMBEDDED REFERENCE POINTER*/
1698 if( (!pointers_are_top_level)
1699 && (type==NDR_POINTER_REF) ){
1704 /* get the referent id */
1705 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1708 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1710 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1711 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1712 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1713 hf_index, callback, callback_args);
1717 /*EMBEDDED UNIQUE POINTER*/
1718 if( (!pointers_are_top_level)
1719 && (type==NDR_POINTER_UNIQUE) ){
1724 /* get the referent id */
1725 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1727 /* we got a NULL pointer */
1729 proto_tree_add_text(tree, tvb, offset-4, 4,
1730 "(NULL pointer) %s", text);
1735 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1737 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1738 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1739 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1740 hf_index, callback, callback_args);
1744 /*EMBEDDED FULL POINTER*/
1745 if( (!pointers_are_top_level)
1746 && (type==NDR_POINTER_PTR) ){
1752 /* get the referent id */
1753 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1755 /* we got a NULL pointer */
1757 proto_tree_add_text(tree, tvb, offset-4, 4,
1758 "(NULL pointer) %s",text);
1762 /* see if we have seen this pointer before */
1763 idx=find_pointer_index(id);
1765 /* we have seen this pointer before */
1767 proto_tree_add_text(tree, tvb, offset-4, 4,
1768 "(duplicate PTR) %s",text);
1773 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1775 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1776 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1777 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
1778 callback, callback_args);
1784 /* After each top level pointer we have dissected we have to
1785 dissect all deferrals before we move on to the next top level
1787 if(pointers_are_top_level==TRUE){
1788 pointers_are_top_level=FALSE;
1789 offset = dissect_deferred_pointers(pinfo, tvb, offset, drep);
1790 pointers_are_top_level=TRUE;
1797 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1798 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
1799 int type, char *text, int hf_index)
1801 return dissect_ndr_pointer_cb(
1802 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
1807 show_stub_data (tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
1808 dcerpc_auth_info *auth_info, gboolean is_encrypted)
1813 * We don't show stub data unless we have some in the tvbuff;
1814 * however, in the protocol tree, we show, as the number of
1815 * bytes, the reported number of bytes, not the number of bytes
1816 * that happen to be in the tvbuff.
1818 if (tvb_length_remaining (tvb, offset) > 0) {
1819 length = tvb_reported_length_remaining (tvb, offset);
1820 if (auth_info != NULL &&
1821 auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
1823 proto_tree_add_text(dcerpc_tree, tvb, offset, -1,
1824 "Encrypted stub data (%d byte%s)",
1825 length, plurality(length, "", "s"));
1827 proto_tree_add_text(dcerpc_tree, tvb, offset, -1,
1828 "Decrypted stub data (%d byte%s)",
1829 length, plurality(length, "", "s"));
1832 proto_tree_add_text (dcerpc_tree, tvb, offset, -1,
1833 "Stub data (%d byte%s)", length,
1834 plurality(length, "", "s"));
1840 dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
1841 proto_tree *dcerpc_tree,
1842 tvbuff_t *volatile tvb, tvbuff_t *decrypted_tvb,
1843 guint8 *drep, dcerpc_info *info,
1844 dcerpc_auth_info *auth_info)
1846 volatile gint offset = 0;
1847 dcerpc_uuid_key key;
1848 dcerpc_uuid_value *sub_proto;
1849 proto_tree *volatile sub_tree = NULL;
1850 dcerpc_sub_dissector *proc;
1852 dcerpc_dissect_fnct_t *volatile sub_dissect;
1853 const char *volatile saved_proto;
1854 void *volatile saved_private_data;
1855 guint length, reported_length;
1856 tvbuff_t *volatile stub_tvb;
1857 volatile guint auth_pad_len;
1858 volatile int auth_pad_offset;
1860 char UUID_NAME[MAX_PATH];
1863 key.uuid = info->call_data->uuid;
1864 key.ver = info->call_data->ver;
1867 if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == NULL
1868 || !proto_is_protocol_enabled(sub_proto->proto)) {
1870 * We don't have a dissector for this UUID, or the protocol
1871 * for that UUID is disabled.
1874 proto_tree_add_boolean_hidden(dcerpc_tree, hf_dcerpc_unknown_if_id,
1875 tvb, offset, 0, TRUE);
1876 if (check_col (pinfo->cinfo, COL_INFO)) {
1878 if(ResolveWin32UUID(info->call_data->uuid, UUID_NAME, MAX_PATH))
1879 col_append_fstr (pinfo->cinfo, COL_INFO, " [%s] UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x rpcver: %u",
1880 UUID_NAME, info->call_data->uuid.Data1, info->call_data->uuid.Data2, info->call_data->uuid.Data3, info->call_data->uuid.Data4[0],
1881 info->call_data->uuid.Data4[1], info->call_data->uuid.Data4[2], info->call_data->uuid.Data4[3],
1882 info->call_data->uuid.Data4[4], info->call_data->uuid.Data4[5], info->call_data->uuid.Data4[6],
1883 info->call_data->uuid.Data4[7], info->call_data->ver);
1886 col_append_fstr (pinfo->cinfo, COL_INFO, " UNKUUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x rpcver: %u",
1887 info->call_data->uuid.Data1, info->call_data->uuid.Data2, info->call_data->uuid.Data3, info->call_data->uuid.Data4[0],
1888 info->call_data->uuid.Data4[1], info->call_data->uuid.Data4[2], info->call_data->uuid.Data4[3],
1889 info->call_data->uuid.Data4[4], info->call_data->uuid.Data4[5], info->call_data->uuid.Data4[6],
1890 info->call_data->uuid.Data4[7], info->call_data->ver);
1893 if (decrypted_tvb != NULL) {
1894 show_stub_data (decrypted_tvb, 0, dcerpc_tree, auth_info,
1897 show_stub_data (tvb, 0, dcerpc_tree, auth_info, TRUE);
1901 for (proc = sub_proto->procs; proc->name; proc++) {
1902 if (proc->num == info->call_data->opnum) {
1911 if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
1912 col_set_str (pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
1915 if (check_col (pinfo->cinfo, COL_INFO)) {
1916 col_add_fstr (pinfo->cinfo, COL_INFO, "%s %s",
1917 name, (info->ptype == PDU_REQ) ? "request" : "response");
1921 proto_item *sub_item;
1922 sub_item = proto_tree_add_item (tree, sub_proto->proto_id, tvb, 0,
1926 sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
1927 proto_item_append_text(sub_item, ", %s", name);
1931 * Put the operation number into the tree along with
1932 * the operation's name.
1935 if (sub_proto->opnum_hf != -1)
1936 proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
1937 tvb, 0, 0, info->call_data->opnum,
1938 "Operation: %s (%u)",
1939 name, info->call_data->opnum);
1941 proto_tree_add_uint_format(sub_tree, hf_dcerpc_op, tvb,
1942 0, 0, info->call_data->opnum,
1943 "Operation: %s (%u)",
1944 name, info->call_data->opnum);
1947 sub_dissect = (info->ptype == PDU_REQ) ?
1948 proc->dissect_rqst : proc->dissect_resp;
1950 if (decrypted_tvb != NULL) {
1951 /* Either there was no encryption or we successfully decrypted
1952 the entrypted payload. */
1954 /* We have a subdissector - call it. */
1955 saved_proto = pinfo->current_proto;
1956 saved_private_data = pinfo->private_data;
1957 pinfo->current_proto = sub_proto->name;
1958 pinfo->private_data = (void *)info;
1960 init_ndr_pointer_list(pinfo);
1963 * Remove the authentication padding from the stub data.
1965 if (auth_info != NULL && auth_info->auth_pad_len != 0) {
1966 length = tvb_length(decrypted_tvb);
1967 reported_length = tvb_reported_length(decrypted_tvb);
1968 if (reported_length >= auth_info->auth_pad_len) {
1970 * OK, the padding length isn't so big that it
1971 * exceeds the stub length. Trim the reported
1972 * length of the tvbuff.
1974 reported_length -= auth_info->auth_pad_len;
1977 * If that exceeds the actual amount of data in
1978 * the tvbuff (which means we have at least one
1979 * byte of authentication padding in the tvbuff),
1980 * trim the actual amount.
1982 if (length > reported_length)
1983 length = reported_length;
1985 stub_tvb = tvb_new_subset(tvb, 0, length, reported_length);
1986 auth_pad_len = auth_info->auth_pad_len;
1987 auth_pad_offset = reported_length;
1990 * The padding length exceeds the stub length.
1991 * Don't bother dissecting the stub, trim the padding
1992 * length to what's in the stub data, and show the
1993 * entire stub as authentication padding.
1996 auth_pad_len = reported_length;
1997 auth_pad_offset = 0;
2001 * No authentication padding.
2003 stub_tvb = decrypted_tvb;
2005 auth_pad_offset = 0;
2008 if (stub_tvb != NULL) {
2010 * Catch all exceptions other than BoundsError, so that even
2011 * if the stub data is bad, we still show the authentication
2014 * If we get BoundsError, it means the frame was cut short
2015 * by a snapshot length, so there's nothing more to
2016 * dissect; just re-throw that exception.
2019 offset = sub_dissect (decrypted_tvb, 0, pinfo, sub_tree,
2022 /* If we have a subdissector and it didn't dissect all
2023 data in the tvb, make a note of it. */
2025 if (tvb_reported_length_remaining(stub_tvb, offset) > 0) {
2026 if (check_col(pinfo->cinfo, COL_INFO))
2027 col_append_fstr(pinfo->cinfo, COL_INFO,
2028 "[Long frame (%d bytes)]",
2029 tvb_reported_length_remaining(stub_tvb, offset));
2031 } CATCH(BoundsError) {
2034 show_exception(decrypted_tvb, pinfo, tree, EXCEPT_CODE);
2038 /* If there is auth padding at the end of the stub, display it */
2039 if (auth_pad_len != 0) {
2040 proto_tree_add_text (sub_tree, decrypted_tvb, auth_pad_offset,
2042 "Auth Padding (%u byte%s)",
2044 plurality(auth_pad_len, "", "s"));
2047 pinfo->current_proto = saved_proto;
2048 pinfo->private_data = saved_private_data;
2050 /* No subdissector - show it as stub data. */
2052 show_stub_data (decrypted_tvb, 0, sub_tree, auth_info, FALSE);
2054 show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
2058 show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
2060 tap_queue_packet(dcerpc_tap, pinfo, info);
2065 dissect_dcerpc_verifier (tvbuff_t *tvb, packet_info *pinfo,
2066 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
2067 dcerpc_auth_info *auth_info)
2071 auth_info->auth_data = NULL;
2073 if (auth_info->auth_size != 0) {
2074 dcerpc_auth_subdissector_fns *auth_fns;
2077 auth_offset = hdr->frag_len - hdr->auth_len;
2079 auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
2082 auth_info->auth_data = auth_tvb;
2084 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
2085 auth_info->auth_type))) {
2087 * Catch all exceptions, so that even if the verifier is bad
2088 * or we don't have all of it, we still show the stub data.
2091 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
2094 show_exception(auth_tvb, pinfo, dcerpc_tree, EXCEPT_CODE);
2097 proto_tree_add_text (dcerpc_tree, auth_tvb, 0, hdr->auth_len,
2102 return hdr->auth_len;
2106 dissect_dcerpc_cn_auth (tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
2107 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
2108 gboolean are_credentials, dcerpc_auth_info *auth_info)
2110 volatile int offset;
2113 * Initially set auth_level and auth_type to zero to indicate that we
2114 * haven't yet seen any authentication level information.
2116 auth_info->auth_level = 0;
2117 auth_info->auth_type = 0;
2118 auth_info->auth_size = 0;
2119 auth_info->auth_pad_len = 0;
2122 * The authentication information is at the *end* of the PDU; in
2123 * request and response PDUs, the request and response stub data
2126 * Is there any authentication data (i.e., is the authentication length
2127 * non-zero), and is the authentication length valid (i.e., is it, plus
2128 * 8 bytes for the type/level/pad length/reserved/context id, less than
2129 * or equal to the fragment length minus the starting offset of the
2134 && (hdr->auth_len + 8 <= hdr->frag_len - stub_offset)) {
2137 * Yes, there is authentication data, and the length is valid.
2138 * Do we have all the bytes of stub data?
2139 * (If not, we'd throw an exception dissecting *that*, so don't
2140 * bother trying to dissect the authentication information and
2141 * throwing another exception there.)
2143 offset = hdr->frag_len - (hdr->auth_len + 8);
2144 if (offset == 0 || tvb_offset_exists(tvb, offset - 1)) {
2146 * Either there's no stub data, or the last byte of the stub
2147 * data is present in the captured data, so we shouldn't
2148 * get a BoundsError dissecting the stub data.
2150 * Try dissecting the authentication data.
2151 * Catch all exceptions, so that even if the auth info is bad
2152 * or we don't have all of it, we still show the stuff we
2153 * dissect after this, such as stub data.
2156 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2157 hf_dcerpc_auth_type,
2158 &auth_info->auth_type);
2159 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2160 hf_dcerpc_auth_level,
2161 &auth_info->auth_level);
2163 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2164 hf_dcerpc_auth_pad_len,
2165 &auth_info->auth_pad_len);
2166 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2167 hf_dcerpc_auth_rsrvd, NULL);
2168 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2169 hf_dcerpc_auth_ctx_id, NULL);
2172 * Dissect the authentication data.
2174 if (are_credentials) {
2176 dcerpc_auth_subdissector_fns *auth_fns;
2178 auth_tvb = tvb_new_subset(tvb, offset, hdr->auth_len,
2181 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
2182 auth_info->auth_type)))
2183 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
2186 proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len,
2187 "Auth Credentials");
2190 /* Compute the size of the auth block. Note that this should not
2191 include auth padding, since when NTLMSSP encryption is used, the
2192 padding is actually inside the encrypted stub */
2193 auth_info->auth_size = hdr->auth_len + 8;
2195 show_exception(tvb, pinfo, dcerpc_tree, EXCEPT_CODE);
2202 /* We need to hash in the SMB fid number to generate a unique hash table
2203 * key as DCERPC over SMB allows several pipes over the same TCP/IP
2205 * We pass this function the transport type here to make sure we only look
2206 * at this function if it came across an SMB pipe.
2207 * Other transports might need to mix in their own extra multiplexing data
2208 * as well in the future.
2211 guint16 dcerpc_get_transport_salt (packet_info *pinfo, int transport_type)
2213 dcerpc_private_info *priv = (dcerpc_private_info *)pinfo->private_data;
2216 return 0; /* Nothing to see here */
2218 switch(transport_type){
2219 case DCE_CN_TRANSPORT_SMBPIPE:
2220 /* DCERPC over smb */
2224 /* Some other transport... */
2229 * Connection oriented packet types
2233 dissect_dcerpc_cn_bind (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2234 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
2237 conversation_t *conv = NULL;
2238 guint8 num_ctx_items = 0;
2240 gboolean saw_ctx_item = FALSE;
2242 guint8 num_trans_items;
2247 guint16 if_ver, if_ver_minor;
2248 char uuid_str[DCERPC_UUID_STR_LEN];
2250 dcerpc_auth_info auth_info;
2252 char UUID_NAME[MAX_PATH];
2255 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2256 hf_dcerpc_cn_max_xmit, NULL);
2258 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2259 hf_dcerpc_cn_max_recv, NULL);
2261 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2262 hf_dcerpc_cn_assoc_group, NULL);
2264 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2265 hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
2270 for (i = 0; i < num_ctx_items; i++) {
2271 proto_tree *ctx_tree = NULL, *iface_tree = NULL;
2273 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, NULL, hdr->drep,
2274 hf_dcerpc_cn_ctx_id, &ctx_id);
2276 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
2277 /* (if we have multiple contexts, this might cause "decode as"
2278 * to behave unpredictably) */
2279 pinfo->dcectxid = ctx_id;
2280 pinfo->dcetransporttype = transport_type;
2283 proto_item *ctx_item;
2285 ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_id,
2287 hdr->drep[0] & 0x10);
2289 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
2292 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, ctx_tree, hdr->drep,
2293 hf_dcerpc_cn_num_trans_items, &num_trans_items);
2298 /* XXX - use "dissect_ndr_uuid_t()"? */
2299 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
2301 proto_item *iface_item;
2303 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2304 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2305 if_id.Data1, if_id.Data2, if_id.Data3,
2306 if_id.Data4[0], if_id.Data4[1],
2307 if_id.Data4[2], if_id.Data4[3],
2308 if_id.Data4[4], if_id.Data4[5],
2309 if_id.Data4[6], if_id.Data4[7]);
2311 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2312 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2314 if(ResolveWin32UUID(if_id, UUID_NAME, MAX_PATH))
2315 iface_item = proto_tree_add_string_format (ctx_tree, hf_dcerpc_cn_bind_if_id, tvb,
2316 offset, 16, uuid_str, "Interface [%s] UUID: %s", UUID_NAME, uuid_str);
2319 iface_item = proto_tree_add_string_format (ctx_tree, hf_dcerpc_cn_bind_if_id, tvb,
2320 offset, 16, uuid_str, "Interface UUID: %s", uuid_str);
2321 iface_tree = proto_item_add_subtree(iface_item, ett_dcerpc_cn_iface);
2325 if (hdr->drep[0] & 0x10) {
2326 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2327 hf_dcerpc_cn_bind_if_ver, &if_ver);
2328 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2329 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2331 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2332 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2333 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2334 hf_dcerpc_cn_bind_if_ver, &if_ver);
2337 if (!saw_ctx_item) {
2338 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2339 pinfo->srcport, pinfo->destport, 0);
2341 conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
2342 pinfo->srcport, pinfo->destport, 0);
2346 /* if this is the first time we see this packet, we need to
2347 update the dcerpc_binds table so that any later calls can
2348 match to the interface.
2349 XXX We assume that BINDs will NEVER be fragmented.
2351 if(!(pinfo->fd->flags.visited)){
2352 dcerpc_bind_key *key;
2353 dcerpc_bind_value *value;
2355 key = g_mem_chunk_alloc (dcerpc_bind_key_chunk);
2357 key->ctx_id = ctx_id;
2358 key->smb_fid = dcerpc_get_transport_salt(pinfo, transport_type);
2360 value = g_mem_chunk_alloc (dcerpc_bind_value_chunk);
2361 value->uuid = if_id;
2362 value->ver = if_ver;
2364 /* add this entry to the bind table, first removing any
2365 previous ones that are identical
2367 if(g_hash_table_lookup(dcerpc_binds, key)){
2368 g_hash_table_remove(dcerpc_binds, key);
2370 g_hash_table_insert (dcerpc_binds, key, value);
2373 if (check_col (pinfo->cinfo, COL_INFO)) {
2374 dcerpc_uuid_key key;
2375 dcerpc_uuid_value *value;
2380 if (num_ctx_items > 1)
2381 col_append_fstr(pinfo->cinfo, COL_INFO, ", %u context items, 1st", num_ctx_items);
2383 if ((value = g_hash_table_lookup(dcerpc_uuids, &key)))
2384 col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %s", value->name);
2387 if(ResolveWin32UUID(if_id, UUID_NAME, MAX_PATH))
2388 col_append_fstr(pinfo->cinfo, COL_INFO, " [%s] UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
2389 UUID_NAME, if_id.Data1, if_id.Data2, if_id.Data3,
2390 if_id.Data4[0], if_id.Data4[1],
2391 if_id.Data4[2], if_id.Data4[3],
2392 if_id.Data4[4], if_id.Data4[5],
2393 if_id.Data4[6], if_id.Data4[7],
2394 if_ver, if_ver_minor);
2397 col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
2398 if_id.Data1, if_id.Data2, if_id.Data3,
2399 if_id.Data4[0], if_id.Data4[1],
2400 if_id.Data4[2], if_id.Data4[3],
2401 if_id.Data4[4], if_id.Data4[5],
2402 if_id.Data4[6], if_id.Data4[7],
2403 if_ver, if_ver_minor);
2405 saw_ctx_item = TRUE;
2408 for (j = 0; j < num_trans_items; j++) {
2409 /* XXX - use "dissect_ndr_uuid_t()"? */
2410 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2412 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2413 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2414 trans_id.Data1, trans_id.Data2, trans_id.Data3,
2415 trans_id.Data4[0], trans_id.Data4[1],
2416 trans_id.Data4[2], trans_id.Data4[3],
2417 trans_id.Data4[4], trans_id.Data4[5],
2418 trans_id.Data4[6], trans_id.Data4[7]);
2419 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2420 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2421 proto_tree_add_string_format (iface_tree, hf_dcerpc_cn_bind_trans_id, tvb,
2422 offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2426 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, iface_tree, hdr->drep,
2427 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
2432 * XXX - we should save the authentication type *if* we have
2433 * an authentication header, and associate it with an authentication
2434 * context, so subsequent PDUs can use that context.
2436 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2440 dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2441 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2443 guint16 max_xmit, max_recv;
2444 guint16 sec_addr_len;
2451 char uuid_str[DCERPC_UUID_STR_LEN];
2453 dcerpc_auth_info auth_info;
2455 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2456 hf_dcerpc_cn_max_xmit, &max_xmit);
2458 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2459 hf_dcerpc_cn_max_recv, &max_recv);
2461 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2462 hf_dcerpc_cn_assoc_group, NULL);
2464 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2465 hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
2466 if (sec_addr_len != 0) {
2467 proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
2468 sec_addr_len, FALSE);
2469 offset += sec_addr_len;
2473 offset += 4 - offset % 4;
2476 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2477 hf_dcerpc_cn_num_results, &num_results);
2482 for (i = 0; i < num_results; i++) {
2483 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2484 hdr->drep, hf_dcerpc_cn_ack_result,
2487 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2488 hdr->drep, hf_dcerpc_cn_ack_reason,
2492 * The reason for rejection isn't meaningful, and often isn't
2493 * set, when the syntax was accepted.
2498 /* XXX - use "dissect_ndr_uuid_t()"? */
2499 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2501 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2502 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2503 trans_id.Data1, trans_id.Data2, trans_id.Data3,
2504 trans_id.Data4[0], trans_id.Data4[1],
2505 trans_id.Data4[2], trans_id.Data4[3],
2506 trans_id.Data4[4], trans_id.Data4[5],
2507 trans_id.Data4[6], trans_id.Data4[7]);
2508 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2509 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2510 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_ack_trans_id, tvb,
2511 offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2515 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2516 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
2520 * XXX - do we need to do anything with the authentication level
2521 * we get back from this?
2523 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2525 if (check_col (pinfo->cinfo, COL_INFO)) {
2526 if (num_results != 0 && result == 0) {
2527 /* XXX - only checks the last result */
2528 col_append_fstr (pinfo->cinfo, COL_INFO,
2529 " accept max_xmit: %u max_recv: %u",
2530 max_xmit, max_recv);
2532 /* XXX - only shows the last result and reason */
2533 col_append_fstr (pinfo->cinfo, COL_INFO, " %s, reason: %s",
2534 val_to_str(result, p_cont_result_vals,
2535 "Unknown result (%u)"),
2536 val_to_str(reason, p_provider_reason_vals,
2543 dissect_dcerpc_cn_bind_nak (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2544 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2547 guint8 num_protocols;
2550 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2551 hdr->drep, hf_dcerpc_cn_reject_reason,
2554 if (check_col (pinfo->cinfo, COL_INFO)) {
2555 col_append_fstr (pinfo->cinfo, COL_INFO, " reason: %s",
2556 val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
2559 if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
2560 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2561 hf_dcerpc_cn_num_protocols,
2564 for (i = 0; i < num_protocols; i++) {
2565 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2566 hdr->drep, hf_dcerpc_cn_protocol_ver_major,
2568 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2569 hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
2575 /* Return a string describing a DCE/RPC fragment as first, middle, or end
2578 #define PFC_FRAG_MASK 0x03
2581 fragment_type(guint8 flags)
2583 flags = flags & PFC_FRAG_MASK;
2585 if (flags == PFC_FIRST_FRAG)
2591 if (flags == PFC_LAST_FRAG)
2594 if (flags == (PFC_FIRST_FRAG | PFC_LAST_FRAG))
2600 /* Dissect stub data (payload) of a DCERPC packet. */
2603 dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
2604 proto_tree *dcerpc_tree, proto_tree *tree,
2605 e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
2606 dcerpc_auth_info *auth_info, guint32 alloc_hint,
2609 gint length, reported_length;
2610 gboolean save_fragmented;
2611 fragment_data *fd_head=NULL;
2613 tvbuff_t *payload_tvb, *decrypted_tvb;
2616 save_fragmented = pinfo->fragmented;
2618 length = tvb_length_remaining(tvb, offset);
2619 reported_length = tvb_reported_length_remaining(tvb, offset);
2620 if (reported_length < 0 ||
2621 (guint32)reported_length < auth_info->auth_size) {
2622 /* We don't even have enough bytes for the authentication
2626 reported_length -= auth_info->auth_size;
2627 if (length > reported_length)
2628 length = reported_length;
2629 payload_tvb = tvb_new_subset(tvb, offset, length, reported_length);
2631 /* Decrypt the PDU if it is encrypted */
2633 if (auth_info->auth_type &&
2634 auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
2636 * We know the authentication type, and the authentication
2637 * level is "Packet privacy", meaning the payload is
2638 * encrypted; attempt to decrypt it.
2640 dcerpc_auth_subdissector_fns *auth_fns;
2642 /* Start out assuming we won't succeed in decrypting. */
2643 decrypted_tvb = NULL;
2645 if ((auth_fns = get_auth_subdissector_fns(
2646 auth_info->auth_level, auth_info->auth_type))) {
2649 result = decode_encrypted_data(
2650 payload_tvb, pinfo, auth_fns,
2651 hdr->ptype == PDU_REQ, auth_info);
2655 proto_tree_add_text(
2656 dcerpc_tree, payload_tvb, 0, -1,
2657 "Encrypted stub data (%d byte%s)",
2658 tvb_reported_length(payload_tvb),
2660 plurality(tvb_length(payload_tvb), "", "s"));
2662 add_new_data_source(
2663 pinfo, result, "Decrypted stub data");
2666 decrypted_tvb = result;
2670 decrypted_tvb = payload_tvb;
2672 /* if this packet is not fragmented, just dissect it and exit */
2673 if(PFC_NOT_FRAGMENTED(hdr)){
2674 pinfo->fragmented = FALSE;
2677 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
2678 hdr->drep, di, auth_info);
2680 pinfo->fragmented = save_fragmented;
2684 /* The packet is fragmented. */
2685 pinfo->fragmented = TRUE;
2687 /* if we are not doing reassembly and this is the first fragment
2688 then just dissect it and exit
2689 XXX - if we're not doing reassembly, can we decrypt an
2692 if( (!dcerpc_reassemble) && hdr->flags&PFC_FIRST_FRAG ){
2695 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
2696 hdr->drep, di, auth_info);
2698 if (check_col(pinfo->cinfo, COL_INFO)) {
2699 col_append_fstr(pinfo->cinfo, COL_INFO,
2700 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
2702 pinfo->fragmented = save_fragmented;
2706 /* if we have already seen this packet, see if it was reassembled
2707 and if so dissect the full pdu.
2710 if(pinfo->fd->flags.visited){
2711 fd_head=fragment_get(pinfo, frame, dcerpc_co_reassemble_table);
2715 /* if we are not doing reassembly and it was neither a complete PDU
2716 nor the first fragment then there is nothing more we can do
2717 so we just have to exit
2719 if( !dcerpc_reassemble )
2722 /* if we didnt get 'frame' we dont know where the PDU started and thus
2723 it is pointless to continue
2728 /* from now on we must attempt to reassemble the PDU
2731 /* if we get here we know it is the first time we see the packet
2732 and we also know it is only a fragment and not a full PDU,
2733 thus we must reassemble it.
2736 /* Do we have any non-encrypted data to reassemble? */
2737 if (decrypted_tvb == NULL) {
2738 /* No. We can't even try to reassemble. */
2742 /* if this is the first fragment we need to start reassembly
2744 if(hdr->flags&PFC_FIRST_FRAG){
2745 fragment_add(decrypted_tvb, 0, pinfo, frame, dcerpc_co_reassemble_table,
2746 0, tvb_length(decrypted_tvb), TRUE);
2747 fragment_set_tot_len(pinfo, frame,
2748 dcerpc_co_reassemble_table, alloc_hint);
2753 /* if this is a middle fragment, just add it and exit */
2754 if(!(hdr->flags&PFC_LAST_FRAG)){
2755 tot_len = fragment_get_tot_len(pinfo, frame,
2756 dcerpc_co_reassemble_table);
2757 fragment_add(decrypted_tvb, 0, pinfo, frame,
2758 dcerpc_co_reassemble_table,
2759 tot_len-alloc_hint, tvb_length(decrypted_tvb),
2765 /* this was the last fragment add it to reassembly
2767 tot_len = fragment_get_tot_len(pinfo, frame,
2768 dcerpc_co_reassemble_table);
2769 fd_head = fragment_add(decrypted_tvb, 0, pinfo,
2771 dcerpc_co_reassemble_table,
2772 tot_len-alloc_hint, tvb_length(decrypted_tvb),
2777 /* if reassembly is complete, dissect the full PDU
2779 if(fd_head && (fd_head->flags&FD_DEFRAGMENTED) ){
2781 if(pinfo->fd->num==fd_head->reassembled_in){
2784 next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
2785 tvb_set_child_real_data_tvbuff(decrypted_tvb, next_tvb);
2786 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
2787 show_fragment_tree(fd_head, &dcerpc_frag_items,
2788 dcerpc_tree, pinfo, next_tvb);
2790 pinfo->fragmented = FALSE;
2792 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
2793 next_tvb, hdr->drep, di, auth_info);
2796 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
2797 decrypted_tvb, 0, 0, fd_head->reassembled_in);
2798 PROTO_ITEM_SET_GENERATED(pi);
2799 if (check_col(pinfo->cinfo, COL_INFO)) {
2800 col_append_fstr(pinfo->cinfo, COL_INFO,
2801 " [DCE/RPC %s fragment, reas: #%u]", fragment_type(hdr->flags), fd_head->reassembled_in);
2805 /* Reassembly not complete - some fragments
2806 are missing. Just show the stub data. */
2808 if (check_col(pinfo->cinfo, COL_INFO)) {
2809 col_append_fstr(pinfo->cinfo, COL_INFO,
2810 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
2814 show_stub_data (decrypted_tvb, 0, tree, auth_info, FALSE);
2816 show_stub_data (payload_tvb, 0, tree, auth_info, TRUE);
2820 pinfo->fragmented = save_fragmented;
2824 * Registers a conversation/UUID binding association, so that
2825 * we can invoke the proper sub-dissector for a given DCERPC
2828 * @param binding all values needed to create and bind a new conversation
2830 * @return Pointer to newly-added UUID/conversation binding.
2832 struct _dcerpc_bind_value *
2833 dcerpc_add_conv_to_bind_table(decode_dcerpc_bind_values_t *binding)
2835 dcerpc_bind_value *bind_value;
2836 dcerpc_bind_key *key;
2837 conversation_t *conv;
2839 conv = find_conversation (
2848 conv = conversation_new (
2857 bind_value = g_mem_chunk_alloc (dcerpc_bind_value_chunk);
2858 bind_value->uuid = binding->uuid;
2859 bind_value->ver = binding->ver;
2861 key = g_mem_chunk_alloc(dcerpc_bind_key_chunk);
2863 key->ctx_id = binding->ctx_id;
2864 key->smb_fid = binding->smb_fid;
2866 /* add this entry to the bind table, first removing any
2867 previous ones that are identical
2869 if(g_hash_table_lookup(dcerpc_binds, key)){
2870 g_hash_table_remove(dcerpc_binds, key);
2872 g_hash_table_insert(dcerpc_binds, key, bind_value);
2879 dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2880 proto_tree *dcerpc_tree, proto_tree *tree,
2881 e_dce_cn_common_hdr_t *hdr, int transport_type)
2883 conversation_t *conv;
2887 dcerpc_auth_info auth_info;
2889 char uuid_str[DCERPC_UUID_STR_LEN];
2893 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2894 hf_dcerpc_cn_alloc_hint, &alloc_hint);
2896 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2897 hf_dcerpc_cn_ctx_id, &ctx_id);
2899 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2900 hf_dcerpc_opnum, &opnum);
2902 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
2903 pinfo->dcectxid = ctx_id;
2904 pinfo->dcetransporttype = transport_type;
2906 if (check_col (pinfo->cinfo, COL_INFO)) {
2907 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u ctx_id: %u",
2911 if (hdr->flags & PFC_OBJECT_UUID) {
2912 /* XXX - use "dissect_ndr_uuid_t()"? */
2913 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id);
2915 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2916 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2917 obj_id.Data1, obj_id.Data2, obj_id.Data3,
2926 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2927 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2928 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
2929 offset, 16, uuid_str, "Object UUID: %s", uuid_str);
2935 * XXX - what if this was set when the connection was set up,
2936 * and we just have a security context?
2938 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
2940 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2941 pinfo->srcport, pinfo->destport, 0);
2943 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
2945 dcerpc_matched_key matched_key, *new_matched_key;
2946 dcerpc_call_value *value;
2948 /* !!! we can NOT check flags.visited here since this will interact
2949 badly with when SMB handles (i.e. calls the subdissector)
2950 and desegmented pdu's .
2951 Instead we check if this pdu is already in the matched table or not
2953 matched_key.frame = pinfo->fd->num;
2954 matched_key.call_id = hdr->call_id;
2955 value = g_hash_table_lookup(dcerpc_matched, &matched_key);
2957 dcerpc_bind_key bind_key;
2958 dcerpc_bind_value *bind_value;
2961 bind_key.ctx_id=ctx_id;
2962 bind_key.smb_fid=dcerpc_get_transport_salt(pinfo, transport_type);
2964 if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key)) ){
2965 if(!(hdr->flags&PFC_FIRST_FRAG)){
2966 dcerpc_cn_call_key call_key;
2967 dcerpc_call_value *call_value;
2970 call_key.call_id=hdr->call_id;
2971 call_key.smb_fid=dcerpc_get_transport_salt(pinfo, transport_type);
2972 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
2973 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
2974 *new_matched_key = matched_key;
2975 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
2979 dcerpc_cn_call_key *call_key;
2980 dcerpc_call_value *call_value;
2982 /* We found the binding and it is the first fragment
2983 (or a complete PDU) of a dcerpc pdu so just add
2984 the call to both the call table and the
2987 call_key=g_mem_chunk_alloc (dcerpc_cn_call_key_chunk);
2988 call_key->conv=conv;
2989 call_key->call_id=hdr->call_id;
2990 call_key->smb_fid=dcerpc_get_transport_salt(pinfo, transport_type);
2992 /* if there is already a matching call in the table
2993 remove it so it is replaced with the new one */
2994 if(g_hash_table_lookup(dcerpc_cn_calls, call_key)){
2995 g_hash_table_remove(dcerpc_cn_calls, call_key);
2998 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
2999 call_value->uuid = bind_value->uuid;
3000 call_value->ver = bind_value->ver;
3001 call_value->opnum = opnum;
3002 call_value->req_frame=pinfo->fd->num;
3003 call_value->req_time.secs=pinfo->fd->abs_secs;
3004 call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000;
3005 call_value->rep_frame=0;
3006 call_value->max_ptr=0;
3007 call_value->private_data = NULL;
3008 g_hash_table_insert (dcerpc_cn_calls, call_key, call_value);
3010 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3011 *new_matched_key = matched_key;
3012 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3022 /* handoff this call */
3024 di->call_id = hdr->call_id;
3025 di->smb_fid = dcerpc_get_transport_salt(pinfo, transport_type);
3026 di->ptype = PDU_REQ;
3027 di->call_data = value;
3030 if(value->rep_frame!=0){
3031 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
3032 tvb, 0, 0, value->rep_frame);
3033 PROTO_ITEM_SET_GENERATED(pi);
3036 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
3037 hdr, di, &auth_info, alloc_hint,
3040 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3043 /* Dissect the verifier */
3044 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
3049 dissect_dcerpc_cn_resp (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3050 proto_tree *dcerpc_tree, proto_tree *tree,
3051 e_dce_cn_common_hdr_t *hdr, int transport_type)
3053 dcerpc_call_value *value = NULL;
3054 conversation_t *conv;
3056 dcerpc_auth_info auth_info;
3060 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3061 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3063 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3064 hf_dcerpc_cn_ctx_id, &ctx_id);
3066 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3067 pinfo->dcectxid = ctx_id;
3068 pinfo->dcetransporttype = transport_type;
3070 if (check_col (pinfo->cinfo, COL_INFO)) {
3071 col_append_fstr (pinfo->cinfo, COL_INFO, " ctx_id: %u", ctx_id);
3074 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3075 hf_dcerpc_cn_cancel_count, NULL);
3080 * XXX - what if this was set when the connection was set up,
3081 * and we just have a security context?
3083 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3085 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
3086 pinfo->srcport, pinfo->destport, 0);
3089 /* no point in creating one here, really */
3090 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3092 dcerpc_matched_key matched_key, *new_matched_key;
3094 /* !!! we can NOT check flags.visited here since this will interact
3095 badly with when SMB handles (i.e. calls the subdissector)
3096 and desegmented pdu's .
3097 Instead we check if this pdu is already in the matched table or not
3099 matched_key.frame = pinfo->fd->num;
3100 matched_key.call_id = hdr->call_id;
3101 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3103 dcerpc_cn_call_key call_key;
3104 dcerpc_call_value *call_value;
3107 call_key.call_id=hdr->call_id;
3108 call_key.smb_fid=dcerpc_get_transport_salt(pinfo, transport_type);
3110 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3111 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3112 *new_matched_key = matched_key;
3113 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3115 if(call_value->rep_frame==0){
3116 call_value->rep_frame=pinfo->fd->num;
3125 /* handoff this call */
3127 di->call_id = hdr->call_id;
3128 di->smb_fid = dcerpc_get_transport_salt(pinfo, transport_type);
3129 di->ptype = PDU_RESP;
3130 di->call_data = value;
3132 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
3133 if(value->req_frame!=0){
3135 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3136 tvb, 0, 0, value->req_frame);
3137 PROTO_ITEM_SET_GENERATED(pi);
3138 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
3139 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
3141 ns.nsecs+=1000000000;
3144 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
3145 PROTO_ITEM_SET_GENERATED(pi);
3148 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
3149 hdr, di, &auth_info, alloc_hint,
3152 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3155 /* Dissect the verifier */
3156 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
3160 dissect_dcerpc_cn_fault (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3161 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
3164 dcerpc_call_value *value = NULL;
3165 conversation_t *conv;
3169 dcerpc_auth_info auth_info;
3172 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3173 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3175 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3176 hf_dcerpc_cn_ctx_id, &ctx_id);
3178 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3179 hf_dcerpc_cn_cancel_count, NULL);
3183 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3184 hf_dcerpc_cn_status, &status);
3186 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3187 pinfo->dcectxid = ctx_id;
3188 pinfo->dcetransporttype = transport_type;
3190 if (check_col (pinfo->cinfo, COL_INFO)) {
3191 col_append_fstr (pinfo->cinfo, COL_INFO,
3192 " ctx_id: %u status: %s", ctx_id,
3193 val_to_str(status, reject_status_vals,
3194 "Unknown (0x%08x)"));
3201 * XXX - what if this was set when the connection was set up,
3202 * and we just have a security context?
3204 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3206 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
3207 pinfo->srcport, pinfo->destport, 0);
3209 /* no point in creating one here, really */
3211 dcerpc_matched_key matched_key, *new_matched_key;
3213 /* !!! we can NOT check flags.visited here since this will interact
3214 badly with when SMB handles (i.e. calls the subdissector)
3215 and desegmented pdu's .
3216 Instead we check if this pdu is already in the matched table or not
3218 matched_key.frame = pinfo->fd->num;
3219 matched_key.call_id = hdr->call_id;
3220 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3222 dcerpc_cn_call_key call_key;
3223 dcerpc_call_value *call_value;
3226 call_key.call_id=hdr->call_id;
3227 call_key.smb_fid=dcerpc_get_transport_salt(pinfo, transport_type);
3229 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3230 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3231 *new_matched_key = matched_key;
3232 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3234 if(call_value->rep_frame==0){
3235 call_value->rep_frame=pinfo->fd->num;
3242 int length, reported_length, stub_length;
3246 /* handoff this call */
3248 di->call_id = hdr->call_id;
3249 di->smb_fid = dcerpc_get_transport_salt(pinfo, transport_type);
3250 di->ptype = PDU_FAULT;
3251 di->call_data = value;
3253 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
3254 if(value->req_frame!=0){
3256 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3257 tvb, 0, 0, value->req_frame);
3258 PROTO_ITEM_SET_GENERATED(pi);
3259 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
3260 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
3262 ns.nsecs+=1000000000;
3265 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
3266 PROTO_ITEM_SET_GENERATED(pi);
3269 length = tvb_length_remaining(tvb, offset);
3270 reported_length = tvb_reported_length_remaining(tvb, offset);
3271 stub_length = hdr->frag_len - offset - auth_info.auth_size;
3272 if (length > stub_length)
3273 length = stub_length;
3274 if (reported_length > stub_length)
3275 reported_length = stub_length;
3277 /* If we don't have reassembly enabled, or this packet contains
3278 the entire PDU, or if we don't have all the data in this
3279 fragment, just call the handoff directly if this is the
3280 first fragment or the PDU isn't fragmented. */
3281 if( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
3282 !tvb_bytes_exist(tvb, offset, stub_length) ){
3283 if(hdr->flags&PFC_FIRST_FRAG){
3284 /* First fragment, possibly the only fragment */
3286 * XXX - should there be a third routine for each
3287 * function in an RPC subdissector, to handle
3288 * fault responses? The DCE RPC 1.1 spec says
3289 * three's "stub data" here, which I infer means
3290 * that it's protocol-specific and call-specific.
3292 * It should probably get passed the status code
3293 * as well, as that might be protocol-specific.
3296 if (stub_length > 0) {
3297 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3298 "Fault stub data (%d byte%s)",
3300 plurality(stub_length, "", "s"));
3304 /* PDU is fragmented and this isn't the first fragment */
3305 if (check_col(pinfo->cinfo, COL_INFO)) {
3306 col_append_fstr(pinfo->cinfo, COL_INFO,
3307 " [DCE/RPC fragment]");
3310 if (stub_length > 0) {
3311 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3312 "Fragment data (%d byte%s)",
3314 plurality(stub_length, "", "s"));
3319 /* Reassembly is enabled, the PDU is fragmented, and
3320 we have all the data in the fragment; the first two
3321 of those mean we should attempt reassembly, and the
3322 third means we can attempt reassembly. */
3325 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3326 "Fragment data (%d byte%s)",
3328 plurality(stub_length, "", "s"));
3331 if(hdr->flags&PFC_FIRST_FRAG){ /* FIRST fragment */
3332 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
3333 fragment_add(tvb, offset, pinfo, value->rep_frame,
3334 dcerpc_co_reassemble_table,
3338 fragment_set_tot_len(pinfo, value->rep_frame,
3339 dcerpc_co_reassemble_table, alloc_hint);
3341 if (check_col(pinfo->cinfo, COL_INFO)) {
3342 col_append_fstr(pinfo->cinfo, COL_INFO,
3343 " [DCE/RPC fragment]");
3345 } else if(hdr->flags&PFC_LAST_FRAG){ /* LAST fragment */
3346 if( value->rep_frame ){
3347 fragment_data *fd_head;
3350 tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
3351 dcerpc_co_reassemble_table);
3352 fd_head = fragment_add(tvb, offset, pinfo,
3354 dcerpc_co_reassemble_table,
3360 /* We completed reassembly */
3363 next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
3364 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
3365 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3366 show_fragment_tree(fd_head, &dcerpc_frag_items,
3367 dcerpc_tree, pinfo, next_tvb);
3370 * XXX - should there be a third routine for each
3371 * function in an RPC subdissector, to handle
3372 * fault responses? The DCE RPC 1.1 spec says
3373 * three's "stub data" here, which I infer means
3374 * that it's protocol-specific and call-specific.
3376 * It should probably get passed the status code
3377 * as well, as that might be protocol-specific.
3381 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3382 "Fault stub data (%d byte%s)",
3384 plurality(stub_length, "", "s"));
3388 /* Reassembly not complete - some fragments
3390 if (check_col(pinfo->cinfo, COL_INFO)) {
3391 col_append_fstr(pinfo->cinfo, COL_INFO,
3392 " [DCE/RPC fragment]");
3396 } else { /* MIDDLE fragment(s) */
3397 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
3399 tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
3400 dcerpc_co_reassemble_table);
3401 fragment_add(tvb, offset, pinfo, value->rep_frame,
3402 dcerpc_co_reassemble_table,
3407 if (check_col(pinfo->cinfo, COL_INFO)) {
3408 col_append_fstr(pinfo->cinfo, COL_INFO,
3409 " [DCE/RPC fragment]");
3418 * DCERPC dissector for connection oriented calls.
3419 * We use transport type to later multiplex between what kind of
3420 * pinfo->private_data structure to expect.
3423 dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
3424 proto_tree *tree, gboolean can_desegment, int *pkt_len,
3427 static const guint8 nulls[4] = { 0 };
3430 proto_item *ti = NULL;
3431 proto_item *tf = NULL;
3432 proto_tree *dcerpc_tree = NULL;
3433 proto_tree *cn_flags_tree = NULL;
3434 proto_tree *drep_tree = NULL;
3435 e_dce_cn_common_hdr_t hdr;
3436 dcerpc_auth_info auth_info;
3439 * when done over nbt, dcerpc requests are padded with 4 bytes of null
3440 * data for some reason.
3442 * XXX - if that's always the case, the right way to do this would
3443 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
3444 * the 4 bytes of null padding, and make that the dissector
3445 * used for "netbios".
3447 if (tvb_memeql (tvb, offset, nulls, 4) == 0) {
3457 * Check if this looks like a C/O DCERPC call
3459 if (!tvb_bytes_exist (tvb, offset, sizeof (hdr))) {
3460 return FALSE; /* not enough information to check */
3462 start_offset = offset;
3463 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
3464 if (hdr.rpc_ver != 5)
3466 hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
3467 if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
3469 hdr.ptype = tvb_get_guint8 (tvb, offset++);
3473 hdr.flags = tvb_get_guint8 (tvb, offset++);
3474 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
3475 offset += sizeof (hdr.drep);
3477 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3479 hdr.auth_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3481 hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3484 if (can_desegment && pinfo->can_desegment
3485 && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
3486 pinfo->desegment_offset = start_offset;
3487 pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, start_offset);
3488 *pkt_len = 0; /* desegmentation required */
3492 if (check_col (pinfo->cinfo, COL_PROTOCOL))
3493 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
3494 if (check_col (pinfo->cinfo, COL_INFO))
3495 col_add_fstr (pinfo->cinfo, COL_INFO, "%s: call_id: %u",
3496 pckt_vals[hdr.ptype].strptr, hdr.call_id);
3499 offset = start_offset;
3500 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE);
3502 dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
3504 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver);
3505 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset++, 1, hdr.rpc_ver_minor);
3506 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype);
3507 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
3508 cn_flags_tree = proto_item_add_subtree (tf, ett_dcerpc_cn_flags);
3509 if (cn_flags_tree) {
3510 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
3511 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
3512 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
3513 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
3514 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
3515 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
3516 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
3517 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
3521 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
3522 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
3524 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
3525 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
3526 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
3528 offset += sizeof (hdr.drep);
3530 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
3533 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
3536 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
3541 * None of the stuff done above should throw an exception, because
3542 * we would have rejected this as "not DCE RPC" if we didn't have all
3543 * of it. (XXX - perhaps we should request reassembly if we have
3544 * enough of the header to consider it DCE RPC but not enough to
3545 * get the fragment length; in that case the stuff still wouldn't
3546 * throw an exception.)
3548 * The rest of the stuff might, so return the PDU length to our caller.
3549 * XXX - should we construct a tvbuff containing only the PDU and
3550 * use that? Or should we have separate "is this a DCE RPC PDU",
3551 * "how long is it", and "dissect it" routines - which might let us
3552 * do most of the work in "tcp_dissect_pdus()"?
3554 if (pkt_len != NULL)
3555 *pkt_len = hdr.frag_len + padding;
3558 * Packet type specific stuff is next.
3560 switch (hdr.ptype) {
3563 dissect_dcerpc_cn_bind (tvb, offset, pinfo, dcerpc_tree, &hdr, transport_type);
3568 dissect_dcerpc_cn_bind_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3573 * Nothing after the common header other than credentials.
3575 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, TRUE,
3580 dissect_dcerpc_cn_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, transport_type);
3584 dissect_dcerpc_cn_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, transport_type);
3588 dissect_dcerpc_cn_fault (tvb, offset, pinfo, dcerpc_tree, &hdr, transport_type);
3592 dissect_dcerpc_cn_bind_nak (tvb, offset, pinfo, dcerpc_tree, &hdr);
3598 * Nothing after the common header other than an authentication
3601 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
3607 * Nothing after the common header, not even an authentication
3613 /* might as well dissect the auth info */
3614 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
3622 * DCERPC dissector for connection oriented calls over packet-oriented
3626 dissect_dcerpc_cn_pk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3629 * Only one PDU per transport packet, and only one transport
3632 if (!dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE, NULL, DCE_TRANSPORT_UNKNOWN)) {
3634 * It wasn't a DCERPC PDU.
3646 * DCERPC dissector for connection oriented calls over byte-stream
3648 * we need to distinguish here between SMB and non-TCP (more in the future?)
3649 * to be able to know what kind of private_data structure to expect.
3652 dissect_dcerpc_cn_bs_body (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int transport_type)
3654 volatile int offset = 0;
3656 volatile gboolean is_dcerpc_pdu;
3657 volatile gboolean ret = FALSE;
3660 * There may be multiple PDUs per transport packet; keep
3663 while (tvb_reported_length_remaining(tvb, offset) != 0) {
3665 * Catch ReportedBoundsError, so that even if the stub data is bad,
3666 * we don't abort the full DCE RPC dissection - there might be more
3667 * than one DCE RPC PDU in the data being dissected.
3669 * If we get BoundsError, it means the frame was cut short by a
3670 * snapshot length, so there's nothing more to dissect; just
3671 * re-throw that exception.
3673 is_dcerpc_pdu = FALSE;
3675 is_dcerpc_pdu = dissect_dcerpc_cn (tvb, offset, pinfo, tree,
3676 dcerpc_cn_desegment, &pdu_len,
3678 } CATCH(BoundsError) {
3680 } CATCH(ReportedBoundsError) {
3681 show_reported_bounds_error(tvb, pinfo, tree);
3684 if (!is_dcerpc_pdu) {
3692 * Well, we've seen at least one DCERPC PDU.
3698 * Desegmentation required - bail now.
3704 * Step to the next PDU.
3712 dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3714 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree, DCE_TRANSPORT_UNKNOWN);
3718 dissect_dcerpc_cn_smbpipe (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3720 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree, DCE_CN_TRANSPORT_SMBPIPE);
3726 dissect_dcerpc_dg_auth (tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
3727 e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
3729 proto_item *ti = NULL;
3730 proto_tree *auth_tree = NULL;
3731 guint8 protection_level;
3734 * Initially set "*auth_level_p" to -1 to indicate that we haven't
3735 * yet seen any authentication level information.
3737 if (auth_level_p != NULL)
3741 * The authentication information is at the *end* of the PDU; in
3742 * request and response PDUs, the request and response stub data
3745 * If the full packet is here, and there's data past the end of the
3746 * packet body, then dissect the auth info.
3748 offset += hdr->frag_len;
3749 if (tvb_length_remaining(tvb, offset) > 0) {
3750 switch (hdr->auth_proto) {
3752 case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
3753 ti = proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Kerberos authentication verifier");
3754 auth_tree = proto_item_add_subtree (ti, ett_dcerpc_krb5_auth_verf);
3755 protection_level = tvb_get_guint8 (tvb, offset);
3756 if (auth_level_p != NULL)
3757 *auth_level_p = protection_level;
3758 proto_tree_add_uint (auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
3760 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, FALSE);
3762 if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
3763 offset += 6; /* 6 bytes of padding */
3765 offset += 2; /* 6 bytes of padding */
3766 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, FALSE);
3771 proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Authentication verifier");
3778 dissect_dcerpc_dg_cancel_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
3779 proto_tree *dcerpc_tree,
3780 e_dce_dg_common_hdr_t *hdr)
3784 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3785 hdr->drep, hf_dcerpc_dg_cancel_vers,
3791 /* The only version we know about */
3792 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3793 hdr->drep, hf_dcerpc_dg_cancel_id,
3795 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
3796 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
3803 dissect_dcerpc_dg_cancel (tvbuff_t *tvb, int offset, packet_info *pinfo,
3804 proto_tree *dcerpc_tree,
3805 e_dce_dg_common_hdr_t *hdr)
3809 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3810 hdr->drep, hf_dcerpc_dg_cancel_vers,
3816 /* The only version we know about */
3817 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3818 hdr->drep, hf_dcerpc_dg_cancel_id,
3820 /* XXX - are NDR booleans 32 bits? */
3822 /* XXX - the RPC reference in chapter: "the cancel PDU" doesn't mention
3823 the accepting_cancels field (it's only in the cancel_ack PDU)! */
3824 /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3825 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
3832 dissect_dcerpc_dg_fack (tvbuff_t *tvb, int offset, packet_info *pinfo,
3833 proto_tree *dcerpc_tree,
3834 e_dce_dg_common_hdr_t *hdr)
3841 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
3842 hdr->drep, hf_dcerpc_dg_fack_vers,
3849 case 0: /* The only version documented in the DCE RPC 1.1 spec */
3850 case 1: /* This appears to be the same */
3851 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
3852 hdr->drep, hf_dcerpc_dg_fack_window_size,
3854 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3855 hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
3857 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3858 hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
3860 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
3861 hdr->drep, hf_dcerpc_dg_fack_serial_num,
3863 if (check_col (pinfo->cinfo, COL_INFO)) {
3864 col_append_fstr (pinfo->cinfo, COL_INFO, " serial: %u",
3867 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
3868 hdr->drep, hf_dcerpc_dg_fack_selack_len,
3870 for (i = 0; i < selack_len; i++) {
3871 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3872 hdr->drep, hf_dcerpc_dg_fack_selack,
3881 dissect_dcerpc_dg_reject_fault (tvbuff_t *tvb, int offset, packet_info *pinfo,
3882 proto_tree *dcerpc_tree,
3883 e_dce_dg_common_hdr_t *hdr)
3887 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3888 hdr->drep, hf_dcerpc_dg_status,
3891 if (check_col (pinfo->cinfo, COL_INFO)) {
3892 col_append_fstr (pinfo->cinfo, COL_INFO,
3894 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
3899 dissect_dcerpc_dg_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
3900 proto_tree *dcerpc_tree, proto_tree *tree,
3901 e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
3903 int length, reported_length, stub_length;
3904 gboolean save_fragmented;
3905 fragment_data *fd_head;
3909 if (check_col (pinfo->cinfo, COL_INFO))
3910 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u len: %u",
3911 di->call_data->opnum, hdr->frag_len );
3913 length = tvb_length_remaining (tvb, offset);
3914 reported_length = tvb_reported_length_remaining (tvb, offset);
3915 stub_length = hdr->frag_len;
3916 if (length > stub_length)
3917 length = stub_length;
3918 if (reported_length > stub_length)
3919 reported_length = stub_length;
3921 save_fragmented = pinfo->fragmented;
3923 /* If we don't have reassembly enabled, or this packet contains
3924 the entire PDU, or if this is a short frame (or a frame
3925 not reassembled at a lower layer) that doesn't include all
3926 the data in the fragment, just call the handoff directly if
3927 this is the first fragment or the PDU isn't fragmented. */
3928 if( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
3929 !tvb_bytes_exist(tvb, offset, stub_length) ){
3930 if(hdr->frag_num == 0) {
3933 /* First fragment, possibly the only fragment */
3936 * XXX - authentication info?
3938 pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
3939 next_tvb = tvb_new_subset (tvb, offset, length,
3941 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
3942 next_tvb, hdr->drep, di, NULL);
3944 /* PDU is fragmented and this isn't the first fragment */
3945 if (check_col(pinfo->cinfo, COL_INFO)) {
3946 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
3950 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3951 "Fragment data (%d byte%s)",
3953 plurality(stub_length, "", "s"));
3958 /* Reassembly is enabled, the PDU is fragmented, and
3959 we have all the data in the fragment; the first two
3960 of those mean we should attempt reassembly, and the
3961 third means we can attempt reassembly. */
3964 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3965 "Fragment data (%d byte%s)", stub_length,
3966 plurality(stub_length, "", "s"));
3970 fd_head = fragment_add_dcerpc(tvb, offset, pinfo,
3971 hdr->seqnum, &hdr->act_id, dcerpc_cl_reassemble_table,
3972 hdr->frag_num, stub_length,
3973 !(hdr->flags1 & PFCL1_LASTFRAG));
3974 if (fd_head != NULL) {
3975 /* We completed reassembly... */
3976 if(pinfo->fd->num==fd_head->reassembled_in) {
3977 /* ...and this is the reassembled RPC PDU */
3978 next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
3979 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
3980 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3981 show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
3982 dcerpc_tree, pinfo, next_tvb);
3985 * XXX - authentication info?
3987 pinfo->fragmented = FALSE;
3988 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
3989 next_tvb, hdr->drep, di, NULL);
3991 /* ...and this isn't the reassembled RPC PDU */
3992 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
3993 tvb, 0, 0, fd_head->reassembled_in);
3994 PROTO_ITEM_SET_GENERATED(pi);
3995 if (check_col(pinfo->cinfo, COL_INFO)) {
3996 col_append_fstr(pinfo->cinfo, COL_INFO,
3997 " [DCE/RPC fragment, reas: #%u]", fd_head->reassembled_in);
4001 /* Reassembly isn't completed yet */
4002 if (check_col(pinfo->cinfo, COL_INFO)) {
4003 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
4007 pinfo->fragmented = save_fragmented;
4011 dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo,
4012 proto_tree *dcerpc_tree, proto_tree *tree,
4013 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4016 dcerpc_call_value *value, v;
4017 dcerpc_matched_key matched_key, *new_matched_key;
4021 if(!(pinfo->fd->flags.visited)){
4022 dcerpc_call_value *call_value;
4023 dcerpc_dg_call_key *call_key;
4025 call_key=g_mem_chunk_alloc (dcerpc_dg_call_key_chunk);
4026 call_key->conv=conv;
4027 call_key->seqnum=hdr->seqnum;
4028 call_key->act_id=hdr->act_id;
4030 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
4031 call_value->uuid = hdr->if_id;
4032 call_value->ver = hdr->if_ver;
4033 call_value->opnum = hdr->opnum;
4034 call_value->req_frame=pinfo->fd->num;
4035 call_value->req_time.secs=pinfo->fd->abs_secs;
4036 call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000;
4037 call_value->rep_frame=0;
4038 call_value->max_ptr=0;
4039 call_value->private_data = NULL;
4040 g_hash_table_insert (dcerpc_dg_calls, call_key, call_value);
4042 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
4043 new_matched_key->frame = pinfo->fd->num;
4044 new_matched_key->call_id = hdr->seqnum;
4045 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
4048 matched_key.frame = pinfo->fd->num;
4049 matched_key.call_id = hdr->seqnum;
4050 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
4052 v.uuid = hdr->if_id;
4053 v.ver = hdr->if_ver;
4054 v.opnum = hdr->opnum;
4055 v.req_frame = pinfo->fd->num;
4058 v.private_data=NULL;
4063 di->call_id = hdr->seqnum;
4065 di->ptype = PDU_REQ;
4066 di->call_data = value;
4068 if(value->rep_frame!=0){
4069 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
4070 tvb, 0, 0, value->rep_frame);
4071 PROTO_ITEM_SET_GENERATED(pi);
4073 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
4077 dissect_dcerpc_dg_resp (tvbuff_t *tvb, int offset, packet_info *pinfo,
4078 proto_tree *dcerpc_tree, proto_tree *tree,
4079 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4082 dcerpc_call_value *value, v;
4083 dcerpc_matched_key matched_key, *new_matched_key;
4087 if(!(pinfo->fd->flags.visited)){
4088 dcerpc_call_value *call_value;
4089 dcerpc_dg_call_key call_key;
4092 call_key.seqnum=hdr->seqnum;
4093 call_key.act_id=hdr->act_id;
4095 if((call_value=g_hash_table_lookup(dcerpc_dg_calls, &call_key))){
4096 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
4097 new_matched_key->frame = pinfo->fd->num;
4098 new_matched_key->call_id = hdr->seqnum;
4099 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
4100 if(call_value->rep_frame==0){
4101 call_value->rep_frame=pinfo->fd->num;
4106 matched_key.frame = pinfo->fd->num;
4107 matched_key.call_id = hdr->seqnum;
4108 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
4110 v.uuid = hdr->if_id;
4111 v.ver = hdr->if_ver;
4112 v.opnum = hdr->opnum;
4114 v.rep_frame=pinfo->fd->num;
4115 v.private_data=NULL;
4122 di->ptype = PDU_RESP;
4123 di->call_data = value;
4125 if(value->req_frame!=0){
4127 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4128 tvb, 0, 0, value->req_frame);
4129 PROTO_ITEM_SET_GENERATED(pi);
4130 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
4131 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
4133 ns.nsecs+=1000000000;
4136 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
4137 PROTO_ITEM_SET_GENERATED(pi);
4139 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
4143 * DCERPC dissector for connectionless calls
4146 dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4148 proto_item *ti = NULL;
4149 proto_item *tf = NULL;
4150 proto_tree *dcerpc_tree = NULL;
4151 proto_tree *dg_flags1_tree = NULL;
4152 proto_tree *dg_flags2_tree = NULL;
4153 proto_tree *drep_tree = NULL;
4154 e_dce_dg_common_hdr_t hdr;
4156 conversation_t *conv;
4158 char uuid_str[DCERPC_UUID_STR_LEN];
4162 * Check if this looks like a CL DCERPC call. All dg packets
4163 * have an 80 byte header on them. Which starts with
4164 * version (4), pkt_type.
4166 if (!tvb_bytes_exist (tvb, 0, sizeof (hdr))) {
4169 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
4170 if (hdr.rpc_ver != 4)
4172 hdr.ptype = tvb_get_guint8 (tvb, offset++);
4176 if (check_col (pinfo->cinfo, COL_PROTOCOL))
4177 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
4178 if (check_col (pinfo->cinfo, COL_INFO))
4179 col_add_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
4181 hdr.flags1 = tvb_get_guint8 (tvb, offset++);
4182 hdr.flags2 = tvb_get_guint8 (tvb, offset++);
4183 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
4184 offset += sizeof (hdr.drep);
4185 hdr.serial_hi = tvb_get_guint8 (tvb, offset++);
4186 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.obj_id);
4188 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.if_id);
4190 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.act_id);
4192 hdr.server_boot = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4194 hdr.if_ver = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4196 hdr.seqnum = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4198 hdr.opnum = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4200 hdr.ihint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4202 hdr.ahint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4204 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4206 hdr.frag_num = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4208 hdr.auth_proto = tvb_get_guint8 (tvb, offset++);
4209 hdr.serial_lo = tvb_get_guint8 (tvb, offset++);
4212 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, -1, FALSE);
4214 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
4220 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
4224 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
4228 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
4229 dg_flags1_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags1);
4230 if (dg_flags1_tree) {
4231 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
4232 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
4233 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
4234 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
4235 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
4236 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
4237 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
4238 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
4244 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
4245 dg_flags2_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags2);
4246 if (dg_flags2_tree) {
4247 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
4248 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
4249 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
4250 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
4251 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
4252 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
4253 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
4254 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
4260 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
4261 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
4263 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
4264 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
4265 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
4268 offset += sizeof (hdr.drep);
4271 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
4275 /* XXX - use "dissect_ndr_uuid_t()"? */
4276 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
4277 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
4278 hdr.obj_id.Data1, hdr.obj_id.Data2, hdr.obj_id.Data3,
4279 hdr.obj_id.Data4[0],
4280 hdr.obj_id.Data4[1],
4281 hdr.obj_id.Data4[2],
4282 hdr.obj_id.Data4[3],
4283 hdr.obj_id.Data4[4],
4284 hdr.obj_id.Data4[5],
4285 hdr.obj_id.Data4[6],
4286 hdr.obj_id.Data4[7]);
4287 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
4288 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
4289 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
4290 offset, 16, uuid_str, "Object UUID: %s", uuid_str);
4295 /* XXX - use "dissect_ndr_uuid_t()"? */
4296 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
4297 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
4298 hdr.if_id.Data1, hdr.if_id.Data2, hdr.if_id.Data3,
4306 hdr.if_id.Data4[7]);
4307 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
4308 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
4309 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
4310 offset, 16, uuid_str, "Interface: %s", uuid_str);
4315 /* XXX - use "dissect_ndr_uuid_t()"? */
4316 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
4317 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
4318 hdr.act_id.Data1, hdr.act_id.Data2, hdr.act_id.Data3,
4319 hdr.act_id.Data4[0],
4320 hdr.act_id.Data4[1],
4321 hdr.act_id.Data4[2],
4322 hdr.act_id.Data4[3],
4323 hdr.act_id.Data4[4],
4324 hdr.act_id.Data4[5],
4325 hdr.act_id.Data4[6],
4326 hdr.act_id.Data4[7]);
4327 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
4328 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
4329 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
4330 offset, 16, uuid_str, "Activity: %s", uuid_str);
4335 nstime_t server_boot;
4337 server_boot.secs = hdr.server_boot;
4338 server_boot.nsecs = 0;
4340 if (hdr.server_boot == 0)
4341 proto_tree_add_time_format (dcerpc_tree, hf_dcerpc_dg_server_boot,
4342 tvb, offset, 4, &server_boot,
4343 "Server boot time: Unknown (0)");
4345 proto_tree_add_time (dcerpc_tree, hf_dcerpc_dg_server_boot,
4346 tvb, offset, 4, &server_boot);
4351 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
4355 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
4356 if (check_col (pinfo->cinfo, COL_INFO)) {
4357 col_append_fstr (pinfo->cinfo, COL_INFO, ": seq: %u", hdr.seqnum);
4362 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
4366 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
4370 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
4374 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
4378 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
4379 if (check_col (pinfo->cinfo, COL_INFO)) {
4380 if (hdr.flags1 & PFCL1_FRAG) {
4381 /* Fragmented - put the fragment number into the Info column */
4382 col_append_fstr (pinfo->cinfo, COL_INFO, " frag: %u",
4389 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
4393 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
4394 if (check_col (pinfo->cinfo, COL_INFO)) {
4395 if (hdr.flags1 & PFCL1_FRAG) {
4396 /* Fragmented - put the serial number into the Info column */
4397 col_append_fstr (pinfo->cinfo, COL_INFO, " serial: %u",
4398 (hdr.serial_hi << 8) | hdr.serial_lo);
4405 * XXX - for Kerberos, we get a protection level; if it's
4406 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
4409 dissect_dcerpc_dg_auth (tvb, offset, dcerpc_tree, &hdr,
4414 * keeping track of the conversation shouldn't really be necessary
4415 * for connectionless packets, because everything we need to know
4416 * to dissect is in the header for each packet. Unfortunately,
4417 * Microsoft's implementation is buggy and often puts the
4418 * completely wrong if_id in the header. go figure. So, keep
4419 * track of the seqnum and use that if possible. Note: that's not
4420 * completely correct. It should really be done based on both the
4421 * activity_id and seqnum. I haven't seen anywhere that it would
4422 * make a difference, but for future reference...
4424 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
4425 pinfo->srcport, pinfo->destport, 0);
4427 conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
4428 pinfo->srcport, pinfo->destport, 0);
4432 * Packet type specific stuff is next.
4435 switch (hdr.ptype) {
4437 case PDU_CANCEL_ACK:
4438 /* Body is optional */
4439 /* XXX - we assume "frag_len" is the length of the body */
4440 if (hdr.frag_len != 0)
4441 dissect_dcerpc_dg_cancel_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
4446 * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
4447 * but in at least one capture none of the Cl_cancel PDUs had a
4450 /* XXX - we assume "frag_len" is the length of the body */
4451 if (hdr.frag_len != 0)
4452 dissect_dcerpc_dg_cancel (tvb, offset, pinfo, dcerpc_tree, &hdr);
4456 /* Body is optional; if present, it's the same as PDU_FACK */
4457 /* XXX - we assume "frag_len" is the length of the body */
4458 if (hdr.frag_len != 0)
4459 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
4463 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
4468 dissect_dcerpc_dg_reject_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
4472 dissect_dcerpc_dg_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
4476 dissect_dcerpc_dg_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
4479 /* these requests have no body */
4491 dcerpc_init_protocol (void)
4493 /* structures and data for BIND */
4495 g_hash_table_destroy (dcerpc_binds);
4497 dcerpc_binds = g_hash_table_new (dcerpc_bind_hash, dcerpc_bind_equal);
4499 if (dcerpc_bind_key_chunk){
4500 g_mem_chunk_destroy (dcerpc_bind_key_chunk);
4502 dcerpc_bind_key_chunk = g_mem_chunk_new ("dcerpc_bind_key_chunk",
4503 sizeof (dcerpc_bind_key),
4504 200 * sizeof (dcerpc_bind_key),
4506 if (dcerpc_bind_value_chunk){
4507 g_mem_chunk_destroy (dcerpc_bind_value_chunk);
4509 dcerpc_bind_value_chunk = g_mem_chunk_new ("dcerpc_bind_value_chunk",
4510 sizeof (dcerpc_bind_value),
4511 200 * sizeof (dcerpc_bind_value),
4513 /* structures and data for CALL */
4514 if (dcerpc_cn_calls){
4515 g_hash_table_destroy (dcerpc_cn_calls);
4517 dcerpc_cn_calls = g_hash_table_new (dcerpc_cn_call_hash, dcerpc_cn_call_equal);
4518 if (dcerpc_dg_calls){
4519 g_hash_table_destroy (dcerpc_dg_calls);
4521 dcerpc_dg_calls = g_hash_table_new (dcerpc_dg_call_hash, dcerpc_dg_call_equal);
4522 if (dcerpc_cn_call_key_chunk){
4523 g_mem_chunk_destroy (dcerpc_cn_call_key_chunk);
4525 dcerpc_cn_call_key_chunk = g_mem_chunk_new ("dcerpc_cn_call_key_chunk",
4526 sizeof (dcerpc_cn_call_key),
4527 200 * sizeof (dcerpc_cn_call_key),
4529 if (dcerpc_dg_call_key_chunk){
4530 g_mem_chunk_destroy (dcerpc_dg_call_key_chunk);
4532 dcerpc_dg_call_key_chunk = g_mem_chunk_new ("dcerpc_dg_call_key_chunk",
4533 sizeof (dcerpc_dg_call_key),
4534 200 * sizeof (dcerpc_dg_call_key),
4537 if (dcerpc_call_value_chunk){
4538 g_mem_chunk_destroy (dcerpc_call_value_chunk);
4540 dcerpc_call_value_chunk = g_mem_chunk_new ("dcerpc_call_value_chunk",
4541 sizeof (dcerpc_call_value),
4542 200 * sizeof (dcerpc_call_value),
4545 /* structure and data for MATCHED */
4546 if (dcerpc_matched){
4547 g_hash_table_destroy (dcerpc_matched);
4549 dcerpc_matched = g_hash_table_new (dcerpc_matched_hash, dcerpc_matched_equal);
4550 if (dcerpc_matched_key_chunk){
4551 g_mem_chunk_destroy (dcerpc_matched_key_chunk);
4553 dcerpc_matched_key_chunk = g_mem_chunk_new ("dcerpc_matched_key_chunk",
4554 sizeof (dcerpc_matched_key),
4555 200 * sizeof (dcerpc_matched_key),
4558 /* call the registered hooks */
4559 g_hook_list_invoke(&dcerpc_hooks_init_protos, FALSE /* not may_recurse */);
4563 proto_register_dcerpc (void)
4565 static hf_register_info hf[] = {
4566 { &hf_dcerpc_request_in,
4567 { "Request in frame", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE,
4568 NULL, 0, "This packet is a response to the packet with this number", HFILL }},
4569 { &hf_dcerpc_response_in,
4570 { "Response in frame", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
4571 NULL, 0, "This packet will be responded in the packet with this number", HFILL }},
4572 { &hf_dcerpc_referent_id,
4573 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
4574 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
4576 { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4577 { &hf_dcerpc_ver_minor,
4578 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4579 { &hf_dcerpc_packet_type,
4580 { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS (pckt_vals), 0x0, "", HFILL }},
4581 { &hf_dcerpc_cn_flags,
4582 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4583 { &hf_dcerpc_cn_flags_first_frag,
4584 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_FIRST_FRAG, "", HFILL }},
4585 { &hf_dcerpc_cn_flags_last_frag,
4586 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_LAST_FRAG, "", HFILL }},
4587 { &hf_dcerpc_cn_flags_cancel_pending,
4588 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_PENDING_CANCEL, "", HFILL }},
4589 { &hf_dcerpc_cn_flags_reserved,
4590 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_RESERVED_1, "", HFILL }},
4591 { &hf_dcerpc_cn_flags_mpx,
4592 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_CONC_MPX, "", HFILL }},
4593 { &hf_dcerpc_cn_flags_dne,
4594 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_DID_NOT_EXECUTE, "", HFILL }},
4595 { &hf_dcerpc_cn_flags_maybe,
4596 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_MAYBE, "", HFILL }},
4597 { &hf_dcerpc_cn_flags_object,
4598 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_OBJECT_UUID, "", HFILL }},
4600 { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
4601 { &hf_dcerpc_drep_byteorder,
4602 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS (drep_byteorder_vals), 0x0, "", HFILL }},
4603 { &hf_dcerpc_drep_character,
4604 { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS (drep_character_vals), 0x0, "", HFILL }},
4605 { &hf_dcerpc_drep_fp,
4606 { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS (drep_fp_vals), 0x0, "", HFILL }},
4607 { &hf_dcerpc_cn_frag_len,
4608 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4609 { &hf_dcerpc_cn_auth_len,
4610 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4611 { &hf_dcerpc_cn_call_id,
4612 { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4613 { &hf_dcerpc_cn_max_xmit,
4614 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4615 { &hf_dcerpc_cn_max_recv,
4616 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4617 { &hf_dcerpc_cn_assoc_group,
4618 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
4619 { &hf_dcerpc_cn_num_ctx_items,
4620 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4621 { &hf_dcerpc_cn_ctx_id,
4622 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4623 { &hf_dcerpc_cn_num_trans_items,
4624 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4625 { &hf_dcerpc_cn_bind_if_id,
4626 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4627 { &hf_dcerpc_cn_bind_if_ver,
4628 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4629 { &hf_dcerpc_cn_bind_if_ver_minor,
4630 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4631 { &hf_dcerpc_cn_bind_trans_id,
4632 { "Transfer Syntax", "dcerpc.cn_bind_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4633 { &hf_dcerpc_cn_bind_trans_ver,
4634 { "Syntax ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4635 { &hf_dcerpc_cn_alloc_hint,
4636 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4637 { &hf_dcerpc_cn_sec_addr_len,
4638 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4639 { &hf_dcerpc_cn_sec_addr,
4640 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, "", HFILL }},
4641 { &hf_dcerpc_cn_num_results,
4642 { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4643 { &hf_dcerpc_cn_ack_result,
4644 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, "", HFILL }},
4645 { &hf_dcerpc_cn_ack_reason,
4646 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, "", HFILL }},
4647 { &hf_dcerpc_cn_ack_trans_id,
4648 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4649 { &hf_dcerpc_cn_ack_trans_ver,
4650 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4651 { &hf_dcerpc_cn_reject_reason,
4652 { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, "", HFILL }},
4653 { &hf_dcerpc_cn_num_protocols,
4654 { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4655 { &hf_dcerpc_cn_protocol_ver_major,
4656 { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4657 { &hf_dcerpc_cn_protocol_ver_minor,
4658 { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4659 { &hf_dcerpc_cn_cancel_count,
4660 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4661 { &hf_dcerpc_cn_status,
4662 { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
4663 { &hf_dcerpc_auth_type,
4664 { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
4665 { &hf_dcerpc_auth_level,
4666 { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS (authn_level_vals), 0x0, "", HFILL }},
4667 { &hf_dcerpc_auth_pad_len,
4668 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4669 { &hf_dcerpc_auth_rsrvd,
4670 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4671 { &hf_dcerpc_auth_ctx_id,
4672 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4673 { &hf_dcerpc_dg_flags1,
4674 { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4675 { &hf_dcerpc_dg_flags1_rsrvd_01,
4676 { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_01, "", HFILL }},
4677 { &hf_dcerpc_dg_flags1_last_frag,
4678 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_LASTFRAG, "", HFILL }},
4679 { &hf_dcerpc_dg_flags1_frag,
4680 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_FRAG, "", HFILL }},
4681 { &hf_dcerpc_dg_flags1_nofack,
4682 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_NOFACK, "", HFILL }},
4683 { &hf_dcerpc_dg_flags1_maybe,
4684 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_MAYBE, "", HFILL }},
4685 { &hf_dcerpc_dg_flags1_idempotent,
4686 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_IDEMPOTENT, "", HFILL }},
4687 { &hf_dcerpc_dg_flags1_broadcast,
4688 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_BROADCAST, "", HFILL }},
4689 { &hf_dcerpc_dg_flags1_rsrvd_80,
4690 { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_80, "", HFILL }},
4691 { &hf_dcerpc_dg_flags2,
4692 { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4693 { &hf_dcerpc_dg_flags2_rsrvd_01,
4694 { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_01, "", HFILL }},
4695 { &hf_dcerpc_dg_flags2_cancel_pending,
4696 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_CANCEL_PENDING, "", HFILL }},
4697 { &hf_dcerpc_dg_flags2_rsrvd_04,
4698 { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_04, "", HFILL }},
4699 { &hf_dcerpc_dg_flags2_rsrvd_08,
4700 { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_08, "", HFILL }},
4701 { &hf_dcerpc_dg_flags2_rsrvd_10,
4702 { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_10, "", HFILL }},
4703 { &hf_dcerpc_dg_flags2_rsrvd_20,
4704 { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_20, "", HFILL }},
4705 { &hf_dcerpc_dg_flags2_rsrvd_40,
4706 { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_40, "", HFILL }},
4707 { &hf_dcerpc_dg_flags2_rsrvd_80,
4708 { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_80, "", HFILL }},
4709 { &hf_dcerpc_dg_serial_lo,
4710 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4711 { &hf_dcerpc_dg_serial_hi,
4712 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4713 { &hf_dcerpc_dg_ahint,
4714 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
4715 { &hf_dcerpc_dg_ihint,
4716 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
4717 { &hf_dcerpc_dg_frag_len,
4718 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4719 { &hf_dcerpc_dg_frag_num,
4720 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4721 { &hf_dcerpc_dg_auth_proto,
4722 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
4723 { &hf_dcerpc_dg_seqnum,
4724 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4725 { &hf_dcerpc_dg_server_boot,
4726 { "Server boot time", "dcerpc.dg_server_boot", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0, "", HFILL }},
4727 { &hf_dcerpc_dg_if_ver,
4728 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4729 { &hf_dcerpc_krb5_av_prot_level,
4730 { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, "", HFILL }},
4731 { &hf_dcerpc_krb5_av_key_vers_num,
4732 { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4733 { &hf_dcerpc_krb5_av_key_auth_verifier,
4734 { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
4735 { &hf_dcerpc_obj_id,
4736 { "Object", "dcerpc.obj_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4737 { &hf_dcerpc_dg_if_id,
4738 { "Interface", "dcerpc.dg_if_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4739 { &hf_dcerpc_dg_act_id,
4740 { "Activity", "dcerpc.dg_act_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4742 { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4744 { &hf_dcerpc_dg_cancel_vers,
4745 { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4747 { &hf_dcerpc_dg_cancel_id,
4748 { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4750 { &hf_dcerpc_dg_server_accepting_cancels,
4751 { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
4753 { &hf_dcerpc_dg_fack_vers,
4754 { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4756 { &hf_dcerpc_dg_fack_window_size,
4757 { "Window Size", "dcerpc.fack_window_size", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4759 { &hf_dcerpc_dg_fack_max_tsdu,
4760 { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4762 { &hf_dcerpc_dg_fack_max_frag_size,
4763 { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4765 { &hf_dcerpc_dg_fack_serial_num,
4766 { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4768 { &hf_dcerpc_dg_fack_selack_len,
4769 { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4771 { &hf_dcerpc_dg_fack_selack,
4772 { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
4774 { &hf_dcerpc_dg_status,
4775 { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
4777 { &hf_dcerpc_array_max_count,
4778 { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
4780 { &hf_dcerpc_array_offset,
4781 { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
4783 { &hf_dcerpc_array_actual_count,
4784 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
4786 { &hf_dcerpc_array_buffer,
4787 { "Buffer", "dcerpc.array.buffer", FT_BYTES, BASE_NONE, NULL, 0x0, "Buffer: Buffer containing elements of the array", HFILL }},
4790 { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4792 { &hf_dcerpc_fragments,
4793 { "DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
4794 NULL, 0x0, "DCE/RPC Fragments", HFILL }},
4796 { &hf_dcerpc_fragment,
4797 { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM, BASE_NONE,
4798 NULL, 0x0, "DCE/RPC Fragment", HFILL }},
4800 { &hf_dcerpc_fragment_overlap,
4801 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE,
4802 NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
4804 { &hf_dcerpc_fragment_overlap_conflict,
4805 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE,
4806 NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
4808 { &hf_dcerpc_fragment_multiple_tails,
4809 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE,
4810 NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
4812 { &hf_dcerpc_fragment_too_long_fragment,
4813 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE,
4814 NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
4816 { &hf_dcerpc_fragment_error,
4817 { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE,
4818 NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
4821 { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE,
4822 NULL, 0, "Time between Request and Response for DCE-RPC calls", HFILL }},
4824 { &hf_dcerpc_reassembled_in,
4825 { "Reassembled PDU in frame", "dcerpc.reassembled_in", FT_FRAMENUM, BASE_NONE,
4826 NULL, 0x0, "The DCE/RPC PDU is completely reassembled in the packet with this number", HFILL }},
4828 { &hf_dcerpc_unknown_if_id,
4829 { "Unknown DCERPC interface id", "dcerpc.unknown_if_id", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
4831 static gint *ett[] = {
4833 &ett_dcerpc_cn_flags,
4835 &ett_dcerpc_cn_iface,
4837 &ett_dcerpc_dg_flags1,
4838 &ett_dcerpc_dg_flags2,
4839 &ett_dcerpc_pointer_data,
4841 &ett_dcerpc_fragments,
4842 &ett_dcerpc_fragment,
4843 &ett_dcerpc_krb5_auth_verf,
4845 module_t *dcerpc_module;
4847 proto_dcerpc = proto_register_protocol ("DCE RPC", "DCERPC", "dcerpc");
4848 proto_register_field_array (proto_dcerpc, hf, array_length (hf));
4849 proto_register_subtree_array (ett, array_length (ett));
4850 register_init_routine (dcerpc_init_protocol);
4851 dcerpc_module = prefs_register_protocol (proto_dcerpc, NULL);
4852 prefs_register_bool_preference (dcerpc_module,
4854 "Reassemble DCE/RPC messages spanning multiple TCP segments",
4855 "Whether the DCE/RPC dissector should reassemble messages spanning multiple TCP segments."
4856 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
4857 &dcerpc_cn_desegment);
4858 prefs_register_bool_preference (dcerpc_module,
4859 "reassemble_dcerpc",
4860 "Reassemble DCE/RPC fragments",
4861 "Whether the DCE/RPC dissector should reassemble fragmented DCE/RPC PDUs",
4862 &dcerpc_reassemble);
4863 register_init_routine(dcerpc_reassemble_init);
4864 dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
4865 dcerpc_tap=register_tap("dcerpc");
4867 g_hook_list_init(&dcerpc_hooks_init_protos, sizeof(GHook));
4871 proto_reg_handoff_dcerpc (void)
4873 heur_dissector_add ("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
4874 heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
4875 heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
4876 heur_dissector_add ("smb_transact", dissect_dcerpc_cn_smbpipe, proto_dcerpc);
4877 dcerpc_smb_init(proto_dcerpc);