2 * Routines for DCERPC packet disassembly
3 * Copyright 2001, Todd Sabin <tas@webspan.net>
4 * Copyright 2003, Tim Potter <tpot@samba.org>
8 * Ethereal - Network traffic analyzer
9 * By Gerald Combs <gerald@ethereal.com>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 /* The DCE RPC specification can be found at:
28 * http://www.opengroup.org/dce/
39 #include <epan/packet.h>
40 #include <epan/dissectors/packet-dcerpc.h>
41 #include <epan/conversation.h>
42 #include <epan/prefs.h>
43 #include <epan/reassemble.h>
45 #include <epan/dissectors/packet-frame.h>
46 #include <epan/dissectors/packet-dcerpc-nt.h>
48 static int dcerpc_tap = -1;
51 static const value_string pckt_vals[] = {
52 { PDU_REQ, "Request"},
54 { PDU_RESP, "Response"},
55 { PDU_FAULT, "Fault"},
56 { PDU_WORKING, "Working"},
57 { PDU_NOCALL, "Nocall"},
58 { PDU_REJECT, "Reject"},
60 { PDU_CL_CANCEL, "Cl_cancel"},
62 { PDU_CANCEL_ACK, "Cancel_ack"},
64 { PDU_BIND_ACK, "Bind_ack"},
65 { PDU_BIND_NAK, "Bind_nak"},
66 { PDU_ALTER, "Alter_context"},
67 { PDU_ALTER_ACK, "Alter_context_resp"},
68 { PDU_AUTH3, "AUTH3"},
69 { PDU_SHUTDOWN, "Shutdown"},
70 { PDU_CO_CANCEL, "Co_cancel"},
71 { PDU_ORPHANED, "Orphaned"},
75 static const value_string drep_byteorder_vals[] = {
77 { 1, "Little-endian" },
81 static const value_string drep_character_vals[] = {
87 #define DCE_RPC_DREP_FP_IEEE 0
88 #define DCE_RPC_DREP_FP_VAX 1
89 #define DCE_RPC_DREP_FP_CRAY 2
90 #define DCE_RPC_DREP_FP_IBM 3
92 static const value_string drep_fp_vals[] = {
93 { DCE_RPC_DREP_FP_IEEE, "IEEE" },
94 { DCE_RPC_DREP_FP_VAX, "VAX" },
95 { DCE_RPC_DREP_FP_CRAY, "Cray" },
96 { DCE_RPC_DREP_FP_IBM, "IBM" },
101 * Authentication services.
103 static const value_string authn_protocol_vals[] = {
104 { DCE_C_RPC_AUTHN_PROTOCOL_NONE, "None" },
105 { DCE_C_RPC_AUTHN_PROTOCOL_KRB5, "Kerberos 5" },
106 { DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO, "SPNEGO" },
107 { DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP, "NTLMSSP" },
108 { DCE_C_RPC_AUTHN_PROTOCOL_GSS_SCHANNEL, "SCHANNEL SSP" },
109 { DCE_C_RPC_AUTHN_PROTOCOL_GSS_KERBEROS, "Kerberos SSP" },
110 { DCE_C_RPC_AUTHN_PROTOCOL_DPA,
111 "Distributed Password Authentication SSP"},
112 { DCE_C_RPC_AUTHN_PROTOCOL_MSN, "MSN SSP"},
113 { DCE_C_RPC_AUTHN_PROTOCOL_DIGEST, "Digest SSP"},
114 { DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN,"NETLOGON Secure Channel" },
115 { DCE_C_RPC_AUTHN_PROTOCOL_MQ, "MSMQ SSP"},
122 static const value_string authn_level_vals[] = {
123 { DCE_C_AUTHN_LEVEL_NONE, "None" },
124 { DCE_C_AUTHN_LEVEL_CONNECT, "Connect" },
125 { DCE_C_AUTHN_LEVEL_CALL, "Call" },
126 { DCE_C_AUTHN_LEVEL_PKT, "Packet" },
127 { DCE_C_AUTHN_LEVEL_PKT_INTEGRITY, "Packet integrity" },
128 { DCE_C_AUTHN_LEVEL_PKT_PRIVACY, "Packet privacy" },
133 * Flag bits in first flag field in connectionless PDU header.
135 #define PFCL1_RESERVED_01 0x01 /* Reserved for use by implementations */
136 #define PFCL1_LASTFRAG 0x02 /* If set, the PDU is the last
137 * fragment of a multi-PDU
139 #define PFCL1_FRAG 0x04 /* If set, the PDU is a fragment of
140 a multi-PDU transmission */
141 #define PFCL1_NOFACK 0x08 /* If set, the receiver is not
142 * requested to send a `fack' PDU
143 * for the fragment */
144 #define PFCL1_MAYBE 0x10 /* If set, the PDU is for a `maybe'
146 #define PFCL1_IDEMPOTENT 0x20 /* If set, the PDU is for an idempotent
148 #define PFCL1_BROADCAST 0x40 /* If set, the PDU is for a broadcast
150 #define PFCL1_RESERVED_80 0x80 /* Reserved for use by implementations */
153 * Flag bits in second flag field in connectionless PDU header.
155 #define PFCL2_RESERVED_01 0x01 /* Reserved for use by implementations */
156 #define PFCL2_CANCEL_PENDING 0x02 /* Cancel pending at the call end */
157 #define PFCL2_RESERVED_04 0x04 /* Reserved for future use */
158 #define PFCL2_RESERVED_08 0x08 /* Reserved for future use */
159 #define PFCL2_RESERVED_10 0x10 /* Reserved for future use */
160 #define PFCL2_RESERVED_20 0x20 /* Reserved for future use */
161 #define PFCL2_RESERVED_40 0x40 /* Reserved for future use */
162 #define PFCL2_RESERVED_80 0x80 /* Reserved for future use */
165 * Flag bits in connection-oriented PDU header.
167 #define PFC_FIRST_FRAG 0x01 /* First fragment */
168 #define PFC_LAST_FRAG 0x02 /* Last fragment */
169 #define PFC_PENDING_CANCEL 0x04 /* Cancel was pending at sender */
170 #define PFC_RESERVED_1 0x08
171 #define PFC_CONC_MPX 0x10 /* suports concurrent multiplexing
172 * of a single connection. */
173 #define PFC_DID_NOT_EXECUTE 0x20 /* only meaningful on `fault' packet;
174 * if true, guaranteed call did not
176 #define PFC_MAYBE 0x40 /* `maybe' call semantics requested */
177 #define PFC_OBJECT_UUID 0x80 /* if true, a non-nil object UUID
178 * was specified in the handle, and
179 * is present in the optional object
180 * field. If false, the object field
184 * Tests whether a connection-oriented PDU is fragmented; returns TRUE if
185 * it's not fragmented (i.e., this is both the first *and* last fragment),
186 * and FALSE otherwise.
188 #define PFC_NOT_FRAGMENTED(hdr) \
189 ((hdr->flags&(PFC_FIRST_FRAG|PFC_LAST_FRAG))==(PFC_FIRST_FRAG|PFC_LAST_FRAG))
192 * Presentation context negotiation result.
194 static const value_string p_cont_result_vals[] = {
196 { 1, "User rejection" },
197 { 2, "Provider rejection" },
202 * Presentation context negotiation rejection reasons.
204 static const value_string p_provider_reason_vals[] = {
205 { 0, "Reason not specified" },
206 { 1, "Abstract syntax not supported" },
207 { 2, "Proposed transfer syntaxes not supported" },
208 { 3, "Local limit exceeded" },
215 #define REASON_NOT_SPECIFIED 0
216 #define TEMPORARY_CONGESTION 1
217 #define LOCAL_LIMIT_EXCEEDED 2
218 #define CALLED_PADDR_UNKNOWN 3 /* not used */
219 #define PROTOCOL_VERSION_NOT_SUPPORTED 4
220 #define DEFAULT_CONTEXT_NOT_SUPPORTED 5 /* not used */
221 #define USER_DATA_NOT_READABLE 6 /* not used */
222 #define NO_PSAP_AVAILABLE 7 /* not used */
224 static const value_string reject_reason_vals[] = {
225 { REASON_NOT_SPECIFIED, "Reason not specified" },
226 { TEMPORARY_CONGESTION, "Temporary congestion" },
227 { LOCAL_LIMIT_EXCEEDED, "Local limit exceeded" },
228 { CALLED_PADDR_UNKNOWN, "Called paddr unknown" },
229 { PROTOCOL_VERSION_NOT_SUPPORTED, "Protocol version not supported" },
230 { DEFAULT_CONTEXT_NOT_SUPPORTED, "Default context not supported" },
231 { USER_DATA_NOT_READABLE, "User data not readable" },
232 { NO_PSAP_AVAILABLE, "No PSAP available" },
237 * Reject status codes.
239 static const value_string reject_status_vals[] = {
240 { 0, "Stub-defined exception" },
241 { 0x00000001, "nca_s_fault_other" },
242 { 0x00000005, "nca_s_fault_access_denied" },
243 { 0x000006f7, "nca_s_fault_ndr" },
244 { 0x000006d8, "nca_s_fault_cant_perform" },
245 { 0x1c000001, "nca_s_fault_int_div_by_zero" },
246 { 0x1c000002, "nca_s_fault_addr_error" },
247 { 0x1c000003, "nca_s_fault_fp_div_zero" },
248 { 0x1c000004, "nca_s_fault_fp_underflow" },
249 { 0x1c000005, "nca_s_fault_fp_overflow" },
250 { 0x1c000006, "nca_s_fault_invalid_tag" },
251 { 0x1c000007, "nca_s_fault_invalid_bound" },
252 { 0x1c000008, "nca_rpc_version_mismatch" },
253 { 0x1c000009, "nca_unspec_reject" },
254 { 0x1c00000a, "nca_s_bad_actid" },
255 { 0x1c00000b, "nca_who_are_you_failed" },
256 { 0x1c00000c, "nca_manager_not_entered" },
257 { 0x1c00000d, "nca_s_fault_cancel" },
258 { 0x1c00000e, "nca_s_fault_ill_inst" },
259 { 0x1c00000f, "nca_s_fault_fp_error" },
260 { 0x1c000010, "nca_s_fault_int_overflow" },
261 { 0x1c000014, "nca_s_fault_pipe_empty" },
262 { 0x1c000015, "nca_s_fault_pipe_closed" },
263 { 0x1c000016, "nca_s_fault_pipe_order" },
264 { 0x1c000017, "nca_s_fault_pipe_discipline" },
265 { 0x1c000018, "nca_s_fault_pipe_comm_error" },
266 { 0x1c000019, "nca_s_fault_pipe_memory" },
267 { 0x1c00001a, "nca_s_fault_context_mismatch" },
268 { 0x1c00001b, "nca_s_fault_remote_no_memory" },
269 { 0x1c00001c, "nca_invalid_pres_context_id" },
270 { 0x1c00001d, "nca_unsupported_authn_level" },
271 { 0x1c00001f, "nca_invalid_checksum" },
272 { 0x1c000020, "nca_invalid_crc" },
273 { 0x1c000021, "ncs_s_fault_user_defined" },
274 { 0x1c000022, "nca_s_fault_tx_open_failed" },
275 { 0x1c000023, "nca_s_fault_codeset_conv_error" },
276 { 0x1c000024, "nca_s_fault_object_not_found" },
277 { 0x1c000025, "nca_s_fault_no_client_stub" },
278 { 0x1c010002, "nca_op_rng_error" },
279 { 0x1c010003, "nca_unk_if"},
280 { 0x1c010006, "nca_wrong_boot_time" },
281 { 0x1c010009, "nca_s_you_crashed" },
282 { 0x1c01000b, "nca_proto_error" },
283 { 0x1c010013, "nca_out_args_too_big" },
284 { 0x1c010014, "nca_server_too_busy" },
285 { 0x1c010017, "nca_unsupported_type" },
290 /* we need to keep track of what transport were used, ie what handle we came
291 * in through so we know what kind of pinfo->dce_smb_fid was passed to us.
293 /* Value of -1 is reserved for "not DCE packet" in packet_info.dcetransporttype. */
294 #define DCE_TRANSPORT_UNKNOWN 0
295 #define DCE_CN_TRANSPORT_SMBPIPE 1
298 static int proto_dcerpc = -1;
301 static int hf_dcerpc_request_in = -1;
302 static int hf_dcerpc_time = -1;
303 static int hf_dcerpc_response_in = -1;
304 static int hf_dcerpc_ver = -1;
305 static int hf_dcerpc_ver_minor = -1;
306 static int hf_dcerpc_packet_type = -1;
307 static int hf_dcerpc_cn_flags = -1;
308 static int hf_dcerpc_cn_flags_first_frag = -1;
309 static int hf_dcerpc_cn_flags_last_frag = -1;
310 static int hf_dcerpc_cn_flags_cancel_pending = -1;
311 static int hf_dcerpc_cn_flags_reserved = -1;
312 static int hf_dcerpc_cn_flags_mpx = -1;
313 static int hf_dcerpc_cn_flags_dne = -1;
314 static int hf_dcerpc_cn_flags_maybe = -1;
315 static int hf_dcerpc_cn_flags_object = -1;
316 static int hf_dcerpc_drep = -1;
317 static int hf_dcerpc_drep_byteorder = -1;
318 static int hf_dcerpc_drep_character = -1;
319 static int hf_dcerpc_drep_fp = -1;
320 static int hf_dcerpc_cn_frag_len = -1;
321 static int hf_dcerpc_cn_auth_len = -1;
322 static int hf_dcerpc_cn_call_id = -1;
323 static int hf_dcerpc_cn_max_xmit = -1;
324 static int hf_dcerpc_cn_max_recv = -1;
325 static int hf_dcerpc_cn_assoc_group = -1;
326 static int hf_dcerpc_cn_num_ctx_items = -1;
327 static int hf_dcerpc_cn_ctx_id = -1;
328 static int hf_dcerpc_cn_num_trans_items = -1;
329 static int hf_dcerpc_cn_bind_if_id = -1;
330 static int hf_dcerpc_cn_bind_if_ver = -1;
331 static int hf_dcerpc_cn_bind_if_ver_minor = -1;
332 static int hf_dcerpc_cn_bind_trans_id = -1;
333 static int hf_dcerpc_cn_bind_trans_ver = -1;
334 static int hf_dcerpc_cn_alloc_hint = -1;
335 static int hf_dcerpc_cn_sec_addr_len = -1;
336 static int hf_dcerpc_cn_sec_addr = -1;
337 static int hf_dcerpc_cn_num_results = -1;
338 static int hf_dcerpc_cn_ack_result = -1;
339 static int hf_dcerpc_cn_ack_reason = -1;
340 static int hf_dcerpc_cn_ack_trans_id = -1;
341 static int hf_dcerpc_cn_ack_trans_ver = -1;
342 static int hf_dcerpc_cn_reject_reason = -1;
343 static int hf_dcerpc_cn_num_protocols = -1;
344 static int hf_dcerpc_cn_protocol_ver_major = -1;
345 static int hf_dcerpc_cn_protocol_ver_minor = -1;
346 static int hf_dcerpc_cn_cancel_count = -1;
347 static int hf_dcerpc_cn_status = -1;
348 static int hf_dcerpc_auth_type = -1;
349 static int hf_dcerpc_auth_level = -1;
350 static int hf_dcerpc_auth_pad_len = -1;
351 static int hf_dcerpc_auth_rsrvd = -1;
352 static int hf_dcerpc_auth_ctx_id = -1;
353 static int hf_dcerpc_dg_flags1 = -1;
354 static int hf_dcerpc_dg_flags1_rsrvd_01 = -1;
355 static int hf_dcerpc_dg_flags1_last_frag = -1;
356 static int hf_dcerpc_dg_flags1_frag = -1;
357 static int hf_dcerpc_dg_flags1_nofack = -1;
358 static int hf_dcerpc_dg_flags1_maybe = -1;
359 static int hf_dcerpc_dg_flags1_idempotent = -1;
360 static int hf_dcerpc_dg_flags1_broadcast = -1;
361 static int hf_dcerpc_dg_flags1_rsrvd_80 = -1;
362 static int hf_dcerpc_dg_flags2 = -1;
363 static int hf_dcerpc_dg_flags2_rsrvd_01 = -1;
364 static int hf_dcerpc_dg_flags2_cancel_pending = -1;
365 static int hf_dcerpc_dg_flags2_rsrvd_04 = -1;
366 static int hf_dcerpc_dg_flags2_rsrvd_08 = -1;
367 static int hf_dcerpc_dg_flags2_rsrvd_10 = -1;
368 static int hf_dcerpc_dg_flags2_rsrvd_20 = -1;
369 static int hf_dcerpc_dg_flags2_rsrvd_40 = -1;
370 static int hf_dcerpc_dg_flags2_rsrvd_80 = -1;
371 static int hf_dcerpc_dg_serial_hi = -1;
372 static int hf_dcerpc_obj_id = -1;
373 static int hf_dcerpc_dg_if_id = -1;
374 static int hf_dcerpc_dg_act_id = -1;
375 static int hf_dcerpc_dg_serial_lo = -1;
376 static int hf_dcerpc_dg_ahint = -1;
377 static int hf_dcerpc_dg_ihint = -1;
378 static int hf_dcerpc_dg_frag_len = -1;
379 static int hf_dcerpc_dg_frag_num = -1;
380 static int hf_dcerpc_dg_auth_proto = -1;
381 static int hf_dcerpc_opnum = -1;
382 static int hf_dcerpc_dg_seqnum = -1;
383 static int hf_dcerpc_dg_server_boot = -1;
384 static int hf_dcerpc_dg_if_ver = -1;
385 static int hf_dcerpc_krb5_av_prot_level = -1;
386 static int hf_dcerpc_krb5_av_key_vers_num = -1;
387 static int hf_dcerpc_krb5_av_key_auth_verifier = -1;
388 static int hf_dcerpc_dg_cancel_vers = -1;
389 static int hf_dcerpc_dg_cancel_id = -1;
390 static int hf_dcerpc_dg_server_accepting_cancels = -1;
391 static int hf_dcerpc_dg_fack_vers = -1;
392 static int hf_dcerpc_dg_fack_window_size = -1;
393 static int hf_dcerpc_dg_fack_max_tsdu = -1;
394 static int hf_dcerpc_dg_fack_max_frag_size = -1;
395 static int hf_dcerpc_dg_fack_serial_num = -1;
396 static int hf_dcerpc_dg_fack_selack_len = -1;
397 static int hf_dcerpc_dg_fack_selack = -1;
398 static int hf_dcerpc_dg_status = -1;
399 static int hf_dcerpc_array_max_count = -1;
400 static int hf_dcerpc_array_offset = -1;
401 static int hf_dcerpc_array_actual_count = -1;
402 static int hf_dcerpc_array_buffer = -1;
403 static int hf_dcerpc_op = -1;
404 static int hf_dcerpc_referent_id = -1;
405 static int hf_dcerpc_fragments = -1;
406 static int hf_dcerpc_fragment = -1;
407 static int hf_dcerpc_fragment_overlap = -1;
408 static int hf_dcerpc_fragment_overlap_conflict = -1;
409 static int hf_dcerpc_fragment_multiple_tails = -1;
410 static int hf_dcerpc_fragment_too_long_fragment = -1;
411 static int hf_dcerpc_fragment_error = -1;
412 static int hf_dcerpc_reassembled_in = -1;
413 static int hf_dcerpc_unknown_if_id = -1;
415 static gint ett_dcerpc = -1;
416 static gint ett_dcerpc_cn_flags = -1;
417 static gint ett_dcerpc_cn_ctx = -1;
418 static gint ett_dcerpc_cn_iface = -1;
419 static gint ett_dcerpc_drep = -1;
420 static gint ett_dcerpc_dg_flags1 = -1;
421 static gint ett_dcerpc_dg_flags2 = -1;
422 static gint ett_dcerpc_pointer_data = -1;
423 static gint ett_dcerpc_string = -1;
424 static gint ett_dcerpc_fragments = -1;
425 static gint ett_dcerpc_fragment = -1;
426 static gint ett_dcerpc_krb5_auth_verf = -1;
428 static const fragment_items dcerpc_frag_items = {
429 &ett_dcerpc_fragments,
430 &ett_dcerpc_fragment,
432 &hf_dcerpc_fragments,
434 &hf_dcerpc_fragment_overlap,
435 &hf_dcerpc_fragment_overlap_conflict,
436 &hf_dcerpc_fragment_multiple_tails,
437 &hf_dcerpc_fragment_too_long_fragment,
438 &hf_dcerpc_fragment_error,
444 /* list of hooks to be called when init_protocols is done */
445 GHookList dcerpc_hooks_init_protos;
448 int ResolveWin32UUID(e_uuid_t if_id, char *UUID_NAME, int UUID_NAME_MAX_LEN)
450 char REG_UUID_NAME[MAX_PATH];
452 DWORD UUID_MAX_SIZE = MAX_PATH;
453 char REG_UUID_STR[MAX_PATH];
455 if(UUID_NAME_MAX_LEN < 2)
457 REG_UUID_NAME[0] = '\0';
458 snprintf(REG_UUID_STR, MAX_PATH, "SOFTWARE\\Classes\\Interface\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
459 if_id.Data1, if_id.Data2, if_id.Data3,
460 if_id.Data4[0], if_id.Data4[1],
461 if_id.Data4[2], if_id.Data4[3],
462 if_id.Data4[4], if_id.Data4[5],
463 if_id.Data4[6], if_id.Data4[7]);
464 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCSTR)REG_UUID_STR, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
466 if (RegQueryValueEx(hKey, NULL, NULL, NULL, (LPBYTE)REG_UUID_NAME, &UUID_MAX_SIZE) == ERROR_SUCCESS && UUID_MAX_SIZE <= MAX_PATH)
468 snprintf(UUID_NAME, UUID_NAME_MAX_LEN, "%s", REG_UUID_NAME);
470 return strlen(REG_UUID_NAME);
474 return 0; /* we didn't find anything anyhow. Please don't use the string! */
482 static dcerpc_info di[20];
483 static int di_counter=0;
489 return &di[di_counter];
492 /* try to desegment big DCE/RPC packets over TCP? */
493 static gboolean dcerpc_cn_desegment = TRUE;
495 /* reassemble DCE/RPC fragments */
496 /* reassembly of dcerpc fragments will not work for the case where ONE frame
497 might contain multiple dcerpc fragments for different PDUs.
498 this case would be so unusual/weird so if you got captures like that:
501 static gboolean dcerpc_reassemble = FALSE;
502 static GHashTable *dcerpc_co_reassemble_table = NULL;
503 static GHashTable *dcerpc_cl_reassemble_table = NULL;
506 dcerpc_reassemble_init(void)
508 fragment_table_init(&dcerpc_co_reassemble_table);
509 dcerpc_fragment_table_init(&dcerpc_cl_reassemble_table);
513 * Authentication subdissectors. Used to dissect authentication blobs in
514 * DCERPC binds, requests and responses.
517 typedef struct _dcerpc_auth_subdissector {
520 dcerpc_auth_subdissector_fns auth_fns;
521 } dcerpc_auth_subdissector;
523 static GSList *dcerpc_auth_subdissector_list;
525 static dcerpc_auth_subdissector_fns *get_auth_subdissector_fns(
526 guint8 auth_level, guint8 auth_type)
531 for (i = 0; (data = g_slist_nth_data(dcerpc_auth_subdissector_list, i)); i++) {
532 dcerpc_auth_subdissector *asd = (dcerpc_auth_subdissector *)data;
534 if (asd->auth_level == auth_level &&
535 asd->auth_type == auth_type)
536 return &asd->auth_fns;
542 void register_dcerpc_auth_subdissector(guint8 auth_level, guint8 auth_type,
543 dcerpc_auth_subdissector_fns *fns)
545 dcerpc_auth_subdissector *d;
547 if (get_auth_subdissector_fns(auth_level, auth_type))
550 d = (dcerpc_auth_subdissector *)g_malloc(sizeof(dcerpc_auth_subdissector));
552 d->auth_level = auth_level;
553 d->auth_type = auth_type;
554 memcpy(&d->auth_fns, fns, sizeof(dcerpc_auth_subdissector_fns));
556 dcerpc_auth_subdissector_list = g_slist_append(dcerpc_auth_subdissector_list, d);
559 /* Hand off verifier data to a registered dissector */
561 static void dissect_auth_verf(tvbuff_t *auth_tvb, packet_info *pinfo,
563 dcerpc_auth_subdissector_fns *auth_fns,
564 e_dce_cn_common_hdr_t *hdr,
565 dcerpc_auth_info *auth_info)
567 dcerpc_dissect_fnct_t *volatile fn = NULL;
569 switch (hdr->ptype) {
572 fn = auth_fns->bind_fn;
576 fn = auth_fns->bind_ack_fn;
579 fn = auth_fns->auth3_fn;
582 fn = auth_fns->req_verf_fn;
585 fn = auth_fns->resp_verf_fn;
588 /* Don't know how to handle authentication data in this
592 g_warning("attempt to dissect %s pdu authentication data",
593 val_to_str(hdr->ptype, pckt_vals, "Unknown (%u)"));
598 fn(auth_tvb, 0, pinfo, tree, hdr->drep);
600 proto_tree_add_text(tree, auth_tvb, 0, hdr->auth_len,
602 val_to_str(auth_info->auth_type,
607 /* Hand off payload data to a registered dissector */
609 static tvbuff_t *decode_encrypted_data(tvbuff_t *data_tvb,
612 dcerpc_auth_subdissector_fns *auth_fns,
614 dcerpc_auth_info *auth_info)
616 dcerpc_decode_data_fnct_t *fn;
619 fn = auth_fns->req_data_fn;
621 fn = auth_fns->resp_data_fn;
624 return fn(data_tvb, auth_tvb, 0, pinfo, auth_info);
633 /* the registered subdissectors */
634 GHashTable *dcerpc_uuids=NULL;
637 dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2)
639 const dcerpc_uuid_key *key1 = (const dcerpc_uuid_key *)k1;
640 const dcerpc_uuid_key *key2 = (const dcerpc_uuid_key *)k2;
641 return ((memcmp (&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
642 && (key1->ver == key2->ver));
646 dcerpc_uuid_hash (gconstpointer k)
648 const dcerpc_uuid_key *key = (const dcerpc_uuid_key *)k;
649 /* This isn't perfect, but the Data1 part of these is almost always
651 return key->uuid.Data1;
655 dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver,
656 dcerpc_sub_dissector *procs, int opnum_hf)
658 dcerpc_uuid_key *key = g_malloc (sizeof (*key));
659 dcerpc_uuid_value *value = g_malloc (sizeof (*value));
660 header_field_info *hf_info;
665 value->proto = find_protocol_by_id(proto);
666 value->proto_id = proto;
668 value->name = proto_get_protocol_short_name (value->proto);
669 value->procs = procs;
670 value->opnum_hf = opnum_hf;
672 g_hash_table_insert (dcerpc_uuids, key, value);
674 hf_info = proto_registrar_get_nth(opnum_hf);
675 hf_info->strings = value_string_from_subdissectors(procs);
679 /* try to get registered name for this uuid */
680 gchar *dcerpc_get_uuid_name(e_uuid_t *uuid, guint16 ver)
683 dcerpc_uuid_value *sub_proto;
686 /* try to get registered uuid "name" of if_id */
690 if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) != NULL
691 && proto_is_protocol_enabled(sub_proto->proto)) {
693 return sub_proto->name;
700 /* Function to find the name of a registered protocol
701 * or NULL if the protocol/version is not known to ethereal.
704 dcerpc_get_proto_name(e_uuid_t *uuid, guint16 ver)
707 dcerpc_uuid_value *sub_proto;
711 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
714 return sub_proto->name;
717 /* Function to find the opnum hf-field of a registered protocol
718 * or -1 if the protocol/version is not known to ethereal.
721 dcerpc_get_proto_hf_opnum(e_uuid_t *uuid, guint16 ver)
724 dcerpc_uuid_value *sub_proto;
728 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
731 return sub_proto->opnum_hf;
734 /* Create a value_string consisting of DCERPC opnum and name from a
735 subdissector array. */
737 value_string *value_string_from_subdissectors(dcerpc_sub_dissector *sd)
739 value_string *vs = NULL;
743 for (i = 0; sd[i].name; i++) {
745 vs[i].value = sd[i].num;
746 vs[i].strptr = sd[i].name;
752 vs = g_malloc((num_sd + 1) * sizeof(value_string));
756 vs[num_sd].value = 0;
757 vs[num_sd].strptr = NULL;
762 /* Function to find the subdissector table of a registered protocol
763 * or NULL if the protocol/version is not known to ethereal.
765 dcerpc_sub_dissector *
766 dcerpc_get_proto_sub_dissector(e_uuid_t *uuid, guint16 ver)
769 dcerpc_uuid_value *sub_proto;
773 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
776 return sub_proto->procs;
781 * To keep track of ctx_id mappings.
783 * Everytime we see a bind call we update this table.
784 * Note that we always specify a SMB FID. For non-SMB transports this
787 static GHashTable *dcerpc_binds=NULL;
789 typedef struct _dcerpc_bind_key {
790 conversation_t *conv;
795 typedef struct _dcerpc_bind_value {
800 static GMemChunk *dcerpc_bind_key_chunk=NULL;
801 static GMemChunk *dcerpc_bind_value_chunk=NULL;
804 dcerpc_bind_equal (gconstpointer k1, gconstpointer k2)
806 const dcerpc_bind_key *key1 = (const dcerpc_bind_key *)k1;
807 const dcerpc_bind_key *key2 = (const dcerpc_bind_key *)k2;
808 return (key1->conv == key2->conv
809 && key1->ctx_id == key2->ctx_id
810 && key1->smb_fid == key2->smb_fid);
814 dcerpc_bind_hash (gconstpointer k)
816 const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
819 hash=GPOINTER_TO_UINT(key->conv) + key->ctx_id + key->smb_fid;
825 * To keep track of callid mappings. Should really use some generic
826 * conversation support instead.
828 static GHashTable *dcerpc_cn_calls=NULL;
829 static GHashTable *dcerpc_dg_calls=NULL;
831 typedef struct _dcerpc_cn_call_key {
832 conversation_t *conv;
835 } dcerpc_cn_call_key;
837 typedef struct _dcerpc_dg_call_key {
838 conversation_t *conv;
841 } dcerpc_dg_call_key;
843 static GMemChunk *dcerpc_cn_call_key_chunk=NULL;
845 static GMemChunk *dcerpc_dg_call_key_chunk=NULL;
847 static GMemChunk *dcerpc_call_value_chunk=NULL;
851 dcerpc_cn_call_equal (gconstpointer k1, gconstpointer k2)
853 const dcerpc_cn_call_key *key1 = (const dcerpc_cn_call_key *)k1;
854 const dcerpc_cn_call_key *key2 = (const dcerpc_cn_call_key *)k2;
855 return (key1->conv == key2->conv
856 && key1->call_id == key2->call_id
857 && key1->smb_fid == key2->smb_fid);
861 dcerpc_dg_call_equal (gconstpointer k1, gconstpointer k2)
863 const dcerpc_dg_call_key *key1 = (const dcerpc_dg_call_key *)k1;
864 const dcerpc_dg_call_key *key2 = (const dcerpc_dg_call_key *)k2;
865 return (key1->conv == key2->conv
866 && key1->seqnum == key2->seqnum
867 && (memcmp (&key1->act_id, &key2->act_id, sizeof (e_uuid_t)) == 0));
871 dcerpc_cn_call_hash (gconstpointer k)
873 const dcerpc_cn_call_key *key = (const dcerpc_cn_call_key *)k;
874 return GPOINTER_TO_UINT(key->conv) + key->call_id + key->smb_fid;
878 dcerpc_dg_call_hash (gconstpointer k)
880 const dcerpc_dg_call_key *key = (const dcerpc_dg_call_key *)k;
881 return (GPOINTER_TO_UINT(key->conv) + key->seqnum + key->act_id.Data1
882 + (key->act_id.Data2 << 16) + key->act_id.Data3
883 + (key->act_id.Data4[0] << 24) + (key->act_id.Data4[1] << 16)
884 + (key->act_id.Data4[2] << 8) + (key->act_id.Data4[3] << 0)
885 + (key->act_id.Data4[4] << 24) + (key->act_id.Data4[5] << 16)
886 + (key->act_id.Data4[6] << 8) + (key->act_id.Data4[7] << 0));
889 /* to keep track of matched calls/responses
890 this one uses the same value struct as calls, but the key is the frame id
891 and call id; there can be more than one call in a frame.
893 XXX - why not just use the same keys as are used for calls?
896 static GHashTable *dcerpc_matched=NULL;
898 typedef struct _dcerpc_matched_key {
901 } dcerpc_matched_key;
903 static GMemChunk *dcerpc_matched_key_chunk=NULL;
906 dcerpc_matched_equal (gconstpointer k1, gconstpointer k2)
908 const dcerpc_matched_key *key1 = (const dcerpc_matched_key *)k1;
909 const dcerpc_matched_key *key2 = (const dcerpc_matched_key *)k2;
910 return (key1->frame == key2->frame
911 && key1->call_id == key2->call_id);
915 dcerpc_matched_hash (gconstpointer k)
917 const dcerpc_matched_key *key = (const dcerpc_matched_key *)k;
924 * Utility functions. Modeled after packet-rpc.c
928 dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
929 proto_tree *tree, guint8 *drep,
930 int hfindex, guint8 *pdata)
934 data = tvb_get_guint8 (tvb, offset);
936 proto_tree_add_item (tree, hfindex, tvb, offset, 1, (drep[0] & 0x10));
944 dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
945 proto_tree *tree, guint8 *drep,
946 int hfindex, guint16 *pdata)
950 data = ((drep[0] & 0x10)
951 ? tvb_get_letohs (tvb, offset)
952 : tvb_get_ntohs (tvb, offset));
955 proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10));
963 dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
964 proto_tree *tree, guint8 *drep,
965 int hfindex, guint32 *pdata)
969 data = ((drep[0] & 0x10)
970 ? tvb_get_letohl (tvb, offset)
971 : tvb_get_ntohl (tvb, offset));
974 proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10));
981 /* handles 32 bit unix time_t */
983 dissect_dcerpc_time_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
984 proto_tree *tree, guint8 *drep,
985 int hfindex, guint32 *pdata)
990 data = ((drep[0] & 0x10)
991 ? tvb_get_letohl (tvb, offset)
992 : tvb_get_ntohl (tvb, offset));
997 if(data==0xffffffff){
998 /* special case, no time specified */
999 proto_tree_add_time_format(tree, hfindex, tvb, offset, 4, &tv, "%s: No time specified", proto_registrar_get_nth(hfindex)->name);
1001 proto_tree_add_time (tree, hfindex, tvb, offset, 4, &tv);
1011 dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1012 proto_tree *tree, guint8 *drep,
1013 int hfindex, guint64 *pdata)
1017 data = ((drep[0] & 0x10)
1018 ? tvb_get_letoh64 (tvb, offset)
1019 : tvb_get_ntoh64 (tvb, offset));
1022 proto_tree_add_item(tree, hfindex, tvb, offset, 8, (drep[0] & 0x10));
1031 dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1032 proto_tree *tree, guint8 *drep,
1033 int hfindex, gfloat *pdata)
1039 case(DCE_RPC_DREP_FP_IEEE):
1040 data = ((drep[0] & 0x10)
1041 ? tvb_get_letohieee_float(tvb, offset)
1042 : tvb_get_ntohieee_float(tvb, offset));
1044 proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
1047 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
1048 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1049 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
1051 /* ToBeDone: non IEEE floating formats */
1052 /* Set data to a negative infinity value */
1055 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep[1]);
1065 dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1066 proto_tree *tree, guint8 *drep,
1067 int hfindex, gdouble *pdata)
1073 case(DCE_RPC_DREP_FP_IEEE):
1074 data = ((drep[0] & 0x10)
1075 ? tvb_get_letohieee_double(tvb, offset)
1076 : tvb_get_ntohieee_double(tvb, offset));
1078 proto_tree_add_double(tree, hfindex, tvb, offset, 8, data);
1081 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
1082 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1083 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
1085 /* ToBeDone: non IEEE double formats */
1086 /* Set data to a negative infinity value */
1087 data = -G_MAXDOUBLE;
1089 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep[1]);
1099 dissect_dcerpc_uuid_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1100 proto_tree *tree, char *drep,
1101 int hfindex, e_uuid_t *pdata)
1104 header_field_info* hfi;
1110 dcerpc_tvb_get_uuid (tvb, offset, drep, &uuid);
1112 /* get name of protocol field to prepend it later */
1113 hfi = proto_registrar_get_nth(hfindex);
1116 /* XXX - get the name won't work correct, as we don't know the version of this uuid (if it has one) */
1117 /* look for a registered uuid name */
1118 uuid_name = dcerpc_get_uuid_name(&uuid, 0);
1121 /* we know the name of this uuid */
1122 proto_tree_add_string_format (tree, hfindex, tvb, offset, 16, "",
1123 "%s: %s (%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x)",
1124 hfi->name, uuid_name,
1125 uuid.Data1, uuid.Data2, uuid.Data3,
1126 uuid.Data4[0], uuid.Data4[1],
1127 uuid.Data4[2], uuid.Data4[3],
1128 uuid.Data4[4], uuid.Data4[5],
1129 uuid.Data4[6], uuid.Data4[7]);
1132 /* we don't know the name of this uuid */
1133 proto_tree_add_string_format (tree, hfindex, tvb, offset, 16, "",
1134 "%s: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1136 uuid.Data1, uuid.Data2, uuid.Data3,
1137 uuid.Data4[0], uuid.Data4[1],
1138 uuid.Data4[2], uuid.Data4[3],
1139 uuid.Data4[4], uuid.Data4[5],
1140 uuid.Data4[6], uuid.Data4[7]);
1153 * a couple simpler things
1156 dcerpc_tvb_get_ntohs (tvbuff_t *tvb, gint offset, guint8 *drep)
1158 if (drep[0] & 0x10) {
1159 return tvb_get_letohs (tvb, offset);
1161 return tvb_get_ntohs (tvb, offset);
1166 dcerpc_tvb_get_ntohl (tvbuff_t *tvb, gint offset, guint8 *drep)
1168 if (drep[0] & 0x10) {
1169 return tvb_get_letohl (tvb, offset);
1171 return tvb_get_ntohl (tvb, offset);
1176 dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, guint8 *drep, e_uuid_t *uuid)
1179 uuid->Data1 = dcerpc_tvb_get_ntohl (tvb, offset, drep);
1180 uuid->Data2 = dcerpc_tvb_get_ntohs (tvb, offset+4, drep);
1181 uuid->Data3 = dcerpc_tvb_get_ntohs (tvb, offset+6, drep);
1183 for (i=0; i<sizeof (uuid->Data4); i++) {
1184 uuid->Data4[i] = tvb_get_guint8 (tvb, offset+8+i);
1191 /* function to dissect a unidimensional conformant array */
1193 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1194 proto_tree *tree, guint8 *drep,
1195 dcerpc_dissect_fnct_t *fnct)
1201 di=pinfo->private_data;
1202 if(di->conformant_run){
1203 /* conformant run, just dissect the max_count header */
1205 di->conformant_run=0;
1206 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1207 hf_dcerpc_array_max_count, &di->array_max_count);
1208 di->array_max_count_offset=offset-4;
1209 di->conformant_run=1;
1210 di->conformant_eaten=offset-old_offset;
1212 /* we don't remember where in the bytestream this field was */
1213 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1215 /* real run, dissect the elements */
1216 for(i=0;i<di->array_max_count;i++){
1217 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1223 /* function to dissect a unidimensional conformant and varying array */
1225 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1226 proto_tree *tree, guint8 *drep,
1227 dcerpc_dissect_fnct_t *fnct)
1233 di=pinfo->private_data;
1234 if(di->conformant_run){
1235 /* conformant run, just dissect the max_count header */
1237 di->conformant_run=0;
1238 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1239 hf_dcerpc_array_max_count, &di->array_max_count);
1240 di->array_max_count_offset=offset-4;
1241 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1242 hf_dcerpc_array_offset, &di->array_offset);
1243 di->array_offset_offset=offset-4;
1244 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1245 hf_dcerpc_array_actual_count, &di->array_actual_count);
1246 di->array_actual_count_offset=offset-4;
1247 di->conformant_run=1;
1248 di->conformant_eaten=offset-old_offset;
1250 /* we dont dont remember where in the bytestream these fields were */
1251 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1252 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
1253 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
1255 /* real run, dissect the elements */
1256 for(i=0;i<di->array_actual_count;i++){
1257 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1263 /* function to dissect a unidimensional varying array */
1265 dissect_ndr_uvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1266 proto_tree *tree, guint8 *drep,
1267 dcerpc_dissect_fnct_t *fnct)
1273 di=pinfo->private_data;
1274 if(di->conformant_run){
1275 /* conformant run, just dissect the max_count header */
1277 di->conformant_run=0;
1278 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1279 hf_dcerpc_array_offset, &di->array_offset);
1280 di->array_offset_offset=offset-4;
1281 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1282 hf_dcerpc_array_actual_count, &di->array_actual_count);
1283 di->array_actual_count_offset=offset-4;
1284 di->conformant_run=1;
1285 di->conformant_eaten=offset-old_offset;
1287 /* we dont dont remember where in the bytestream these fields were */
1288 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
1289 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
1291 /* real run, dissect the elements */
1292 for(i=0;i<di->array_actual_count;i++){
1293 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1300 /* Dissect an string of bytes. This corresponds to
1301 IDL of the form '[string] byte *foo'.
1303 It can also be used for a conformant varying array of bytes if
1304 the contents of the array should be shown as a big blob, rather
1305 than showing each byte as an individual element.
1307 XXX - which of those is really the IDL type for, for example,
1308 the encrypted data in some MAPI packets? (Microsoft haven't
1311 XXX - does this need to do all the conformant array stuff that
1312 "dissect_ndr_ucvarray()" does? These are presumably for strings
1313 that are conformant and varying - they're stored like conformant
1314 varying arrays of bytes. */
1316 dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo,
1317 proto_tree *tree, guint8 *drep)
1322 di=pinfo->private_data;
1323 if(di->conformant_run){
1324 /* just a run to handle conformant arrays, no scalars to dissect */
1328 /* NDR array header */
1330 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1331 hf_dcerpc_array_max_count, NULL);
1333 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1334 hf_dcerpc_array_offset, NULL);
1336 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1337 hf_dcerpc_array_actual_count, &len);
1340 proto_tree_add_item(tree, hf_dcerpc_array_buffer,
1341 tvb, offset, len, drep[0] & 0x10);
1348 /* For dissecting arrays that are to be interpreted as strings. */
1350 /* Dissect an NDR conformant varying string of elements.
1351 The length of each element is given by the 'size_is' parameter;
1352 the elements are assumed to be characters or wide characters.
1354 XXX - does this need to do all the conformant array stuff that
1355 "dissect_ndr_ucvarray()" does? */
1357 dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1358 proto_tree *tree, guint8 *drep, int size_is,
1359 int hfindex, gboolean add_subtree, char **data)
1362 proto_item *string_item;
1363 proto_tree *string_tree;
1364 guint32 len, buffer_len;
1366 header_field_info *hfinfo;
1368 di=pinfo->private_data;
1369 if(di->conformant_run){
1370 /* just a run to handle conformant arrays, no scalars to dissect */
1375 string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1376 proto_registrar_get_name(hfindex));
1377 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1383 /* NDR array header */
1385 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1386 hf_dcerpc_array_max_count, NULL);
1388 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1389 hf_dcerpc_array_offset, NULL);
1391 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1392 hf_dcerpc_array_actual_count, &len);
1394 buffer_len = size_is * len;
1397 if (offset % size_is)
1398 offset += size_is - (offset % size_is);
1400 if (size_is == sizeof(guint16)) {
1401 /* XXX - use drep to determine the byte order? */
1402 s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
1404 * XXX - we don't support a string type with Unicode
1405 * characters, so if this is a string item, we make
1406 * its value be the "fake Unicode" string.
1408 if (tree && buffer_len) {
1409 hfinfo = proto_registrar_get_nth(hfindex);
1410 if (hfinfo->type == FT_STRING) {
1411 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1414 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1415 buffer_len, drep[0] & 0x10);
1420 * "tvb_get_string()" throws an exception if the entire string
1421 * isn't in the tvbuff. If the length is bogus, this should
1422 * keep us from trying to allocate an immensely large buffer.
1423 * (It won't help if the length is *valid* but immensely large,
1424 * but that's another matter; in any case, that would happen only
1425 * if we had an immensely large tvbuff....)
1427 s = tvb_get_string(tvb, offset, buffer_len);
1428 if (tree && buffer_len)
1429 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1430 buffer_len, drep[0] & 0x10);
1433 if (string_item != NULL)
1434 proto_item_append_text(string_item, ": %s", s);
1441 offset += buffer_len;
1443 proto_item_set_end(string_item, tvb, offset);
1448 /* Dissect an conformant varying string of chars.
1449 This corresponds to IDL of the form '[string] char *foo'.
1451 XXX - at least according to the DCE RPC 1.1 spec, a string has
1452 a null terminator, which isn't necessary as a terminator for
1453 the transfer language (as there's a length), but is presumably
1454 there for the benefit of null-terminated-string languages
1455 such as C. Is this ever used for purely counted strings?
1456 (Not that it matters if it is.) */
1458 dissect_ndr_char_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1459 proto_tree *tree, guint8 *drep)
1462 di=pinfo->private_data;
1464 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1465 sizeof(guint8), di->hf_index,
1469 /* Dissect a conformant varying string of wchars (wide characters).
1470 This corresponds to IDL of the form '[string] wchar *foo'
1472 XXX - at least according to the DCE RPC 1.1 spec, a string has
1473 a null terminator, which isn't necessary as a terminator for
1474 the transfer language (as there's a length), but is presumably
1475 there for the benefit of null-terminated-string languages
1476 such as C. Is this ever used for purely counted strings?
1477 (Not that it matters if it is.) */
1479 dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1480 proto_tree *tree, guint8 *drep)
1483 di=pinfo->private_data;
1485 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1486 sizeof(guint16), di->hf_index,
1490 /* Dissect an NDR varying string of elements.
1491 The length of each element is given by the 'size_is' parameter;
1492 the elements are assumed to be characters or wide characters.
1495 dissect_ndr_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1496 proto_tree *tree, guint8 *drep, int size_is,
1497 int hfindex, gboolean add_subtree, char **data)
1500 proto_item *string_item;
1501 proto_tree *string_tree;
1502 guint32 len, buffer_len;
1504 header_field_info *hfinfo;
1506 di=pinfo->private_data;
1507 if(di->conformant_run){
1508 /* just a run to handle conformant arrays, no scalars to dissect */
1513 string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1514 proto_registrar_get_name(hfindex));
1515 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1521 /* NDR array header */
1522 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1523 hf_dcerpc_array_offset, NULL);
1525 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1526 hf_dcerpc_array_actual_count, &len);
1528 buffer_len = size_is * len;
1531 if (offset % size_is)
1532 offset += size_is - (offset % size_is);
1534 if (size_is == sizeof(guint16)) {
1535 /* XXX - use drep to determine the byte order? */
1536 s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
1538 * XXX - we don't support a string type with Unicode
1539 * characters, so if this is a string item, we make
1540 * its value be the "fake Unicode" string.
1542 if (tree && buffer_len) {
1543 hfinfo = proto_registrar_get_nth(hfindex);
1544 if (hfinfo->type == FT_STRING) {
1545 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1548 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1549 buffer_len, drep[0] & 0x10);
1554 * "tvb_get_string()" throws an exception if the entire string
1555 * isn't in the tvbuff. If the length is bogus, this should
1556 * keep us from trying to allocate an immensely large buffer.
1557 * (It won't help if the length is *valid* but immensely large,
1558 * but that's another matter; in any case, that would happen only
1559 * if we had an immensely large tvbuff....)
1561 s = tvb_get_string(tvb, offset, buffer_len);
1562 if (tree && buffer_len)
1563 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1564 buffer_len, drep[0] & 0x10);
1567 if (string_item != NULL)
1568 proto_item_append_text(string_item, ": %s", s);
1575 offset += buffer_len;
1577 proto_item_set_end(string_item, tvb, offset);
1581 /* Dissect an varying string of chars.
1582 This corresponds to IDL of the form '[string] char *foo'.
1584 XXX - at least according to the DCE RPC 1.1 spec, a string has
1585 a null terminator, which isn't necessary as a terminator for
1586 the transfer language (as there's a length), but is presumably
1587 there for the benefit of null-terminated-string languages
1588 such as C. Is this ever used for purely counted strings?
1589 (Not that it matters if it is.) */
1591 dissect_ndr_char_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1592 proto_tree *tree, guint8 *drep)
1595 di=pinfo->private_data;
1597 return dissect_ndr_vstring(tvb, offset, pinfo, tree, drep,
1598 sizeof(guint8), di->hf_index,
1602 /* Dissect a varying string of wchars (wide characters).
1603 This corresponds to IDL of the form '[string] wchar *foo'
1605 XXX - at least according to the DCE RPC 1.1 spec, a string has
1606 a null terminator, which isn't necessary as a terminator for
1607 the transfer language (as there's a length), but is presumably
1608 there for the benefit of null-terminated-string languages
1609 such as C. Is this ever used for purely counted strings?
1610 (Not that it matters if it is.) */
1612 dissect_ndr_wchar_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1613 proto_tree *tree, guint8 *drep)
1616 di=pinfo->private_data;
1618 return dissect_ndr_vstring(tvb, offset, pinfo, tree, drep,
1619 sizeof(guint16), di->hf_index,
1624 /* ndr pointer handling */
1625 /* list of pointers encountered so far */
1626 static GSList *ndr_pointer_list = NULL;
1628 /* position where in the list to insert newly encountered pointers */
1629 static int ndr_pointer_list_pos=0;
1631 /* boolean controlling whether pointers are top-level or embedded */
1632 static gboolean pointers_are_top_level = TRUE;
1634 /* as a kludge, we represent all embedded reference pointers as id==-1
1635 hoping that his will not collide with any non-ref pointers */
1636 typedef struct ndr_pointer_data {
1638 proto_item *item; /* proto_item for pointer */
1639 proto_tree *tree; /* subtree of above item */
1640 dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
1642 dcerpc_callback_fnct_t *callback;
1643 void *callback_args;
1644 } ndr_pointer_data_t;
1647 init_ndr_pointer_list(packet_info *pinfo)
1651 di=pinfo->private_data;
1652 di->conformant_run=0;
1654 while(ndr_pointer_list){
1655 ndr_pointer_data_t *npd;
1657 npd=g_slist_nth_data(ndr_pointer_list, 0);
1658 ndr_pointer_list=g_slist_remove(ndr_pointer_list, npd);
1664 ndr_pointer_list=NULL;
1665 ndr_pointer_list_pos=0;
1666 pointers_are_top_level=TRUE;
1670 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, guint8 *drep)
1672 int found_new_pointer;
1678 di=pinfo->private_data;
1682 found_new_pointer=0;
1683 len=g_slist_length(ndr_pointer_list);
1684 for(i=next_pointer;i<len;i++){
1685 ndr_pointer_data_t *tnpd;
1686 tnpd=g_slist_nth_data(ndr_pointer_list, i);
1688 dcerpc_dissect_fnct_t *fnct;
1691 found_new_pointer=1;
1694 ndr_pointer_list_pos=i+1;
1695 di->hf_index=tnpd->hf_index;
1696 /* first a run to handle any conformant
1698 di->conformant_run=1;
1699 di->conformant_eaten=0;
1700 old_offset = offset;
1701 offset = (*(fnct))(tvb, offset, pinfo, NULL, drep);
1703 g_assert((offset-old_offset)==di->conformant_eaten);
1704 /* This is to check for any bugs in the dissectors.
1706 * Basically, the NDR representation will store all
1707 * arrays in two blocks, one block with the dimension
1708 * discreption, like size, number of elements and such,
1709 * and another block that contains the actual data stored
1711 * If the array is embedded directly inside another,
1712 * encapsulating aggregate type, like a union or struct,
1713 * then these two blocks will be stored at different places
1714 * in the bytestream, with other data between the blocks.
1716 * For this reason, all pointers to types (both aggregate
1717 * and scalar, for simplicity no distinction is made)
1718 * will have its dissector called twice.
1719 * The dissector will first be called with conformant_run==1
1720 * in which mode the dissector MUST NOT consume any data from
1721 * the tvbuff (i.e. may not dissect anything) except the
1722 * initial control block for arrays.
1723 * The second time the dissector is called, with
1724 * conformant_run==0, all other data for the type will be
1727 * All dissect_ndr_<type> dissectors are already prepared
1728 * for this and knows when it should eat data from the tvb
1729 * and when not to, so implementors of dissectors will
1730 * normally not need to worry about this or even know about
1731 * it. However, if a dissector for an aggregate type calls
1732 * a subdissector from outside packet-dcerpc.c, such as
1733 * the dissector in packet-smb.c for NT Security Descriptors
1734 * as an example, then it is VERY important to encapsulate
1735 * this call to an external subdissector with the appropriate
1736 * test for conformant_run, i.e. it will need something like
1740 * di=pinfo->private_data;
1741 * if(di->conformant_run){
1745 * to make sure it makes the right thing.
1746 * This assert will signal when someone has forgotten to
1747 * make the dissector aware of this requirement.
1750 /* now we dissect the actual pointer */
1751 di->conformant_run=0;
1752 old_offset = offset;
1753 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, drep);
1755 tnpd->callback(pinfo, tnpd->tree, tnpd->item, tvb, old_offset, offset, tnpd->callback_args);
1759 } while(found_new_pointer);
1766 add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
1767 dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index,
1768 dcerpc_callback_fnct_t *callback, void *callback_args)
1770 ndr_pointer_data_t *npd;
1772 /* check if this pointer is valid */
1775 dcerpc_call_value *value;
1777 di=pinfo->private_data;
1778 value=di->call_data;
1780 if(di->ptype == PDU_REQ){
1781 if(!(pinfo->fd->flags.visited)){
1782 if(id>value->max_ptr){
1787 /* if we havent seen the request bail out since we cant
1788 know whether this is the first non-NULL instance
1790 if(value->req_frame==0){
1791 /* XXX THROW EXCEPTION */
1794 /* We saw this one in the request frame, nothing to
1796 if(id<=value->max_ptr){
1802 npd=g_malloc(sizeof(ndr_pointer_data_t));
1807 npd->hf_index=hf_index;
1808 npd->callback=callback;
1809 npd->callback_args=callback_args;
1810 ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
1811 ndr_pointer_list_pos);
1812 ndr_pointer_list_pos++;
1817 find_pointer_index(guint32 id)
1819 ndr_pointer_data_t *npd;
1822 len=g_slist_length(ndr_pointer_list);
1824 npd=g_slist_nth_data(ndr_pointer_list, i);
1835 /* This function dissects an NDR pointer and stores the callback for later
1836 * deferred dissection.
1838 * fnct is the callback function for when we have reached this object in
1841 * type is what type of pointer.
1843 * this is text is what text we should put in any created tree node.
1845 * hf_index is what hf value we want to pass to the callback function when
1846 * it is called, the callback can later pich this one up from di->hf_index.
1848 * callback is executed after the pointer has been dereferenced.
1850 * callback_args is passed as an argument to the callback function
1852 * See packet-dcerpc-samr.c for examples
1855 dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1856 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
1857 int type, char *text, int hf_index,
1858 dcerpc_callback_fnct_t *callback, void *callback_args)
1862 di=pinfo->private_data;
1863 if(di->conformant_run){
1864 /* this call was only for dissecting the header for any
1865 embedded conformant array. we will not parse any
1866 pointers in this mode.
1871 /*TOP LEVEL REFERENCE POINTER*/
1872 if( pointers_are_top_level
1873 &&(type==NDR_POINTER_REF) ){
1877 /* we must find out a nice way to do the length here */
1878 item=proto_tree_add_text(tree, tvb, offset, 0,
1880 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1882 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1883 hf_index, callback, callback_args);
1887 /*TOP LEVEL FULL POINTER*/
1888 if( pointers_are_top_level
1889 && (type==NDR_POINTER_PTR) ){
1895 /* get the referent id */
1896 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1898 /* we got a NULL pointer */
1900 proto_tree_add_text(tree, tvb, offset-4, 4,
1901 "(NULL pointer) %s",text);
1905 /* see if we have seen this pointer before */
1906 idx=find_pointer_index(id);
1908 /* we have seen this pointer before */
1910 proto_tree_add_text(tree, tvb, offset-4, 4,
1911 "(duplicate PTR) %s",text);
1916 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1918 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1919 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1920 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
1921 callback, callback_args);
1924 /*TOP LEVEL UNIQUE POINTER*/
1925 if( pointers_are_top_level
1926 && (type==NDR_POINTER_UNIQUE) ){
1931 /* get the referent id */
1932 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1934 /* we got a NULL pointer */
1936 proto_tree_add_text(tree, tvb, offset-4, 4,
1937 "(NULL pointer) %s",text);
1942 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1944 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1945 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1946 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1947 hf_index, callback, callback_args);
1951 /*EMBEDDED REFERENCE POINTER*/
1952 if( (!pointers_are_top_level)
1953 && (type==NDR_POINTER_REF) ){
1958 /* get the referent id */
1959 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1962 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1964 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1965 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1966 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1967 hf_index, callback, callback_args);
1971 /*EMBEDDED UNIQUE POINTER*/
1972 if( (!pointers_are_top_level)
1973 && (type==NDR_POINTER_UNIQUE) ){
1978 /* get the referent id */
1979 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1981 /* we got a NULL pointer */
1983 proto_tree_add_text(tree, tvb, offset-4, 4,
1984 "(NULL pointer) %s", text);
1989 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1991 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1992 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1993 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1994 hf_index, callback, callback_args);
1998 /*EMBEDDED FULL POINTER*/
1999 if( (!pointers_are_top_level)
2000 && (type==NDR_POINTER_PTR) ){
2006 /* get the referent id */
2007 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
2009 /* we got a NULL pointer */
2011 proto_tree_add_text(tree, tvb, offset-4, 4,
2012 "(NULL pointer) %s",text);
2016 /* see if we have seen this pointer before */
2017 idx=find_pointer_index(id);
2019 /* we have seen this pointer before */
2021 proto_tree_add_text(tree, tvb, offset-4, 4,
2022 "(duplicate PTR) %s",text);
2027 item=proto_tree_add_text(tree, tvb, offset-4, 4,
2029 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2030 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
2031 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
2032 callback, callback_args);
2038 /* After each top level pointer we have dissected we have to
2039 dissect all deferrals before we move on to the next top level
2041 if(pointers_are_top_level==TRUE){
2042 pointers_are_top_level=FALSE;
2043 offset = dissect_deferred_pointers(pinfo, tvb, offset, drep);
2044 pointers_are_top_level=TRUE;
2051 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2052 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2053 int type, char *text, int hf_index)
2055 return dissect_ndr_pointer_cb(
2056 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
2061 show_stub_data (tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
2062 dcerpc_auth_info *auth_info, gboolean is_encrypted)
2064 int length, plain_length, auth_pad_len;
2065 guint auth_pad_offset;
2068 * We don't show stub data unless we have some in the tvbuff;
2069 * however, in the protocol tree, we show, as the number of
2070 * bytes, the reported number of bytes, not the number of bytes
2071 * that happen to be in the tvbuff.
2073 if (tvb_length_remaining (tvb, offset) > 0) {
2074 auth_pad_len = auth_info?auth_info->auth_pad_len:0;
2075 length = tvb_reported_length_remaining (tvb, offset);
2077 /* if auth_pad_len is larger than length then we ignore auth_pad_len totally */
2078 plain_length = length - auth_pad_len;
2079 if (plain_length < 1) {
2080 plain_length = length;
2083 auth_pad_offset = offset + plain_length;
2085 if (auth_info != NULL &&
2086 auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
2088 proto_tree_add_text(dcerpc_tree, tvb, offset, length,
2089 "Encrypted stub data (%d byte%s)",
2090 length, plurality(length, "", "s"));
2091 /* is the padding is still inside the encrypted blob, don't display it explicit */
2094 proto_tree_add_text(dcerpc_tree, tvb, offset, plain_length,
2095 "Decrypted stub data (%d byte%s)",
2096 plain_length, plurality(plain_length, "", "s"));
2099 proto_tree_add_text (dcerpc_tree, tvb, offset, plain_length,
2100 "Stub data (%d byte%s)", plain_length,
2101 plurality(plain_length, "", "s"));
2103 /* If there is auth padding at the end of the stub, display it */
2104 if (auth_pad_len != 0) {
2105 proto_tree_add_text (dcerpc_tree, tvb, auth_pad_offset,
2107 "Auth Padding (%u byte%s)",
2109 plurality(auth_pad_len, "", "s"));
2115 dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
2116 proto_tree *dcerpc_tree,
2117 tvbuff_t *volatile tvb, tvbuff_t *decrypted_tvb,
2118 guint8 *drep, dcerpc_info *info,
2119 dcerpc_auth_info *auth_info)
2121 volatile gint offset = 0;
2122 dcerpc_uuid_key key;
2123 dcerpc_uuid_value *sub_proto;
2124 proto_tree *volatile sub_tree = NULL;
2125 dcerpc_sub_dissector *proc;
2127 dcerpc_dissect_fnct_t *volatile sub_dissect;
2128 const char *volatile saved_proto;
2129 void *volatile saved_private_data;
2130 guint length, reported_length;
2131 tvbuff_t *volatile stub_tvb;
2132 volatile guint auth_pad_len;
2133 volatile int auth_pad_offset;
2135 char UUID_NAME[MAX_PATH];
2138 key.uuid = info->call_data->uuid;
2139 key.ver = info->call_data->ver;
2142 if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == NULL
2143 || !proto_is_protocol_enabled(sub_proto->proto)) {
2145 * We don't have a dissector for this UUID, or the protocol
2146 * for that UUID is disabled.
2149 proto_tree_add_boolean_hidden(dcerpc_tree, hf_dcerpc_unknown_if_id,
2150 tvb, offset, 0, TRUE);
2151 if (check_col (pinfo->cinfo, COL_INFO)) {
2153 if(ResolveWin32UUID(info->call_data->uuid, UUID_NAME, MAX_PATH))
2154 col_append_fstr (pinfo->cinfo, COL_INFO, " [%s] UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x rpcver: %u",
2155 UUID_NAME, info->call_data->uuid.Data1, info->call_data->uuid.Data2, info->call_data->uuid.Data3, info->call_data->uuid.Data4[0],
2156 info->call_data->uuid.Data4[1], info->call_data->uuid.Data4[2], info->call_data->uuid.Data4[3],
2157 info->call_data->uuid.Data4[4], info->call_data->uuid.Data4[5], info->call_data->uuid.Data4[6],
2158 info->call_data->uuid.Data4[7], info->call_data->ver);
2161 col_append_fstr (pinfo->cinfo, COL_INFO, " UNKUUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x rpcver: %u",
2162 info->call_data->uuid.Data1, info->call_data->uuid.Data2, info->call_data->uuid.Data3, info->call_data->uuid.Data4[0],
2163 info->call_data->uuid.Data4[1], info->call_data->uuid.Data4[2], info->call_data->uuid.Data4[3],
2164 info->call_data->uuid.Data4[4], info->call_data->uuid.Data4[5], info->call_data->uuid.Data4[6],
2165 info->call_data->uuid.Data4[7], info->call_data->ver);
2168 if (decrypted_tvb != NULL) {
2169 show_stub_data (decrypted_tvb, 0, dcerpc_tree, auth_info,
2172 show_stub_data (tvb, 0, dcerpc_tree, auth_info, TRUE);
2176 for (proc = sub_proto->procs; proc->name; proc++) {
2177 if (proc->num == info->call_data->opnum) {
2186 if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
2187 col_set_str (pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
2190 if (check_col (pinfo->cinfo, COL_INFO)) {
2191 col_add_fstr (pinfo->cinfo, COL_INFO, "%s %s",
2192 name, (info->ptype == PDU_REQ) ? "request" : "response");
2196 proto_item *sub_item;
2197 sub_item = proto_tree_add_item (tree, sub_proto->proto_id, tvb, 0,
2201 sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
2202 proto_item_append_text(sub_item, ", %s", name);
2206 * Put the operation number into the tree along with
2207 * the operation's name.
2210 if (sub_proto->opnum_hf != -1)
2211 proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
2212 tvb, 0, 0, info->call_data->opnum,
2213 "Operation: %s (%u)",
2214 name, info->call_data->opnum);
2216 proto_tree_add_uint_format(sub_tree, hf_dcerpc_op, tvb,
2217 0, 0, info->call_data->opnum,
2218 "Operation: %s (%u)",
2219 name, info->call_data->opnum);
2222 sub_dissect = (info->ptype == PDU_REQ) ?
2223 proc->dissect_rqst : proc->dissect_resp;
2225 if (decrypted_tvb != NULL) {
2226 /* Either there was no encryption or we successfully decrypted
2227 the entrypted payload. */
2229 /* We have a subdissector - call it. */
2230 saved_proto = pinfo->current_proto;
2231 saved_private_data = pinfo->private_data;
2232 pinfo->current_proto = sub_proto->name;
2233 pinfo->private_data = (void *)info;
2235 init_ndr_pointer_list(pinfo);
2238 * Remove the authentication padding from the stub data.
2240 if (auth_info != NULL && auth_info->auth_pad_len != 0) {
2241 length = tvb_length(decrypted_tvb);
2242 reported_length = tvb_reported_length(decrypted_tvb);
2243 if (reported_length >= auth_info->auth_pad_len) {
2245 * OK, the padding length isn't so big that it
2246 * exceeds the stub length. Trim the reported
2247 * length of the tvbuff.
2249 reported_length -= auth_info->auth_pad_len;
2252 * If that exceeds the actual amount of data in
2253 * the tvbuff (which means we have at least one
2254 * byte of authentication padding in the tvbuff),
2255 * trim the actual amount.
2257 if (length > reported_length)
2258 length = reported_length;
2260 stub_tvb = tvb_new_subset(tvb, 0, length, reported_length);
2261 auth_pad_len = auth_info->auth_pad_len;
2262 auth_pad_offset = reported_length;
2265 * The padding length exceeds the stub length.
2266 * Don't bother dissecting the stub, trim the padding
2267 * length to what's in the stub data, and show the
2268 * entire stub as authentication padding.
2271 auth_pad_len = reported_length;
2272 auth_pad_offset = 0;
2276 * No authentication padding.
2278 stub_tvb = decrypted_tvb;
2280 auth_pad_offset = 0;
2283 if (stub_tvb != NULL) {
2285 * Catch all exceptions other than BoundsError, so that even
2286 * if the stub data is bad, we still show the authentication
2289 * If we get BoundsError, it means the frame was cut short
2290 * by a snapshot length, so there's nothing more to
2291 * dissect; just re-throw that exception.
2294 offset = sub_dissect (decrypted_tvb, 0, pinfo, sub_tree,
2297 /* If we have a subdissector and it didn't dissect all
2298 data in the tvb, make a note of it. */
2300 if (tvb_reported_length_remaining(stub_tvb, offset) > 0) {
2301 if (check_col(pinfo->cinfo, COL_INFO))
2302 col_append_fstr(pinfo->cinfo, COL_INFO,
2303 "[Long frame (%d bytes)]",
2304 tvb_reported_length_remaining(stub_tvb, offset));
2306 } CATCH(BoundsError) {
2309 show_exception(decrypted_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
2313 /* If there is auth padding at the end of the stub, display it */
2314 if (auth_pad_len != 0) {
2315 proto_tree_add_text (sub_tree, decrypted_tvb, auth_pad_offset,
2317 "Auth Padding (%u byte%s)",
2319 plurality(auth_pad_len, "", "s"));
2322 pinfo->current_proto = saved_proto;
2323 pinfo->private_data = saved_private_data;
2325 /* No subdissector - show it as stub data. */
2327 show_stub_data (decrypted_tvb, 0, sub_tree, auth_info, FALSE);
2329 show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
2333 show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
2335 tap_queue_packet(dcerpc_tap, pinfo, info);
2340 dissect_dcerpc_verifier (tvbuff_t *tvb, packet_info *pinfo,
2341 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
2342 dcerpc_auth_info *auth_info)
2346 auth_info->auth_data = NULL;
2348 if (auth_info->auth_size != 0) {
2349 dcerpc_auth_subdissector_fns *auth_fns;
2352 auth_offset = hdr->frag_len - hdr->auth_len;
2354 auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
2357 auth_info->auth_data = auth_tvb;
2359 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
2360 auth_info->auth_type))) {
2362 * Catch all exceptions, so that even if the verifier is bad
2363 * or we don't have all of it, we still show the stub data.
2366 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
2369 show_exception(auth_tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
2372 proto_tree_add_text (dcerpc_tree, auth_tvb, 0, hdr->auth_len,
2377 return hdr->auth_len;
2381 dissect_dcerpc_cn_auth (tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
2382 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
2383 gboolean are_credentials, dcerpc_auth_info *auth_info)
2385 volatile int offset;
2388 * Initially set auth_level and auth_type to zero to indicate that we
2389 * haven't yet seen any authentication level information.
2391 auth_info->auth_level = 0;
2392 auth_info->auth_type = 0;
2393 auth_info->auth_size = 0;
2394 auth_info->auth_pad_len = 0;
2397 * The authentication information is at the *end* of the PDU; in
2398 * request and response PDUs, the request and response stub data
2401 * Is there any authentication data (i.e., is the authentication length
2402 * non-zero), and is the authentication length valid (i.e., is it, plus
2403 * 8 bytes for the type/level/pad length/reserved/context id, less than
2404 * or equal to the fragment length minus the starting offset of the
2409 && (hdr->auth_len + 8 <= hdr->frag_len - stub_offset)) {
2412 * Yes, there is authentication data, and the length is valid.
2413 * Do we have all the bytes of stub data?
2414 * (If not, we'd throw an exception dissecting *that*, so don't
2415 * bother trying to dissect the authentication information and
2416 * throwing another exception there.)
2418 offset = hdr->frag_len - (hdr->auth_len + 8);
2419 if (offset == 0 || tvb_offset_exists(tvb, offset - 1)) {
2421 * Either there's no stub data, or the last byte of the stub
2422 * data is present in the captured data, so we shouldn't
2423 * get a BoundsError dissecting the stub data.
2425 * Try dissecting the authentication data.
2426 * Catch all exceptions, so that even if the auth info is bad
2427 * or we don't have all of it, we still show the stuff we
2428 * dissect after this, such as stub data.
2431 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2432 hf_dcerpc_auth_type,
2433 &auth_info->auth_type);
2434 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2435 hf_dcerpc_auth_level,
2436 &auth_info->auth_level);
2438 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2439 hf_dcerpc_auth_pad_len,
2440 &auth_info->auth_pad_len);
2441 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2442 hf_dcerpc_auth_rsrvd, NULL);
2443 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2444 hf_dcerpc_auth_ctx_id, NULL);
2447 * Dissect the authentication data.
2449 if (are_credentials) {
2451 dcerpc_auth_subdissector_fns *auth_fns;
2453 auth_tvb = tvb_new_subset(tvb, offset, hdr->auth_len,
2456 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
2457 auth_info->auth_type)))
2458 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
2461 proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len,
2462 "Auth Credentials");
2465 /* Compute the size of the auth block. Note that this should not
2466 include auth padding, since when NTLMSSP encryption is used, the
2467 padding is actually inside the encrypted stub */
2468 auth_info->auth_size = hdr->auth_len + 8;
2470 show_exception(tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
2477 /* We need to hash in the SMB fid number to generate a unique hash table
2478 * key as DCERPC over SMB allows several pipes over the same TCP/IP
2480 * We pass this function the transport type here to make sure we only look
2481 * at this function if it came across an SMB pipe.
2482 * Other transports might need to mix in their own extra multiplexing data
2483 * as well in the future.
2486 guint16 dcerpc_get_transport_salt (packet_info *pinfo)
2488 switch(pinfo->dcetransporttype){
2489 case DCE_CN_TRANSPORT_SMBPIPE:
2490 /* DCERPC over smb */
2491 return pinfo->dcetransportsalt;
2494 /* Some other transport... */
2499 * Connection oriented packet types
2503 dissect_dcerpc_cn_bind (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2504 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2506 conversation_t *conv = NULL;
2507 guint8 num_ctx_items = 0;
2509 gboolean saw_ctx_item = FALSE;
2511 guint8 num_trans_items;
2516 guint16 if_ver, if_ver_minor;
2517 char uuid_str[DCERPC_UUID_STR_LEN];
2519 dcerpc_auth_info auth_info;
2521 char UUID_NAME[MAX_PATH];
2524 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2525 hf_dcerpc_cn_max_xmit, NULL);
2527 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2528 hf_dcerpc_cn_max_recv, NULL);
2530 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2531 hf_dcerpc_cn_assoc_group, NULL);
2533 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2534 hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
2539 for (i = 0; i < num_ctx_items; i++) {
2540 proto_tree *ctx_tree = NULL, *iface_tree = NULL;
2542 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, NULL, hdr->drep,
2543 hf_dcerpc_cn_ctx_id, &ctx_id);
2545 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
2546 /* (if we have multiple contexts, this might cause "decode as"
2547 * to behave unpredictably) */
2548 pinfo->dcectxid = ctx_id;
2551 proto_item *ctx_item;
2553 ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_id,
2555 hdr->drep[0] & 0x10);
2557 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
2560 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, ctx_tree, hdr->drep,
2561 hf_dcerpc_cn_num_trans_items, &num_trans_items);
2566 /* XXX - use "dissect_ndr_uuid_t()"? */
2567 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
2569 proto_item *iface_item;
2571 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2572 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2573 if_id.Data1, if_id.Data2, if_id.Data3,
2574 if_id.Data4[0], if_id.Data4[1],
2575 if_id.Data4[2], if_id.Data4[3],
2576 if_id.Data4[4], if_id.Data4[5],
2577 if_id.Data4[6], if_id.Data4[7]);
2579 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2580 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2582 if(ResolveWin32UUID(if_id, UUID_NAME, MAX_PATH))
2583 iface_item = proto_tree_add_string_format (ctx_tree, hf_dcerpc_cn_bind_if_id, tvb,
2584 offset, 16, uuid_str, "Interface [%s] UUID: %s", UUID_NAME, uuid_str);
2587 iface_item = proto_tree_add_string_format (ctx_tree, hf_dcerpc_cn_bind_if_id, tvb,
2588 offset, 16, uuid_str, "Interface UUID: %s", uuid_str);
2589 iface_tree = proto_item_add_subtree(iface_item, ett_dcerpc_cn_iface);
2593 if (hdr->drep[0] & 0x10) {
2594 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2595 hf_dcerpc_cn_bind_if_ver, &if_ver);
2596 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2597 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2599 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2600 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2601 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2602 hf_dcerpc_cn_bind_if_ver, &if_ver);
2605 if (!saw_ctx_item) {
2606 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
2607 pinfo->srcport, pinfo->destport, 0);
2609 conv = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
2610 pinfo->srcport, pinfo->destport, 0);
2614 /* if this is the first time we see this packet, we need to
2615 update the dcerpc_binds table so that any later calls can
2616 match to the interface.
2617 XXX We assume that BINDs will NEVER be fragmented.
2619 if(!(pinfo->fd->flags.visited)){
2620 dcerpc_bind_key *key;
2621 dcerpc_bind_value *value;
2623 key = g_mem_chunk_alloc (dcerpc_bind_key_chunk);
2625 key->ctx_id = ctx_id;
2626 key->smb_fid = dcerpc_get_transport_salt(pinfo);
2628 value = g_mem_chunk_alloc (dcerpc_bind_value_chunk);
2629 value->uuid = if_id;
2630 value->ver = if_ver;
2632 /* add this entry to the bind table, first removing any
2633 previous ones that are identical
2635 if(g_hash_table_lookup(dcerpc_binds, key)){
2636 g_hash_table_remove(dcerpc_binds, key);
2638 g_hash_table_insert (dcerpc_binds, key, value);
2641 if (check_col (pinfo->cinfo, COL_INFO)) {
2642 dcerpc_uuid_key key;
2643 dcerpc_uuid_value *value;
2648 if (num_ctx_items > 1)
2649 col_append_fstr(pinfo->cinfo, COL_INFO, ", %u context items, 1st", num_ctx_items);
2651 if ((value = g_hash_table_lookup(dcerpc_uuids, &key)))
2652 col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %s", value->name);
2655 if(ResolveWin32UUID(if_id, UUID_NAME, MAX_PATH))
2656 col_append_fstr(pinfo->cinfo, COL_INFO, " [%s] UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
2657 UUID_NAME, if_id.Data1, if_id.Data2, if_id.Data3,
2658 if_id.Data4[0], if_id.Data4[1],
2659 if_id.Data4[2], if_id.Data4[3],
2660 if_id.Data4[4], if_id.Data4[5],
2661 if_id.Data4[6], if_id.Data4[7],
2662 if_ver, if_ver_minor);
2665 col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
2666 if_id.Data1, if_id.Data2, if_id.Data3,
2667 if_id.Data4[0], if_id.Data4[1],
2668 if_id.Data4[2], if_id.Data4[3],
2669 if_id.Data4[4], if_id.Data4[5],
2670 if_id.Data4[6], if_id.Data4[7],
2671 if_ver, if_ver_minor);
2673 saw_ctx_item = TRUE;
2676 for (j = 0; j < num_trans_items; j++) {
2677 /* XXX - use "dissect_ndr_uuid_t()"? */
2678 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2680 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2681 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2682 trans_id.Data1, trans_id.Data2, trans_id.Data3,
2683 trans_id.Data4[0], trans_id.Data4[1],
2684 trans_id.Data4[2], trans_id.Data4[3],
2685 trans_id.Data4[4], trans_id.Data4[5],
2686 trans_id.Data4[6], trans_id.Data4[7]);
2687 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2688 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2689 proto_tree_add_string_format (iface_tree, hf_dcerpc_cn_bind_trans_id, tvb,
2690 offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2694 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, iface_tree, hdr->drep,
2695 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
2700 * XXX - we should save the authentication type *if* we have
2701 * an authentication header, and associate it with an authentication
2702 * context, so subsequent PDUs can use that context.
2704 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2708 dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2709 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2711 guint16 max_xmit, max_recv;
2712 guint16 sec_addr_len;
2719 char uuid_str[DCERPC_UUID_STR_LEN];
2721 dcerpc_auth_info auth_info;
2723 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2724 hf_dcerpc_cn_max_xmit, &max_xmit);
2726 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2727 hf_dcerpc_cn_max_recv, &max_recv);
2729 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2730 hf_dcerpc_cn_assoc_group, NULL);
2732 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2733 hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
2734 if (sec_addr_len != 0) {
2735 proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
2736 sec_addr_len, FALSE);
2737 offset += sec_addr_len;
2741 offset += 4 - offset % 4;
2744 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2745 hf_dcerpc_cn_num_results, &num_results);
2750 for (i = 0; i < num_results; i++) {
2751 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2752 hdr->drep, hf_dcerpc_cn_ack_result,
2755 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2756 hdr->drep, hf_dcerpc_cn_ack_reason,
2760 * The reason for rejection isn't meaningful, and often isn't
2761 * set, when the syntax was accepted.
2766 /* XXX - use "dissect_ndr_uuid_t()"? */
2767 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2769 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2770 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2771 trans_id.Data1, trans_id.Data2, trans_id.Data3,
2772 trans_id.Data4[0], trans_id.Data4[1],
2773 trans_id.Data4[2], trans_id.Data4[3],
2774 trans_id.Data4[4], trans_id.Data4[5],
2775 trans_id.Data4[6], trans_id.Data4[7]);
2776 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2777 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2778 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_ack_trans_id, tvb,
2779 offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2783 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2784 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
2788 * XXX - do we need to do anything with the authentication level
2789 * we get back from this?
2791 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2793 if (check_col (pinfo->cinfo, COL_INFO)) {
2794 if (num_results != 0 && result == 0) {
2795 /* XXX - only checks the last result */
2796 col_append_fstr (pinfo->cinfo, COL_INFO,
2797 " accept max_xmit: %u max_recv: %u",
2798 max_xmit, max_recv);
2800 /* XXX - only shows the last result and reason */
2801 col_append_fstr (pinfo->cinfo, COL_INFO, " %s, reason: %s",
2802 val_to_str(result, p_cont_result_vals,
2803 "Unknown result (%u)"),
2804 val_to_str(reason, p_provider_reason_vals,
2811 dissect_dcerpc_cn_bind_nak (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2812 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2815 guint8 num_protocols;
2818 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2819 hdr->drep, hf_dcerpc_cn_reject_reason,
2822 if (check_col (pinfo->cinfo, COL_INFO)) {
2823 col_append_fstr (pinfo->cinfo, COL_INFO, " reason: %s",
2824 val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
2827 if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
2828 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2829 hf_dcerpc_cn_num_protocols,
2832 for (i = 0; i < num_protocols; i++) {
2833 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2834 hdr->drep, hf_dcerpc_cn_protocol_ver_major,
2836 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2837 hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
2843 /* Return a string describing a DCE/RPC fragment as first, middle, or end
2846 #define PFC_FRAG_MASK 0x03
2849 fragment_type(guint8 flags)
2851 flags = flags & PFC_FRAG_MASK;
2853 if (flags == PFC_FIRST_FRAG)
2859 if (flags == PFC_LAST_FRAG)
2862 if (flags == (PFC_FIRST_FRAG | PFC_LAST_FRAG))
2868 /* Dissect stub data (payload) of a DCERPC packet. */
2871 dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
2872 proto_tree *dcerpc_tree, proto_tree *tree,
2873 e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
2874 dcerpc_auth_info *auth_info, guint32 alloc_hint,
2877 gint length, reported_length;
2878 gboolean save_fragmented;
2879 fragment_data *fd_head=NULL;
2881 tvbuff_t *auth_tvb, *payload_tvb, *decrypted_tvb;
2884 save_fragmented = pinfo->fragmented;
2886 length = tvb_length_remaining(tvb, offset);
2887 reported_length = tvb_reported_length_remaining(tvb, offset);
2888 if (reported_length < 0 ||
2889 (guint32)reported_length < auth_info->auth_size) {
2890 /* We don't even have enough bytes for the authentication
2894 reported_length -= auth_info->auth_size;
2895 if (length > reported_length)
2896 length = reported_length;
2897 payload_tvb = tvb_new_subset(tvb, offset, length, reported_length);
2900 /*dont bother if we dont have the entire tvb */
2901 /*XXX we should really make sure we calculate auth_info->auth_data
2902 and use that one instead of this auth_tvb hack
2904 if(tvb_length(tvb)==tvb_reported_length(tvb)){
2905 if(tvb_length_remaining(tvb, offset+length)>8){
2906 auth_tvb = tvb_new_subset(tvb, offset+length+8, -1, -1);
2910 /* Decrypt the PDU if it is encrypted */
2912 if (auth_info->auth_type &&
2913 auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
2915 * We know the authentication type, and the authentication
2916 * level is "Packet privacy", meaning the payload is
2917 * encrypted; attempt to decrypt it.
2919 dcerpc_auth_subdissector_fns *auth_fns;
2921 /* Start out assuming we won't succeed in decrypting. */
2922 decrypted_tvb = NULL;
2924 if ((auth_fns = get_auth_subdissector_fns(
2925 auth_info->auth_level, auth_info->auth_type))) {
2928 result = decode_encrypted_data(
2929 payload_tvb, auth_tvb, pinfo, auth_fns,
2930 hdr->ptype == PDU_REQ, auth_info);
2934 proto_tree_add_text(
2935 dcerpc_tree, payload_tvb, 0, -1,
2936 "Encrypted stub data (%d byte%s)",
2937 tvb_reported_length(payload_tvb),
2939 plurality(tvb_length(payload_tvb), "", "s"));
2941 add_new_data_source(
2942 pinfo, result, "Decrypted stub data");
2945 decrypted_tvb = result;
2949 decrypted_tvb = payload_tvb;
2951 /* if this packet is not fragmented, just dissect it and exit */
2952 if(PFC_NOT_FRAGMENTED(hdr)){
2953 pinfo->fragmented = FALSE;
2956 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
2957 hdr->drep, di, auth_info);
2959 pinfo->fragmented = save_fragmented;
2963 /* The packet is fragmented. */
2964 pinfo->fragmented = TRUE;
2966 /* if we are not doing reassembly and this is the first fragment
2967 then just dissect it and exit
2968 XXX - if we're not doing reassembly, can we decrypt an
2971 if( (!dcerpc_reassemble) && hdr->flags&PFC_FIRST_FRAG ){
2974 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
2975 hdr->drep, di, auth_info);
2977 if (check_col(pinfo->cinfo, COL_INFO)) {
2978 col_append_fstr(pinfo->cinfo, COL_INFO,
2979 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
2981 pinfo->fragmented = save_fragmented;
2985 /* if we have already seen this packet, see if it was reassembled
2986 and if so dissect the full pdu.
2989 if(pinfo->fd->flags.visited){
2990 fd_head=fragment_get(pinfo, frame, dcerpc_co_reassemble_table);
2994 /* if we are not doing reassembly and it was neither a complete PDU
2995 nor the first fragment then there is nothing more we can do
2996 so we just have to exit
2998 if( !dcerpc_reassemble )
3001 /* if we didnt get 'frame' we dont know where the PDU started and thus
3002 it is pointless to continue
3007 /* from now on we must attempt to reassemble the PDU
3010 /* if we get here we know it is the first time we see the packet
3011 and we also know it is only a fragment and not a full PDU,
3012 thus we must reassemble it.
3015 /* Do we have any non-encrypted data to reassemble? */
3016 if (decrypted_tvb == NULL) {
3017 /* No. We can't even try to reassemble. */
3021 /* defragmentation is a bit tricky here, as there's no offset of the fragment
3022 * in the protocol data.
3024 * Currently two possible ways:
3025 * - the transmitter sends an alloc_hint != 0, use it
3026 * - the transmitter sends an alloc_hint == 0, simply append fragments
3029 /* if this is the first fragment we need to start reassembly
3031 if(hdr->flags&PFC_FIRST_FRAG){
3032 fragment_add(decrypted_tvb, 0, pinfo, frame, dcerpc_co_reassemble_table,
3033 0, tvb_length(decrypted_tvb), TRUE);
3034 fragment_set_tot_len(pinfo, frame,
3035 dcerpc_co_reassemble_table, alloc_hint ? alloc_hint : tvb_length(decrypted_tvb));
3040 /* if this is a middle fragment, just add it and exit */
3041 if(!(hdr->flags&PFC_LAST_FRAG)){
3042 tot_len = fragment_get_tot_len(pinfo, frame,
3043 dcerpc_co_reassemble_table);
3044 fragment_add(decrypted_tvb, 0, pinfo, frame,
3045 dcerpc_co_reassemble_table,
3046 tot_len-alloc_hint, tvb_length(decrypted_tvb),
3048 if(alloc_hint == 0) {
3049 fragment_set_tot_len(pinfo, frame,
3050 dcerpc_co_reassemble_table, tot_len + tvb_length(decrypted_tvb));
3056 /* this was the last fragment add it to reassembly
3058 tot_len = fragment_get_tot_len(pinfo, frame,
3059 dcerpc_co_reassemble_table);
3060 fd_head = fragment_add(decrypted_tvb, 0, pinfo,
3062 dcerpc_co_reassemble_table,
3063 tot_len-alloc_hint, tvb_length(decrypted_tvb),
3065 if(alloc_hint == 0) {
3066 fragment_set_tot_len(pinfo, frame,
3067 dcerpc_co_reassemble_table, tot_len + tvb_length(decrypted_tvb));
3072 /* if reassembly is complete, dissect the full PDU
3074 if(fd_head && (fd_head->flags&FD_DEFRAGMENTED) ){
3076 if(pinfo->fd->num==fd_head->reassembled_in){
3079 next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
3080 tvb_set_child_real_data_tvbuff(decrypted_tvb, next_tvb);
3081 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3082 show_fragment_tree(fd_head, &dcerpc_frag_items,
3083 dcerpc_tree, pinfo, next_tvb);
3085 pinfo->fragmented = FALSE;
3087 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
3088 next_tvb, hdr->drep, di, auth_info);
3091 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
3092 decrypted_tvb, 0, 0, fd_head->reassembled_in);
3093 PROTO_ITEM_SET_GENERATED(pi);
3094 if (check_col(pinfo->cinfo, COL_INFO)) {
3095 col_append_fstr(pinfo->cinfo, COL_INFO,
3096 " [DCE/RPC %s fragment, reas: #%u]", fragment_type(hdr->flags), fd_head->reassembled_in);
3100 /* Reassembly not complete - some fragments
3101 are missing. Just show the stub data. */
3103 if (check_col(pinfo->cinfo, COL_INFO)) {
3104 col_append_fstr(pinfo->cinfo, COL_INFO,
3105 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
3109 show_stub_data (decrypted_tvb, 0, tree, auth_info, FALSE);
3111 show_stub_data (payload_tvb, 0, tree, auth_info, TRUE);
3115 pinfo->fragmented = save_fragmented;
3119 * Registers a conversation/UUID binding association, so that
3120 * we can invoke the proper sub-dissector for a given DCERPC
3123 * @param binding all values needed to create and bind a new conversation
3125 * @return Pointer to newly-added UUID/conversation binding.
3127 struct _dcerpc_bind_value *
3128 dcerpc_add_conv_to_bind_table(decode_dcerpc_bind_values_t *binding)
3130 dcerpc_bind_value *bind_value;
3131 dcerpc_bind_key *key;
3132 conversation_t *conv;
3134 conv = find_conversation (
3144 conv = conversation_new (
3154 bind_value = g_mem_chunk_alloc (dcerpc_bind_value_chunk);
3155 bind_value->uuid = binding->uuid;
3156 bind_value->ver = binding->ver;
3158 key = g_mem_chunk_alloc(dcerpc_bind_key_chunk);
3160 key->ctx_id = binding->ctx_id;
3161 key->smb_fid = binding->smb_fid;
3163 /* add this entry to the bind table, first removing any
3164 previous ones that are identical
3166 if(g_hash_table_lookup(dcerpc_binds, key)){
3167 g_hash_table_remove(dcerpc_binds, key);
3169 g_hash_table_insert(dcerpc_binds, key, bind_value);
3176 dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3177 proto_tree *dcerpc_tree, proto_tree *tree,
3178 e_dce_cn_common_hdr_t *hdr)
3180 conversation_t *conv;
3184 dcerpc_auth_info auth_info;
3186 char uuid_str[DCERPC_UUID_STR_LEN];
3190 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3191 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3193 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3194 hf_dcerpc_cn_ctx_id, &ctx_id);
3196 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3197 hf_dcerpc_opnum, &opnum);
3199 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3200 pinfo->dcectxid = ctx_id;
3202 if (check_col (pinfo->cinfo, COL_INFO)) {
3203 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u ctx_id: %u",
3207 if (hdr->flags & PFC_OBJECT_UUID) {
3208 /* XXX - use "dissect_ndr_uuid_t()"? */
3209 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id);
3211 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
3212 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3213 obj_id.Data1, obj_id.Data2, obj_id.Data3,
3222 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
3223 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
3224 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
3225 offset, 16, uuid_str, "Object UUID: %s", uuid_str);
3231 * XXX - what if this was set when the connection was set up,
3232 * and we just have a security context?
3234 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3236 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3237 pinfo->srcport, pinfo->destport, 0);
3239 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3241 dcerpc_matched_key matched_key, *new_matched_key;
3242 dcerpc_call_value *value;
3244 /* !!! we can NOT check flags.visited here since this will interact
3245 badly with when SMB handles (i.e. calls the subdissector)
3246 and desegmented pdu's .
3247 Instead we check if this pdu is already in the matched table or not
3249 matched_key.frame = pinfo->fd->num;
3250 matched_key.call_id = hdr->call_id;
3251 value = g_hash_table_lookup(dcerpc_matched, &matched_key);
3253 dcerpc_bind_key bind_key;
3254 dcerpc_bind_value *bind_value;
3257 bind_key.ctx_id=ctx_id;
3258 bind_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3260 if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key)) ){
3261 if(!(hdr->flags&PFC_FIRST_FRAG)){
3262 dcerpc_cn_call_key call_key;
3263 dcerpc_call_value *call_value;
3266 call_key.call_id=hdr->call_id;
3267 call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3268 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3269 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3270 *new_matched_key = matched_key;
3271 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3275 dcerpc_cn_call_key *call_key;
3276 dcerpc_call_value *call_value;
3278 /* We found the binding and it is the first fragment
3279 (or a complete PDU) of a dcerpc pdu so just add
3280 the call to both the call table and the
3283 call_key=g_mem_chunk_alloc (dcerpc_cn_call_key_chunk);
3284 call_key->conv=conv;
3285 call_key->call_id=hdr->call_id;
3286 call_key->smb_fid=dcerpc_get_transport_salt(pinfo);
3288 /* if there is already a matching call in the table
3289 remove it so it is replaced with the new one */
3290 if(g_hash_table_lookup(dcerpc_cn_calls, call_key)){
3291 g_hash_table_remove(dcerpc_cn_calls, call_key);
3294 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
3295 call_value->uuid = bind_value->uuid;
3296 call_value->ver = bind_value->ver;
3297 call_value->opnum = opnum;
3298 call_value->req_frame=pinfo->fd->num;
3299 call_value->req_time.secs=pinfo->fd->abs_secs;
3300 call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000;
3301 call_value->rep_frame=0;
3302 call_value->max_ptr=0;
3303 call_value->private_data = NULL;
3304 g_hash_table_insert (dcerpc_cn_calls, call_key, call_value);
3306 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3307 *new_matched_key = matched_key;
3308 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3318 /* handoff this call */
3320 di->call_id = hdr->call_id;
3321 di->smb_fid = dcerpc_get_transport_salt(pinfo);
3322 di->ptype = PDU_REQ;
3323 di->call_data = value;
3326 if(value->rep_frame!=0){
3327 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
3328 tvb, 0, 0, value->rep_frame);
3329 PROTO_ITEM_SET_GENERATED(pi);
3332 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
3333 hdr, di, &auth_info, alloc_hint,
3336 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3339 /* Dissect the verifier */
3340 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
3345 dissect_dcerpc_cn_resp (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3346 proto_tree *dcerpc_tree, proto_tree *tree,
3347 e_dce_cn_common_hdr_t *hdr)
3349 dcerpc_call_value *value = NULL;
3350 conversation_t *conv;
3352 dcerpc_auth_info auth_info;
3356 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3357 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3359 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3360 hf_dcerpc_cn_ctx_id, &ctx_id);
3362 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3363 pinfo->dcectxid = ctx_id;
3365 if (check_col (pinfo->cinfo, COL_INFO)) {
3366 col_append_fstr (pinfo->cinfo, COL_INFO, " ctx_id: %u", ctx_id);
3369 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3370 hf_dcerpc_cn_cancel_count, NULL);
3375 * XXX - what if this was set when the connection was set up,
3376 * and we just have a security context?
3378 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3380 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3381 pinfo->srcport, pinfo->destport, 0);
3384 /* no point in creating one here, really */
3385 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3387 dcerpc_matched_key matched_key, *new_matched_key;
3389 /* !!! we can NOT check flags.visited here since this will interact
3390 badly with when SMB handles (i.e. calls the subdissector)
3391 and desegmented pdu's .
3392 Instead we check if this pdu is already in the matched table or not
3394 matched_key.frame = pinfo->fd->num;
3395 matched_key.call_id = hdr->call_id;
3396 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3398 dcerpc_cn_call_key call_key;
3399 dcerpc_call_value *call_value;
3402 call_key.call_id=hdr->call_id;
3403 call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3405 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3406 /* extra sanity check, only match them if the reply
3407 came after the request */
3408 if(call_value->req_frame<pinfo->fd->num){
3409 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3410 *new_matched_key = matched_key;
3411 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3413 if(call_value->rep_frame==0){
3414 call_value->rep_frame=pinfo->fd->num;
3424 /* handoff this call */
3426 di->call_id = hdr->call_id;
3427 di->smb_fid = dcerpc_get_transport_salt(pinfo);
3428 di->ptype = PDU_RESP;
3429 di->call_data = value;
3431 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
3432 if(value->req_frame!=0){
3434 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3435 tvb, 0, 0, value->req_frame);
3436 PROTO_ITEM_SET_GENERATED(pi);
3437 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
3438 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
3440 ns.nsecs+=1000000000;
3443 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
3444 PROTO_ITEM_SET_GENERATED(pi);
3447 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
3448 hdr, di, &auth_info, alloc_hint,
3451 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3454 /* Dissect the verifier */
3455 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
3459 dissect_dcerpc_cn_fault (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3460 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
3462 dcerpc_call_value *value = NULL;
3463 conversation_t *conv;
3467 dcerpc_auth_info auth_info;
3470 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3471 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3473 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3474 hf_dcerpc_cn_ctx_id, &ctx_id);
3476 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3477 hf_dcerpc_cn_cancel_count, NULL);
3481 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3482 hf_dcerpc_cn_status, &status);
3484 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3485 pinfo->dcectxid = ctx_id;
3487 if (check_col (pinfo->cinfo, COL_INFO)) {
3488 col_append_fstr (pinfo->cinfo, COL_INFO,
3489 " ctx_id: %u status: %s", ctx_id,
3490 val_to_str(status, reject_status_vals,
3491 "Unknown (0x%08x)"));
3498 * XXX - what if this was set when the connection was set up,
3499 * and we just have a security context?
3501 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3503 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3504 pinfo->srcport, pinfo->destport, 0);
3506 /* no point in creating one here, really */
3508 dcerpc_matched_key matched_key, *new_matched_key;
3510 /* !!! we can NOT check flags.visited here since this will interact
3511 badly with when SMB handles (i.e. calls the subdissector)
3512 and desegmented pdu's .
3513 Instead we check if this pdu is already in the matched table or not
3515 matched_key.frame = pinfo->fd->num;
3516 matched_key.call_id = hdr->call_id;
3517 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3519 dcerpc_cn_call_key call_key;
3520 dcerpc_call_value *call_value;
3523 call_key.call_id=hdr->call_id;
3524 call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3526 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3527 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3528 *new_matched_key = matched_key;
3529 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3531 if(call_value->rep_frame==0){
3532 call_value->rep_frame=pinfo->fd->num;
3539 int length, reported_length, stub_length;
3543 /* handoff this call */
3545 di->call_id = hdr->call_id;
3546 di->smb_fid = dcerpc_get_transport_salt(pinfo);
3547 di->ptype = PDU_FAULT;
3548 di->call_data = value;
3550 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
3551 if(value->req_frame!=0){
3553 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3554 tvb, 0, 0, value->req_frame);
3555 PROTO_ITEM_SET_GENERATED(pi);
3556 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
3557 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
3559 ns.nsecs+=1000000000;
3562 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
3563 PROTO_ITEM_SET_GENERATED(pi);
3566 length = tvb_length_remaining(tvb, offset);
3567 reported_length = tvb_reported_length_remaining(tvb, offset);
3568 stub_length = hdr->frag_len - offset - auth_info.auth_size;
3569 if (length > stub_length)
3570 length = stub_length;
3571 if (reported_length > stub_length)
3572 reported_length = stub_length;
3574 /* If we don't have reassembly enabled, or this packet contains
3575 the entire PDU, or if we don't have all the data in this
3576 fragment, just call the handoff directly if this is the
3577 first fragment or the PDU isn't fragmented. */
3578 if( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
3579 !tvb_bytes_exist(tvb, offset, stub_length) ){
3580 if(hdr->flags&PFC_FIRST_FRAG){
3581 /* First fragment, possibly the only fragment */
3583 * XXX - should there be a third routine for each
3584 * function in an RPC subdissector, to handle
3585 * fault responses? The DCE RPC 1.1 spec says
3586 * three's "stub data" here, which I infer means
3587 * that it's protocol-specific and call-specific.
3589 * It should probably get passed the status code
3590 * as well, as that might be protocol-specific.
3593 if (stub_length > 0) {
3594 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3595 "Fault stub data (%d byte%s)",
3597 plurality(stub_length, "", "s"));
3601 /* PDU is fragmented and this isn't the first fragment */
3602 if (check_col(pinfo->cinfo, COL_INFO)) {
3603 col_append_fstr(pinfo->cinfo, COL_INFO,
3604 " [DCE/RPC fragment]");
3607 if (stub_length > 0) {
3608 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3609 "Fragment data (%d byte%s)",
3611 plurality(stub_length, "", "s"));
3616 /* Reassembly is enabled, the PDU is fragmented, and
3617 we have all the data in the fragment; the first two
3618 of those mean we should attempt reassembly, and the
3619 third means we can attempt reassembly. */
3622 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3623 "Fragment data (%d byte%s)",
3625 plurality(stub_length, "", "s"));
3628 if(hdr->flags&PFC_FIRST_FRAG){ /* FIRST fragment */
3629 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
3630 fragment_add(tvb, offset, pinfo, value->rep_frame,
3631 dcerpc_co_reassemble_table,
3635 fragment_set_tot_len(pinfo, value->rep_frame,
3636 dcerpc_co_reassemble_table, alloc_hint);
3638 if (check_col(pinfo->cinfo, COL_INFO)) {
3639 col_append_fstr(pinfo->cinfo, COL_INFO,
3640 " [DCE/RPC fragment]");
3642 } else if(hdr->flags&PFC_LAST_FRAG){ /* LAST fragment */
3643 if( value->rep_frame ){
3644 fragment_data *fd_head;
3647 tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
3648 dcerpc_co_reassemble_table);
3649 fd_head = fragment_add(tvb, offset, pinfo,
3651 dcerpc_co_reassemble_table,
3657 /* We completed reassembly */
3660 next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
3661 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
3662 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3663 show_fragment_tree(fd_head, &dcerpc_frag_items,
3664 dcerpc_tree, pinfo, next_tvb);
3667 * XXX - should there be a third routine for each
3668 * function in an RPC subdissector, to handle
3669 * fault responses? The DCE RPC 1.1 spec says
3670 * three's "stub data" here, which I infer means
3671 * that it's protocol-specific and call-specific.
3673 * It should probably get passed the status code
3674 * as well, as that might be protocol-specific.
3678 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3679 "Fault stub data (%d byte%s)",
3681 plurality(stub_length, "", "s"));
3685 /* Reassembly not complete - some fragments
3687 if (check_col(pinfo->cinfo, COL_INFO)) {
3688 col_append_fstr(pinfo->cinfo, COL_INFO,
3689 " [DCE/RPC fragment]");
3693 } else { /* MIDDLE fragment(s) */
3694 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
3696 tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
3697 dcerpc_co_reassemble_table);
3698 fragment_add(tvb, offset, pinfo, value->rep_frame,
3699 dcerpc_co_reassemble_table,
3704 if (check_col(pinfo->cinfo, COL_INFO)) {
3705 col_append_fstr(pinfo->cinfo, COL_INFO,
3706 " [DCE/RPC fragment]");
3715 * DCERPC dissector for connection oriented calls.
3716 * We use transport type to later multiplex between what kind of
3717 * pinfo->private_data structure to expect.
3720 dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
3721 proto_tree *tree, gboolean can_desegment, int *pkt_len)
3723 static const guint8 nulls[4] = { 0 };
3726 proto_item *ti = NULL;
3727 proto_item *tf = NULL;
3728 proto_tree *dcerpc_tree = NULL;
3729 proto_tree *cn_flags_tree = NULL;
3730 proto_tree *drep_tree = NULL;
3731 e_dce_cn_common_hdr_t hdr;
3732 dcerpc_auth_info auth_info;
3735 * when done over nbt, dcerpc requests are padded with 4 bytes of null
3736 * data for some reason.
3738 * XXX - if that's always the case, the right way to do this would
3739 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
3740 * the 4 bytes of null padding, and make that the dissector
3741 * used for "netbios".
3743 if (tvb_memeql (tvb, offset, nulls, 4) == 0) {
3753 * Check if this looks like a C/O DCERPC call
3755 if (!tvb_bytes_exist (tvb, offset, sizeof (hdr))) {
3756 return FALSE; /* not enough information to check */
3758 start_offset = offset;
3759 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
3760 if (hdr.rpc_ver != 5)
3762 hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
3763 if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
3765 hdr.ptype = tvb_get_guint8 (tvb, offset++);
3769 hdr.flags = tvb_get_guint8 (tvb, offset++);
3770 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
3771 offset += sizeof (hdr.drep);
3773 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3775 hdr.auth_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3777 hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3780 if (can_desegment && pinfo->can_desegment
3781 && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
3782 pinfo->desegment_offset = start_offset;
3783 pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, start_offset);
3784 *pkt_len = 0; /* desegmentation required */
3788 if (check_col (pinfo->cinfo, COL_PROTOCOL))
3789 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
3791 if (check_col (pinfo->cinfo, COL_INFO)) {
3792 if(pinfo->dcectxid != 0) {
3793 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
3794 * append a delimiter and set a column fence */
3795 col_append_str (pinfo->cinfo, COL_INFO, " # ");
3796 col_set_fence(pinfo->cinfo,COL_INFO);
3798 col_add_fstr (pinfo->cinfo, COL_INFO, "%s: call_id: %u",
3799 pckt_vals[hdr.ptype].strptr, hdr.call_id);
3803 offset = start_offset;
3804 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE);
3806 dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
3808 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver);
3809 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset++, 1, hdr.rpc_ver_minor);
3810 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype);
3811 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
3812 cn_flags_tree = proto_item_add_subtree (tf, ett_dcerpc_cn_flags);
3813 if (cn_flags_tree) {
3814 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
3815 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
3816 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
3817 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
3818 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
3819 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
3820 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
3821 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
3825 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
3826 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
3828 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
3829 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
3830 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
3832 offset += sizeof (hdr.drep);
3834 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
3837 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
3840 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
3845 * None of the stuff done above should throw an exception, because
3846 * we would have rejected this as "not DCE RPC" if we didn't have all
3847 * of it. (XXX - perhaps we should request reassembly if we have
3848 * enough of the header to consider it DCE RPC but not enough to
3849 * get the fragment length; in that case the stuff still wouldn't
3850 * throw an exception.)
3852 * The rest of the stuff might, so return the PDU length to our caller.
3853 * XXX - should we construct a tvbuff containing only the PDU and
3854 * use that? Or should we have separate "is this a DCE RPC PDU",
3855 * "how long is it", and "dissect it" routines - which might let us
3856 * do most of the work in "tcp_dissect_pdus()"?
3858 if (pkt_len != NULL)
3859 *pkt_len = hdr.frag_len + padding;
3862 * Packet type specific stuff is next.
3864 switch (hdr.ptype) {
3867 dissect_dcerpc_cn_bind (tvb, offset, pinfo, dcerpc_tree, &hdr);
3872 dissect_dcerpc_cn_bind_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3877 * Nothing after the common header other than credentials.
3879 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, TRUE,
3884 dissect_dcerpc_cn_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
3888 dissect_dcerpc_cn_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
3892 dissect_dcerpc_cn_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
3896 dissect_dcerpc_cn_bind_nak (tvb, offset, pinfo, dcerpc_tree, &hdr);
3902 * Nothing after the common header other than an authentication
3905 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
3911 * Nothing after the common header, not even an authentication
3917 /* might as well dissect the auth info */
3918 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
3926 * DCERPC dissector for connection oriented calls over packet-oriented
3930 dissect_dcerpc_cn_pk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3933 * Only one PDU per transport packet, and only one transport
3936 pinfo->dcetransporttype=DCE_TRANSPORT_UNKNOWN;
3937 if (!dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE, NULL)) {
3939 * It wasn't a DCERPC PDU.
3951 * DCERPC dissector for connection oriented calls over byte-stream
3953 * we need to distinguish here between SMB and non-TCP (more in the future?)
3954 * to be able to know what kind of private_data structure to expect.
3957 dissect_dcerpc_cn_bs_body (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3959 volatile int offset = 0;
3961 volatile gboolean is_dcerpc_pdu;
3962 volatile gboolean ret = FALSE;
3965 * There may be multiple PDUs per transport packet; keep
3968 while (tvb_reported_length_remaining(tvb, offset) != 0) {
3970 * Catch ReportedBoundsError, so that even if the stub data is bad,
3971 * we don't abort the full DCE RPC dissection - there might be more
3972 * than one DCE RPC PDU in the data being dissected.
3974 * If we get BoundsError, it means the frame was cut short by a
3975 * snapshot length, so there's nothing more to dissect; just
3976 * re-throw that exception.
3978 is_dcerpc_pdu = FALSE;
3980 is_dcerpc_pdu = dissect_dcerpc_cn (tvb, offset, pinfo, tree,
3981 dcerpc_cn_desegment, &pdu_len);
3982 } CATCH(BoundsError) {
3984 } CATCH(ReportedBoundsError) {
3985 show_reported_bounds_error(tvb, pinfo, tree);
3988 if (!is_dcerpc_pdu) {
3996 * Well, we've seen at least one DCERPC PDU.
4002 * Desegmentation required - bail now.
4008 * Step to the next PDU.
4016 dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4018 pinfo->dcetransporttype=DCE_TRANSPORT_UNKNOWN;
4019 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
4023 dissect_dcerpc_cn_smbpipe (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4025 pinfo->dcetransporttype=DCE_CN_TRANSPORT_SMBPIPE;
4026 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
4032 dissect_dcerpc_dg_auth (tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
4033 e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
4035 proto_item *ti = NULL;
4036 proto_tree *auth_tree = NULL;
4037 guint8 protection_level;
4040 * Initially set "*auth_level_p" to -1 to indicate that we haven't
4041 * yet seen any authentication level information.
4043 if (auth_level_p != NULL)
4047 * The authentication information is at the *end* of the PDU; in
4048 * request and response PDUs, the request and response stub data
4051 * If the full packet is here, and there's data past the end of the
4052 * packet body, then dissect the auth info.
4054 offset += hdr->frag_len;
4055 if (tvb_length_remaining(tvb, offset) > 0) {
4056 switch (hdr->auth_proto) {
4058 case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
4059 ti = proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Kerberos authentication verifier");
4060 auth_tree = proto_item_add_subtree (ti, ett_dcerpc_krb5_auth_verf);
4061 protection_level = tvb_get_guint8 (tvb, offset);
4062 if (auth_level_p != NULL)
4063 *auth_level_p = protection_level;
4064 proto_tree_add_uint (auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
4066 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, FALSE);
4068 if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
4069 offset += 6; /* 6 bytes of padding */
4071 offset += 2; /* 6 bytes of padding */
4072 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, FALSE);
4077 proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Authentication verifier");
4084 dissect_dcerpc_dg_cancel_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
4085 proto_tree *dcerpc_tree,
4086 e_dce_dg_common_hdr_t *hdr)
4090 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4091 hdr->drep, hf_dcerpc_dg_cancel_vers,
4097 /* The only version we know about */
4098 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4099 hdr->drep, hf_dcerpc_dg_cancel_id,
4101 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
4102 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
4109 dissect_dcerpc_dg_cancel (tvbuff_t *tvb, int offset, packet_info *pinfo,
4110 proto_tree *dcerpc_tree,
4111 e_dce_dg_common_hdr_t *hdr)
4115 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4116 hdr->drep, hf_dcerpc_dg_cancel_vers,
4122 /* The only version we know about */
4123 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4124 hdr->drep, hf_dcerpc_dg_cancel_id,
4126 /* XXX - are NDR booleans 32 bits? */
4128 /* XXX - the RPC reference in chapter: "the cancel PDU" doesn't mention
4129 the accepting_cancels field (it's only in the cancel_ack PDU)! */
4130 /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4131 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
4138 dissect_dcerpc_dg_fack (tvbuff_t *tvb, int offset, packet_info *pinfo,
4139 proto_tree *dcerpc_tree,
4140 e_dce_dg_common_hdr_t *hdr)
4147 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
4148 hdr->drep, hf_dcerpc_dg_fack_vers,
4155 case 0: /* The only version documented in the DCE RPC 1.1 spec */
4156 case 1: /* This appears to be the same */
4157 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
4158 hdr->drep, hf_dcerpc_dg_fack_window_size,
4160 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4161 hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
4163 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4164 hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
4166 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
4167 hdr->drep, hf_dcerpc_dg_fack_serial_num,
4169 if (check_col (pinfo->cinfo, COL_INFO)) {
4170 col_append_fstr (pinfo->cinfo, COL_INFO, " serial: %u",
4173 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
4174 hdr->drep, hf_dcerpc_dg_fack_selack_len,
4176 for (i = 0; i < selack_len; i++) {
4177 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4178 hdr->drep, hf_dcerpc_dg_fack_selack,
4187 dissect_dcerpc_dg_reject_fault (tvbuff_t *tvb, int offset, packet_info *pinfo,
4188 proto_tree *dcerpc_tree,
4189 e_dce_dg_common_hdr_t *hdr)
4193 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4194 hdr->drep, hf_dcerpc_dg_status,
4197 if (check_col (pinfo->cinfo, COL_INFO)) {
4198 col_append_fstr (pinfo->cinfo, COL_INFO,
4200 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
4205 dissect_dcerpc_dg_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
4206 proto_tree *dcerpc_tree, proto_tree *tree,
4207 e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
4209 int length, reported_length, stub_length;
4210 gboolean save_fragmented;
4211 fragment_data *fd_head;
4215 if (check_col (pinfo->cinfo, COL_INFO))
4216 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u len: %u",
4217 di->call_data->opnum, hdr->frag_len );
4219 length = tvb_length_remaining (tvb, offset);
4220 reported_length = tvb_reported_length_remaining (tvb, offset);
4221 stub_length = hdr->frag_len;
4222 if (length > stub_length)
4223 length = stub_length;
4224 if (reported_length > stub_length)
4225 reported_length = stub_length;
4227 save_fragmented = pinfo->fragmented;
4229 /* If we don't have reassembly enabled, or this packet contains
4230 the entire PDU, or if this is a short frame (or a frame
4231 not reassembled at a lower layer) that doesn't include all
4232 the data in the fragment, just call the handoff directly if
4233 this is the first fragment or the PDU isn't fragmented. */
4234 if( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
4235 !tvb_bytes_exist(tvb, offset, stub_length) ){
4236 if(hdr->frag_num == 0) {
4239 /* First fragment, possibly the only fragment */
4242 * XXX - authentication info?
4244 pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
4245 next_tvb = tvb_new_subset (tvb, offset, length,
4247 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
4248 next_tvb, hdr->drep, di, NULL);
4250 /* PDU is fragmented and this isn't the first fragment */
4251 if (check_col(pinfo->cinfo, COL_INFO)) {
4252 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
4256 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
4257 "Fragment data (%d byte%s)",
4259 plurality(stub_length, "", "s"));
4264 /* Reassembly is enabled, the PDU is fragmented, and
4265 we have all the data in the fragment; the first two
4266 of those mean we should attempt reassembly, and the
4267 third means we can attempt reassembly. */
4270 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
4271 "Fragment data (%d byte%s)", stub_length,
4272 plurality(stub_length, "", "s"));
4276 fd_head = fragment_add_dcerpc(tvb, offset, pinfo,
4277 hdr->seqnum, &hdr->act_id, dcerpc_cl_reassemble_table,
4278 hdr->frag_num, stub_length,
4279 !(hdr->flags1 & PFCL1_LASTFRAG));
4280 if (fd_head != NULL) {
4281 /* We completed reassembly... */
4282 if(pinfo->fd->num==fd_head->reassembled_in) {
4283 /* ...and this is the reassembled RPC PDU */
4284 next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
4285 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
4286 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
4287 show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
4288 dcerpc_tree, pinfo, next_tvb);
4291 * XXX - authentication info?
4293 pinfo->fragmented = FALSE;
4294 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
4295 next_tvb, hdr->drep, di, NULL);
4297 /* ...and this isn't the reassembled RPC PDU */
4298 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
4299 tvb, 0, 0, fd_head->reassembled_in);
4300 PROTO_ITEM_SET_GENERATED(pi);
4301 if (check_col(pinfo->cinfo, COL_INFO)) {
4302 col_append_fstr(pinfo->cinfo, COL_INFO,
4303 " [DCE/RPC fragment, reas: #%u]", fd_head->reassembled_in);
4307 /* Reassembly isn't completed yet */
4308 if (check_col(pinfo->cinfo, COL_INFO)) {
4309 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
4313 pinfo->fragmented = save_fragmented;
4317 dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo,
4318 proto_tree *dcerpc_tree, proto_tree *tree,
4319 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4322 dcerpc_call_value *value, v;
4323 dcerpc_matched_key matched_key, *new_matched_key;
4327 if(!(pinfo->fd->flags.visited)){
4328 dcerpc_call_value *call_value;
4329 dcerpc_dg_call_key *call_key;
4331 call_key=g_mem_chunk_alloc (dcerpc_dg_call_key_chunk);
4332 call_key->conv=conv;
4333 call_key->seqnum=hdr->seqnum;
4334 call_key->act_id=hdr->act_id;
4336 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
4337 call_value->uuid = hdr->if_id;
4338 call_value->ver = hdr->if_ver;
4339 call_value->opnum = hdr->opnum;
4340 call_value->req_frame=pinfo->fd->num;
4341 call_value->req_time.secs=pinfo->fd->abs_secs;
4342 call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000;
4343 call_value->rep_frame=0;
4344 call_value->max_ptr=0;
4345 call_value->private_data = NULL;
4346 g_hash_table_insert (dcerpc_dg_calls, call_key, call_value);
4348 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
4349 new_matched_key->frame = pinfo->fd->num;
4350 new_matched_key->call_id = hdr->seqnum;
4351 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
4354 matched_key.frame = pinfo->fd->num;
4355 matched_key.call_id = hdr->seqnum;
4356 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
4358 v.uuid = hdr->if_id;
4359 v.ver = hdr->if_ver;
4360 v.opnum = hdr->opnum;
4361 v.req_frame = pinfo->fd->num;
4364 v.private_data=NULL;
4369 di->call_id = hdr->seqnum;
4371 di->ptype = PDU_REQ;
4372 di->call_data = value;
4374 if(value->rep_frame!=0){
4375 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
4376 tvb, 0, 0, value->rep_frame);
4377 PROTO_ITEM_SET_GENERATED(pi);
4379 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
4383 dissect_dcerpc_dg_resp (tvbuff_t *tvb, int offset, packet_info *pinfo,
4384 proto_tree *dcerpc_tree, proto_tree *tree,
4385 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4388 dcerpc_call_value *value, v;
4389 dcerpc_matched_key matched_key, *new_matched_key;
4393 if(!(pinfo->fd->flags.visited)){
4394 dcerpc_call_value *call_value;
4395 dcerpc_dg_call_key call_key;
4398 call_key.seqnum=hdr->seqnum;
4399 call_key.act_id=hdr->act_id;
4401 if((call_value=g_hash_table_lookup(dcerpc_dg_calls, &call_key))){
4402 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
4403 new_matched_key->frame = pinfo->fd->num;
4404 new_matched_key->call_id = hdr->seqnum;
4405 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
4406 if(call_value->rep_frame==0){
4407 call_value->rep_frame=pinfo->fd->num;
4412 matched_key.frame = pinfo->fd->num;
4413 matched_key.call_id = hdr->seqnum;
4414 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
4416 v.uuid = hdr->if_id;
4417 v.ver = hdr->if_ver;
4418 v.opnum = hdr->opnum;
4420 v.rep_frame=pinfo->fd->num;
4421 v.private_data=NULL;
4428 di->ptype = PDU_RESP;
4429 di->call_data = value;
4431 if(value->req_frame!=0){
4433 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4434 tvb, 0, 0, value->req_frame);
4435 PROTO_ITEM_SET_GENERATED(pi);
4436 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
4437 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
4439 ns.nsecs+=1000000000;
4442 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
4443 PROTO_ITEM_SET_GENERATED(pi);
4445 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
4449 * DCERPC dissector for connectionless calls
4452 dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4454 proto_item *ti = NULL;
4455 proto_item *tf = NULL;
4456 proto_tree *dcerpc_tree = NULL;
4457 proto_tree *dg_flags1_tree = NULL;
4458 proto_tree *dg_flags2_tree = NULL;
4459 proto_tree *drep_tree = NULL;
4460 e_dce_dg_common_hdr_t hdr;
4462 conversation_t *conv;
4464 char uuid_str[DCERPC_UUID_STR_LEN];
4468 * Check if this looks like a CL DCERPC call. All dg packets
4469 * have an 80 byte header on them. Which starts with
4470 * version (4), pkt_type.
4472 if (!tvb_bytes_exist (tvb, 0, sizeof (hdr))) {
4475 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
4476 if (hdr.rpc_ver != 4)
4478 hdr.ptype = tvb_get_guint8 (tvb, offset++);
4482 if (check_col (pinfo->cinfo, COL_PROTOCOL))
4483 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
4484 if (check_col (pinfo->cinfo, COL_INFO))
4485 col_add_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
4487 hdr.flags1 = tvb_get_guint8 (tvb, offset++);
4488 hdr.flags2 = tvb_get_guint8 (tvb, offset++);
4489 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
4490 offset += sizeof (hdr.drep);
4491 hdr.serial_hi = tvb_get_guint8 (tvb, offset++);
4492 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.obj_id);
4494 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.if_id);
4496 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.act_id);
4498 hdr.server_boot = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4500 hdr.if_ver = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4502 hdr.seqnum = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4504 hdr.opnum = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4506 hdr.ihint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4508 hdr.ahint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4510 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4512 hdr.frag_num = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4514 hdr.auth_proto = tvb_get_guint8 (tvb, offset++);
4515 hdr.serial_lo = tvb_get_guint8 (tvb, offset++);
4518 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, -1, FALSE);
4520 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
4526 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
4530 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
4534 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
4535 dg_flags1_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags1);
4536 if (dg_flags1_tree) {
4537 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
4538 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
4539 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
4540 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
4541 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
4542 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
4543 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
4544 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
4550 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
4551 dg_flags2_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags2);
4552 if (dg_flags2_tree) {
4553 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
4554 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
4555 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
4556 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
4557 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
4558 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
4559 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
4560 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
4566 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
4567 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
4569 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
4570 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
4571 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
4574 offset += sizeof (hdr.drep);
4577 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
4581 /* XXX - use "dissect_ndr_uuid_t()"? */
4582 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
4583 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
4584 hdr.obj_id.Data1, hdr.obj_id.Data2, hdr.obj_id.Data3,
4585 hdr.obj_id.Data4[0],
4586 hdr.obj_id.Data4[1],
4587 hdr.obj_id.Data4[2],
4588 hdr.obj_id.Data4[3],
4589 hdr.obj_id.Data4[4],
4590 hdr.obj_id.Data4[5],
4591 hdr.obj_id.Data4[6],
4592 hdr.obj_id.Data4[7]);
4593 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
4594 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
4595 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
4596 offset, 16, uuid_str, "Object UUID: %s", uuid_str);
4601 /* XXX - use "dissect_ndr_uuid_t()"? */
4602 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
4603 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
4604 hdr.if_id.Data1, hdr.if_id.Data2, hdr.if_id.Data3,
4612 hdr.if_id.Data4[7]);
4613 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
4614 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
4615 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
4616 offset, 16, uuid_str, "Interface: %s", uuid_str);
4621 /* XXX - use "dissect_ndr_uuid_t()"? */
4622 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
4623 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
4624 hdr.act_id.Data1, hdr.act_id.Data2, hdr.act_id.Data3,
4625 hdr.act_id.Data4[0],
4626 hdr.act_id.Data4[1],
4627 hdr.act_id.Data4[2],
4628 hdr.act_id.Data4[3],
4629 hdr.act_id.Data4[4],
4630 hdr.act_id.Data4[5],
4631 hdr.act_id.Data4[6],
4632 hdr.act_id.Data4[7]);
4633 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
4634 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
4635 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
4636 offset, 16, uuid_str, "Activity: %s", uuid_str);
4641 nstime_t server_boot;
4643 server_boot.secs = hdr.server_boot;
4644 server_boot.nsecs = 0;
4646 if (hdr.server_boot == 0)
4647 proto_tree_add_time_format (dcerpc_tree, hf_dcerpc_dg_server_boot,
4648 tvb, offset, 4, &server_boot,
4649 "Server boot time: Unknown (0)");
4651 proto_tree_add_time (dcerpc_tree, hf_dcerpc_dg_server_boot,
4652 tvb, offset, 4, &server_boot);
4657 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
4661 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
4662 if (check_col (pinfo->cinfo, COL_INFO)) {
4663 col_append_fstr (pinfo->cinfo, COL_INFO, ": seq: %u", hdr.seqnum);
4668 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
4672 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
4676 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
4680 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
4684 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
4685 if (check_col (pinfo->cinfo, COL_INFO)) {
4686 if (hdr.flags1 & PFCL1_FRAG) {
4687 /* Fragmented - put the fragment number into the Info column */
4688 col_append_fstr (pinfo->cinfo, COL_INFO, " frag: %u",
4695 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
4699 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
4700 if (check_col (pinfo->cinfo, COL_INFO)) {
4701 if (hdr.flags1 & PFCL1_FRAG) {
4702 /* Fragmented - put the serial number into the Info column */
4703 col_append_fstr (pinfo->cinfo, COL_INFO, " serial: %u",
4704 (hdr.serial_hi << 8) | hdr.serial_lo);
4711 * XXX - for Kerberos, we get a protection level; if it's
4712 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
4715 dissect_dcerpc_dg_auth (tvb, offset, dcerpc_tree, &hdr,
4720 * keeping track of the conversation shouldn't really be necessary
4721 * for connectionless packets, because everything we need to know
4722 * to dissect is in the header for each packet. Unfortunately,
4723 * Microsoft's implementation is buggy and often puts the
4724 * completely wrong if_id in the header. go figure. So, keep
4725 * track of the seqnum and use that if possible. Note: that's not
4726 * completely correct. It should really be done based on both the
4727 * activity_id and seqnum. I haven't seen anywhere that it would
4728 * make a difference, but for future reference...
4730 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
4731 pinfo->srcport, pinfo->destport, 0);
4733 conv = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
4734 pinfo->srcport, pinfo->destport, 0);
4738 * Packet type specific stuff is next.
4741 switch (hdr.ptype) {
4743 case PDU_CANCEL_ACK:
4744 /* Body is optional */
4745 /* XXX - we assume "frag_len" is the length of the body */
4746 if (hdr.frag_len != 0)
4747 dissect_dcerpc_dg_cancel_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
4752 * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
4753 * but in at least one capture none of the Cl_cancel PDUs had a
4756 /* XXX - we assume "frag_len" is the length of the body */
4757 if (hdr.frag_len != 0)
4758 dissect_dcerpc_dg_cancel (tvb, offset, pinfo, dcerpc_tree, &hdr);
4762 /* Body is optional; if present, it's the same as PDU_FACK */
4763 /* XXX - we assume "frag_len" is the length of the body */
4764 if (hdr.frag_len != 0)
4765 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
4769 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
4774 dissect_dcerpc_dg_reject_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
4778 dissect_dcerpc_dg_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
4782 dissect_dcerpc_dg_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
4785 /* these requests have no body */
4797 dcerpc_init_protocol (void)
4799 /* structures and data for BIND */
4801 g_hash_table_destroy (dcerpc_binds);
4805 dcerpc_binds = g_hash_table_new (dcerpc_bind_hash, dcerpc_bind_equal);
4808 if (dcerpc_bind_key_chunk){
4809 g_mem_chunk_destroy (dcerpc_bind_key_chunk);
4811 dcerpc_bind_key_chunk = g_mem_chunk_new ("dcerpc_bind_key_chunk",
4812 sizeof (dcerpc_bind_key),
4813 200 * sizeof (dcerpc_bind_key),
4815 if (dcerpc_bind_value_chunk){
4816 g_mem_chunk_destroy (dcerpc_bind_value_chunk);
4818 dcerpc_bind_value_chunk = g_mem_chunk_new ("dcerpc_bind_value_chunk",
4819 sizeof (dcerpc_bind_value),
4820 200 * sizeof (dcerpc_bind_value),
4822 /* structures and data for CALL */
4823 if (dcerpc_cn_calls){
4824 g_hash_table_destroy (dcerpc_cn_calls);
4826 dcerpc_cn_calls = g_hash_table_new (dcerpc_cn_call_hash, dcerpc_cn_call_equal);
4827 if (dcerpc_dg_calls){
4828 g_hash_table_destroy (dcerpc_dg_calls);
4830 dcerpc_dg_calls = g_hash_table_new (dcerpc_dg_call_hash, dcerpc_dg_call_equal);
4831 if (dcerpc_cn_call_key_chunk){
4832 g_mem_chunk_destroy (dcerpc_cn_call_key_chunk);
4834 dcerpc_cn_call_key_chunk = g_mem_chunk_new ("dcerpc_cn_call_key_chunk",
4835 sizeof (dcerpc_cn_call_key),
4836 200 * sizeof (dcerpc_cn_call_key),
4838 if (dcerpc_dg_call_key_chunk){
4839 g_mem_chunk_destroy (dcerpc_dg_call_key_chunk);
4841 dcerpc_dg_call_key_chunk = g_mem_chunk_new ("dcerpc_dg_call_key_chunk",
4842 sizeof (dcerpc_dg_call_key),
4843 200 * sizeof (dcerpc_dg_call_key),
4846 if (dcerpc_call_value_chunk){
4847 g_mem_chunk_destroy (dcerpc_call_value_chunk);
4849 dcerpc_call_value_chunk = g_mem_chunk_new ("dcerpc_call_value_chunk",
4850 sizeof (dcerpc_call_value),
4851 200 * sizeof (dcerpc_call_value),
4854 /* structure and data for MATCHED */
4855 if (dcerpc_matched){
4856 g_hash_table_destroy (dcerpc_matched);
4858 dcerpc_matched = g_hash_table_new (dcerpc_matched_hash, dcerpc_matched_equal);
4859 if (dcerpc_matched_key_chunk){
4860 g_mem_chunk_destroy (dcerpc_matched_key_chunk);
4862 dcerpc_matched_key_chunk = g_mem_chunk_new ("dcerpc_matched_key_chunk",
4863 sizeof (dcerpc_matched_key),
4864 200 * sizeof (dcerpc_matched_key),
4867 /* call the registered hooks */
4868 g_hook_list_invoke(&dcerpc_hooks_init_protos, FALSE /* not may_recurse */);
4872 proto_register_dcerpc (void)
4874 static hf_register_info hf[] = {
4875 { &hf_dcerpc_request_in,
4876 { "Request in frame", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE,
4877 NULL, 0, "This packet is a response to the packet with this number", HFILL }},
4878 { &hf_dcerpc_response_in,
4879 { "Response in frame", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
4880 NULL, 0, "This packet will be responded in the packet with this number", HFILL }},
4881 { &hf_dcerpc_referent_id,
4882 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
4883 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
4885 { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4886 { &hf_dcerpc_ver_minor,
4887 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4888 { &hf_dcerpc_packet_type,
4889 { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS (pckt_vals), 0x0, "", HFILL }},
4890 { &hf_dcerpc_cn_flags,
4891 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4892 { &hf_dcerpc_cn_flags_first_frag,
4893 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_FIRST_FRAG, "", HFILL }},
4894 { &hf_dcerpc_cn_flags_last_frag,
4895 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_LAST_FRAG, "", HFILL }},
4896 { &hf_dcerpc_cn_flags_cancel_pending,
4897 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_PENDING_CANCEL, "", HFILL }},
4898 { &hf_dcerpc_cn_flags_reserved,
4899 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_RESERVED_1, "", HFILL }},
4900 { &hf_dcerpc_cn_flags_mpx,
4901 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_CONC_MPX, "", HFILL }},
4902 { &hf_dcerpc_cn_flags_dne,
4903 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_DID_NOT_EXECUTE, "", HFILL }},
4904 { &hf_dcerpc_cn_flags_maybe,
4905 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_MAYBE, "", HFILL }},
4906 { &hf_dcerpc_cn_flags_object,
4907 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_OBJECT_UUID, "", HFILL }},
4909 { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
4910 { &hf_dcerpc_drep_byteorder,
4911 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS (drep_byteorder_vals), 0x0, "", HFILL }},
4912 { &hf_dcerpc_drep_character,
4913 { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS (drep_character_vals), 0x0, "", HFILL }},
4914 { &hf_dcerpc_drep_fp,
4915 { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS (drep_fp_vals), 0x0, "", HFILL }},
4916 { &hf_dcerpc_cn_frag_len,
4917 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4918 { &hf_dcerpc_cn_auth_len,
4919 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4920 { &hf_dcerpc_cn_call_id,
4921 { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4922 { &hf_dcerpc_cn_max_xmit,
4923 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4924 { &hf_dcerpc_cn_max_recv,
4925 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4926 { &hf_dcerpc_cn_assoc_group,
4927 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
4928 { &hf_dcerpc_cn_num_ctx_items,
4929 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4930 { &hf_dcerpc_cn_ctx_id,
4931 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4932 { &hf_dcerpc_cn_num_trans_items,
4933 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4934 { &hf_dcerpc_cn_bind_if_id,
4935 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4936 { &hf_dcerpc_cn_bind_if_ver,
4937 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4938 { &hf_dcerpc_cn_bind_if_ver_minor,
4939 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4940 { &hf_dcerpc_cn_bind_trans_id,
4941 { "Transfer Syntax", "dcerpc.cn_bind_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4942 { &hf_dcerpc_cn_bind_trans_ver,
4943 { "Syntax ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4944 { &hf_dcerpc_cn_alloc_hint,
4945 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4946 { &hf_dcerpc_cn_sec_addr_len,
4947 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4948 { &hf_dcerpc_cn_sec_addr,
4949 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, "", HFILL }},
4950 { &hf_dcerpc_cn_num_results,
4951 { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4952 { &hf_dcerpc_cn_ack_result,
4953 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, "", HFILL }},
4954 { &hf_dcerpc_cn_ack_reason,
4955 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, "", HFILL }},
4956 { &hf_dcerpc_cn_ack_trans_id,
4957 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4958 { &hf_dcerpc_cn_ack_trans_ver,
4959 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4960 { &hf_dcerpc_cn_reject_reason,
4961 { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, "", HFILL }},
4962 { &hf_dcerpc_cn_num_protocols,
4963 { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4964 { &hf_dcerpc_cn_protocol_ver_major,
4965 { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4966 { &hf_dcerpc_cn_protocol_ver_minor,
4967 { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4968 { &hf_dcerpc_cn_cancel_count,
4969 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4970 { &hf_dcerpc_cn_status,
4971 { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
4972 { &hf_dcerpc_auth_type,
4973 { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
4974 { &hf_dcerpc_auth_level,
4975 { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS (authn_level_vals), 0x0, "", HFILL }},
4976 { &hf_dcerpc_auth_pad_len,
4977 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4978 { &hf_dcerpc_auth_rsrvd,
4979 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4980 { &hf_dcerpc_auth_ctx_id,
4981 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4982 { &hf_dcerpc_dg_flags1,
4983 { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4984 { &hf_dcerpc_dg_flags1_rsrvd_01,
4985 { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_01, "", HFILL }},
4986 { &hf_dcerpc_dg_flags1_last_frag,
4987 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_LASTFRAG, "", HFILL }},
4988 { &hf_dcerpc_dg_flags1_frag,
4989 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_FRAG, "", HFILL }},
4990 { &hf_dcerpc_dg_flags1_nofack,
4991 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_NOFACK, "", HFILL }},
4992 { &hf_dcerpc_dg_flags1_maybe,
4993 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_MAYBE, "", HFILL }},
4994 { &hf_dcerpc_dg_flags1_idempotent,
4995 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_IDEMPOTENT, "", HFILL }},
4996 { &hf_dcerpc_dg_flags1_broadcast,
4997 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_BROADCAST, "", HFILL }},
4998 { &hf_dcerpc_dg_flags1_rsrvd_80,
4999 { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_80, "", HFILL }},
5000 { &hf_dcerpc_dg_flags2,
5001 { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
5002 { &hf_dcerpc_dg_flags2_rsrvd_01,
5003 { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_01, "", HFILL }},
5004 { &hf_dcerpc_dg_flags2_cancel_pending,
5005 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_CANCEL_PENDING, "", HFILL }},
5006 { &hf_dcerpc_dg_flags2_rsrvd_04,
5007 { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_04, "", HFILL }},
5008 { &hf_dcerpc_dg_flags2_rsrvd_08,
5009 { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_08, "", HFILL }},
5010 { &hf_dcerpc_dg_flags2_rsrvd_10,
5011 { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_10, "", HFILL }},
5012 { &hf_dcerpc_dg_flags2_rsrvd_20,
5013 { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_20, "", HFILL }},
5014 { &hf_dcerpc_dg_flags2_rsrvd_40,
5015 { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_40, "", HFILL }},
5016 { &hf_dcerpc_dg_flags2_rsrvd_80,
5017 { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_80, "", HFILL }},
5018 { &hf_dcerpc_dg_serial_lo,
5019 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
5020 { &hf_dcerpc_dg_serial_hi,
5021 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
5022 { &hf_dcerpc_dg_ahint,
5023 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
5024 { &hf_dcerpc_dg_ihint,
5025 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
5026 { &hf_dcerpc_dg_frag_len,
5027 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5028 { &hf_dcerpc_dg_frag_num,
5029 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5030 { &hf_dcerpc_dg_auth_proto,
5031 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
5032 { &hf_dcerpc_dg_seqnum,
5033 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5034 { &hf_dcerpc_dg_server_boot,
5035 { "Server boot time", "dcerpc.dg_server_boot", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0, "", HFILL }},
5036 { &hf_dcerpc_dg_if_ver,
5037 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5038 { &hf_dcerpc_krb5_av_prot_level,
5039 { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, "", HFILL }},
5040 { &hf_dcerpc_krb5_av_key_vers_num,
5041 { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5042 { &hf_dcerpc_krb5_av_key_auth_verifier,
5043 { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
5044 { &hf_dcerpc_obj_id,
5045 { "Object", "dcerpc.obj_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
5046 { &hf_dcerpc_dg_if_id,
5047 { "Interface", "dcerpc.dg_if_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
5048 { &hf_dcerpc_dg_act_id,
5049 { "Activity", "dcerpc.dg_act_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
5051 { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5053 { &hf_dcerpc_dg_cancel_vers,
5054 { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5056 { &hf_dcerpc_dg_cancel_id,
5057 { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5059 { &hf_dcerpc_dg_server_accepting_cancels,
5060 { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
5062 { &hf_dcerpc_dg_fack_vers,
5063 { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5065 { &hf_dcerpc_dg_fack_window_size,
5066 { "Window Size", "dcerpc.fack_window_size", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5068 { &hf_dcerpc_dg_fack_max_tsdu,
5069 { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5071 { &hf_dcerpc_dg_fack_max_frag_size,
5072 { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5074 { &hf_dcerpc_dg_fack_serial_num,
5075 { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5077 { &hf_dcerpc_dg_fack_selack_len,
5078 { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5080 { &hf_dcerpc_dg_fack_selack,
5081 { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
5083 { &hf_dcerpc_dg_status,
5084 { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
5086 { &hf_dcerpc_array_max_count,
5087 { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
5089 { &hf_dcerpc_array_offset,
5090 { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
5092 { &hf_dcerpc_array_actual_count,
5093 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
5095 { &hf_dcerpc_array_buffer,
5096 { "Buffer", "dcerpc.array.buffer", FT_BYTES, BASE_NONE, NULL, 0x0, "Buffer: Buffer containing elements of the array", HFILL }},
5099 { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5101 { &hf_dcerpc_fragments,
5102 { "DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
5103 NULL, 0x0, "DCE/RPC Fragments", HFILL }},
5105 { &hf_dcerpc_fragment,
5106 { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM, BASE_NONE,
5107 NULL, 0x0, "DCE/RPC Fragment", HFILL }},
5109 { &hf_dcerpc_fragment_overlap,
5110 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE,
5111 NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
5113 { &hf_dcerpc_fragment_overlap_conflict,
5114 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE,
5115 NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
5117 { &hf_dcerpc_fragment_multiple_tails,
5118 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE,
5119 NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
5121 { &hf_dcerpc_fragment_too_long_fragment,
5122 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE,
5123 NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
5125 { &hf_dcerpc_fragment_error,
5126 { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE,
5127 NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
5130 { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE,
5131 NULL, 0, "Time between Request and Response for DCE-RPC calls", HFILL }},
5133 { &hf_dcerpc_reassembled_in,
5134 { "Reassembled PDU in frame", "dcerpc.reassembled_in", FT_FRAMENUM, BASE_NONE,
5135 NULL, 0x0, "The DCE/RPC PDU is completely reassembled in the packet with this number", HFILL }},
5137 { &hf_dcerpc_unknown_if_id,
5138 { "Unknown DCERPC interface id", "dcerpc.unknown_if_id", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
5140 static gint *ett[] = {
5142 &ett_dcerpc_cn_flags,
5144 &ett_dcerpc_cn_iface,
5146 &ett_dcerpc_dg_flags1,
5147 &ett_dcerpc_dg_flags2,
5148 &ett_dcerpc_pointer_data,
5150 &ett_dcerpc_fragments,
5151 &ett_dcerpc_fragment,
5152 &ett_dcerpc_krb5_auth_verf,
5154 module_t *dcerpc_module;
5156 proto_dcerpc = proto_register_protocol ("DCE RPC", "DCERPC", "dcerpc");
5157 proto_register_field_array (proto_dcerpc, hf, array_length (hf));
5158 proto_register_subtree_array (ett, array_length (ett));
5159 register_init_routine (dcerpc_init_protocol);
5160 dcerpc_module = prefs_register_protocol (proto_dcerpc, NULL);
5161 prefs_register_bool_preference (dcerpc_module,
5163 "Reassemble DCE/RPC messages spanning multiple TCP segments",
5164 "Whether the DCE/RPC dissector should reassemble messages spanning multiple TCP segments."
5165 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
5166 &dcerpc_cn_desegment);
5167 prefs_register_bool_preference (dcerpc_module,
5168 "reassemble_dcerpc",
5169 "Reassemble DCE/RPC fragments",
5170 "Whether the DCE/RPC dissector should reassemble fragmented DCE/RPC PDUs",
5171 &dcerpc_reassemble);
5172 register_init_routine(dcerpc_reassemble_init);
5173 dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
5174 dcerpc_tap=register_tap("dcerpc");
5176 g_hook_list_init(&dcerpc_hooks_init_protos, sizeof(GHook));
5180 proto_reg_handoff_dcerpc (void)
5182 heur_dissector_add ("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
5183 heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
5184 heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
5185 heur_dissector_add ("smb_transact", dissect_dcerpc_cn_smbpipe, proto_dcerpc);
5186 heur_dissector_add ("http", dissect_dcerpc_cn_bs, proto_dcerpc);
5187 dcerpc_smb_init(proto_dcerpc);