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_cn_deseg_req = -1;
349 static int hf_dcerpc_auth_type = -1;
350 static int hf_dcerpc_auth_level = -1;
351 static int hf_dcerpc_auth_pad_len = -1;
352 static int hf_dcerpc_auth_rsrvd = -1;
353 static int hf_dcerpc_auth_ctx_id = -1;
354 static int hf_dcerpc_dg_flags1 = -1;
355 static int hf_dcerpc_dg_flags1_rsrvd_01 = -1;
356 static int hf_dcerpc_dg_flags1_last_frag = -1;
357 static int hf_dcerpc_dg_flags1_frag = -1;
358 static int hf_dcerpc_dg_flags1_nofack = -1;
359 static int hf_dcerpc_dg_flags1_maybe = -1;
360 static int hf_dcerpc_dg_flags1_idempotent = -1;
361 static int hf_dcerpc_dg_flags1_broadcast = -1;
362 static int hf_dcerpc_dg_flags1_rsrvd_80 = -1;
363 static int hf_dcerpc_dg_flags2 = -1;
364 static int hf_dcerpc_dg_flags2_rsrvd_01 = -1;
365 static int hf_dcerpc_dg_flags2_cancel_pending = -1;
366 static int hf_dcerpc_dg_flags2_rsrvd_04 = -1;
367 static int hf_dcerpc_dg_flags2_rsrvd_08 = -1;
368 static int hf_dcerpc_dg_flags2_rsrvd_10 = -1;
369 static int hf_dcerpc_dg_flags2_rsrvd_20 = -1;
370 static int hf_dcerpc_dg_flags2_rsrvd_40 = -1;
371 static int hf_dcerpc_dg_flags2_rsrvd_80 = -1;
372 static int hf_dcerpc_dg_serial_hi = -1;
373 static int hf_dcerpc_obj_id = -1;
374 static int hf_dcerpc_dg_if_id = -1;
375 static int hf_dcerpc_dg_act_id = -1;
376 static int hf_dcerpc_dg_serial_lo = -1;
377 static int hf_dcerpc_dg_ahint = -1;
378 static int hf_dcerpc_dg_ihint = -1;
379 static int hf_dcerpc_dg_frag_len = -1;
380 static int hf_dcerpc_dg_frag_num = -1;
381 static int hf_dcerpc_dg_auth_proto = -1;
382 static int hf_dcerpc_opnum = -1;
383 static int hf_dcerpc_dg_seqnum = -1;
384 static int hf_dcerpc_dg_server_boot = -1;
385 static int hf_dcerpc_dg_if_ver = -1;
386 static int hf_dcerpc_krb5_av_prot_level = -1;
387 static int hf_dcerpc_krb5_av_key_vers_num = -1;
388 static int hf_dcerpc_krb5_av_key_auth_verifier = -1;
389 static int hf_dcerpc_dg_cancel_vers = -1;
390 static int hf_dcerpc_dg_cancel_id = -1;
391 static int hf_dcerpc_dg_server_accepting_cancels = -1;
392 static int hf_dcerpc_dg_fack_vers = -1;
393 static int hf_dcerpc_dg_fack_window_size = -1;
394 static int hf_dcerpc_dg_fack_max_tsdu = -1;
395 static int hf_dcerpc_dg_fack_max_frag_size = -1;
396 static int hf_dcerpc_dg_fack_serial_num = -1;
397 static int hf_dcerpc_dg_fack_selack_len = -1;
398 static int hf_dcerpc_dg_fack_selack = -1;
399 static int hf_dcerpc_dg_status = -1;
400 static int hf_dcerpc_array_max_count = -1;
401 static int hf_dcerpc_array_offset = -1;
402 static int hf_dcerpc_array_actual_count = -1;
403 static int hf_dcerpc_array_buffer = -1;
404 static int hf_dcerpc_op = -1;
405 static int hf_dcerpc_referent_id = -1;
406 static int hf_dcerpc_fragments = -1;
407 static int hf_dcerpc_fragment = -1;
408 static int hf_dcerpc_fragment_overlap = -1;
409 static int hf_dcerpc_fragment_overlap_conflict = -1;
410 static int hf_dcerpc_fragment_multiple_tails = -1;
411 static int hf_dcerpc_fragment_too_long_fragment = -1;
412 static int hf_dcerpc_fragment_error = -1;
413 static int hf_dcerpc_reassembled_in = -1;
414 static int hf_dcerpc_unknown_if_id = -1;
416 static gint ett_dcerpc = -1;
417 static gint ett_dcerpc_cn_flags = -1;
418 static gint ett_dcerpc_cn_ctx = -1;
419 static gint ett_dcerpc_cn_iface = -1;
420 static gint ett_dcerpc_drep = -1;
421 static gint ett_dcerpc_dg_flags1 = -1;
422 static gint ett_dcerpc_dg_flags2 = -1;
423 static gint ett_dcerpc_pointer_data = -1;
424 static gint ett_dcerpc_string = -1;
425 static gint ett_dcerpc_fragments = -1;
426 static gint ett_dcerpc_fragment = -1;
427 static gint ett_dcerpc_krb5_auth_verf = -1;
429 static const fragment_items dcerpc_frag_items = {
430 &ett_dcerpc_fragments,
431 &ett_dcerpc_fragment,
433 &hf_dcerpc_fragments,
435 &hf_dcerpc_fragment_overlap,
436 &hf_dcerpc_fragment_overlap_conflict,
437 &hf_dcerpc_fragment_multiple_tails,
438 &hf_dcerpc_fragment_too_long_fragment,
439 &hf_dcerpc_fragment_error,
445 /* list of hooks to be called when init_protocols is done */
446 GHookList dcerpc_hooks_init_protos;
449 int ResolveWin32UUID(e_uuid_t if_id, char *UUID_NAME, int UUID_NAME_MAX_LEN)
451 char REG_UUID_NAME[MAX_PATH];
453 DWORD UUID_MAX_SIZE = MAX_PATH;
454 char REG_UUID_STR[MAX_PATH];
456 if(UUID_NAME_MAX_LEN < 2)
458 REG_UUID_NAME[0] = '\0';
459 snprintf(REG_UUID_STR, MAX_PATH, "SOFTWARE\\Classes\\Interface\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
460 if_id.Data1, if_id.Data2, if_id.Data3,
461 if_id.Data4[0], if_id.Data4[1],
462 if_id.Data4[2], if_id.Data4[3],
463 if_id.Data4[4], if_id.Data4[5],
464 if_id.Data4[6], if_id.Data4[7]);
465 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCSTR)REG_UUID_STR, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
467 if (RegQueryValueEx(hKey, NULL, NULL, NULL, (LPBYTE)REG_UUID_NAME, &UUID_MAX_SIZE) == ERROR_SUCCESS && UUID_MAX_SIZE <= MAX_PATH)
469 snprintf(UUID_NAME, UUID_NAME_MAX_LEN, "%s", REG_UUID_NAME);
471 return strlen(REG_UUID_NAME);
475 return 0; /* we didn't find anything anyhow. Please don't use the string! */
483 static dcerpc_info di[20];
484 static int di_counter=0;
490 return &di[di_counter];
493 /* try to desegment big DCE/RPC packets over TCP? */
494 static gboolean dcerpc_cn_desegment = TRUE;
496 /* reassemble DCE/RPC fragments */
497 /* reassembly of dcerpc fragments will not work for the case where ONE frame
498 might contain multiple dcerpc fragments for different PDUs.
499 this case would be so unusual/weird so if you got captures like that:
502 static gboolean dcerpc_reassemble = FALSE;
503 static GHashTable *dcerpc_co_reassemble_table = NULL;
504 static GHashTable *dcerpc_cl_reassemble_table = NULL;
507 dcerpc_reassemble_init(void)
509 fragment_table_init(&dcerpc_co_reassemble_table);
510 dcerpc_fragment_table_init(&dcerpc_cl_reassemble_table);
514 * Authentication subdissectors. Used to dissect authentication blobs in
515 * DCERPC binds, requests and responses.
518 typedef struct _dcerpc_auth_subdissector {
521 dcerpc_auth_subdissector_fns auth_fns;
522 } dcerpc_auth_subdissector;
524 static GSList *dcerpc_auth_subdissector_list;
526 static dcerpc_auth_subdissector_fns *get_auth_subdissector_fns(
527 guint8 auth_level, guint8 auth_type)
532 for (i = 0; (data = g_slist_nth_data(dcerpc_auth_subdissector_list, i)); i++) {
533 dcerpc_auth_subdissector *asd = (dcerpc_auth_subdissector *)data;
535 if (asd->auth_level == auth_level &&
536 asd->auth_type == auth_type)
537 return &asd->auth_fns;
543 void register_dcerpc_auth_subdissector(guint8 auth_level, guint8 auth_type,
544 dcerpc_auth_subdissector_fns *fns)
546 dcerpc_auth_subdissector *d;
548 if (get_auth_subdissector_fns(auth_level, auth_type))
551 d = (dcerpc_auth_subdissector *)g_malloc(sizeof(dcerpc_auth_subdissector));
553 d->auth_level = auth_level;
554 d->auth_type = auth_type;
555 memcpy(&d->auth_fns, fns, sizeof(dcerpc_auth_subdissector_fns));
557 dcerpc_auth_subdissector_list = g_slist_append(dcerpc_auth_subdissector_list, d);
560 /* Hand off verifier data to a registered dissector */
562 static void dissect_auth_verf(tvbuff_t *auth_tvb, packet_info *pinfo,
564 dcerpc_auth_subdissector_fns *auth_fns,
565 e_dce_cn_common_hdr_t *hdr,
566 dcerpc_auth_info *auth_info)
568 dcerpc_dissect_fnct_t *volatile fn = NULL;
570 switch (hdr->ptype) {
573 fn = auth_fns->bind_fn;
577 fn = auth_fns->bind_ack_fn;
580 fn = auth_fns->auth3_fn;
583 fn = auth_fns->req_verf_fn;
586 fn = auth_fns->resp_verf_fn;
589 /* Don't know how to handle authentication data in this
593 g_warning("attempt to dissect %s pdu authentication data",
594 val_to_str(hdr->ptype, pckt_vals, "Unknown (%u)"));
599 fn(auth_tvb, 0, pinfo, tree, hdr->drep);
601 tvb_ensure_bytes_exist(auth_tvb, 0, hdr->auth_len);
602 proto_tree_add_text(tree, auth_tvb, 0, hdr->auth_len,
604 val_to_str(auth_info->auth_type,
610 /* Hand off payload data to a registered dissector */
612 static tvbuff_t *decode_encrypted_data(tvbuff_t *data_tvb,
615 dcerpc_auth_subdissector_fns *auth_fns,
617 dcerpc_auth_info *auth_info)
619 dcerpc_decode_data_fnct_t *fn;
622 fn = auth_fns->req_data_fn;
624 fn = auth_fns->resp_data_fn;
627 return fn(data_tvb, auth_tvb, 0, pinfo, auth_info);
636 /* the registered subdissectors */
637 GHashTable *dcerpc_uuids=NULL;
640 dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2)
642 const dcerpc_uuid_key *key1 = (const dcerpc_uuid_key *)k1;
643 const dcerpc_uuid_key *key2 = (const dcerpc_uuid_key *)k2;
644 return ((memcmp (&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
645 && (key1->ver == key2->ver));
649 dcerpc_uuid_hash (gconstpointer k)
651 const dcerpc_uuid_key *key = (const dcerpc_uuid_key *)k;
652 /* This isn't perfect, but the Data1 part of these is almost always
654 return key->uuid.Data1;
658 dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver,
659 dcerpc_sub_dissector *procs, int opnum_hf)
661 dcerpc_uuid_key *key = g_malloc (sizeof (*key));
662 dcerpc_uuid_value *value = g_malloc (sizeof (*value));
663 header_field_info *hf_info;
668 value->proto = find_protocol_by_id(proto);
669 value->proto_id = proto;
671 value->name = proto_get_protocol_short_name (value->proto);
672 value->procs = procs;
673 value->opnum_hf = opnum_hf;
675 g_hash_table_insert (dcerpc_uuids, key, value);
677 hf_info = proto_registrar_get_nth(opnum_hf);
678 hf_info->strings = value_string_from_subdissectors(procs);
682 /* try to get registered name for this uuid */
683 const gchar *dcerpc_get_uuid_name(e_uuid_t *uuid, guint16 ver)
686 dcerpc_uuid_value *sub_proto;
689 /* try to get registered uuid "name" of if_id */
693 if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) != NULL
694 && proto_is_protocol_enabled(sub_proto->proto)) {
696 return sub_proto->name;
703 /* Function to find the name of a registered protocol
704 * or NULL if the protocol/version is not known to ethereal.
707 dcerpc_get_proto_name(e_uuid_t *uuid, guint16 ver)
710 dcerpc_uuid_value *sub_proto;
714 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
717 return sub_proto->name;
720 /* Function to find the opnum hf-field of a registered protocol
721 * or -1 if the protocol/version is not known to ethereal.
724 dcerpc_get_proto_hf_opnum(e_uuid_t *uuid, guint16 ver)
727 dcerpc_uuid_value *sub_proto;
731 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
734 return sub_proto->opnum_hf;
737 /* Create a value_string consisting of DCERPC opnum and name from a
738 subdissector array. */
740 value_string *value_string_from_subdissectors(dcerpc_sub_dissector *sd)
742 value_string *vs = NULL;
746 for (i = 0; sd[i].name; i++) {
748 vs[i].value = sd[i].num;
749 vs[i].strptr = sd[i].name;
755 vs = g_malloc((num_sd + 1) * sizeof(value_string));
759 vs[num_sd].value = 0;
760 vs[num_sd].strptr = NULL;
765 /* Function to find the subdissector table of a registered protocol
766 * or NULL if the protocol/version is not known to ethereal.
768 dcerpc_sub_dissector *
769 dcerpc_get_proto_sub_dissector(e_uuid_t *uuid, guint16 ver)
772 dcerpc_uuid_value *sub_proto;
776 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
779 return sub_proto->procs;
784 * To keep track of ctx_id mappings.
786 * Everytime we see a bind call we update this table.
787 * Note that we always specify a SMB FID. For non-SMB transports this
790 static GHashTable *dcerpc_binds=NULL;
792 typedef struct _dcerpc_bind_key {
793 conversation_t *conv;
798 typedef struct _dcerpc_bind_value {
803 static GMemChunk *dcerpc_bind_key_chunk=NULL;
804 static GMemChunk *dcerpc_bind_value_chunk=NULL;
807 dcerpc_bind_equal (gconstpointer k1, gconstpointer k2)
809 const dcerpc_bind_key *key1 = (const dcerpc_bind_key *)k1;
810 const dcerpc_bind_key *key2 = (const dcerpc_bind_key *)k2;
811 return (key1->conv == key2->conv
812 && key1->ctx_id == key2->ctx_id
813 && key1->smb_fid == key2->smb_fid);
817 dcerpc_bind_hash (gconstpointer k)
819 const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
822 hash=GPOINTER_TO_UINT(key->conv) + key->ctx_id + key->smb_fid;
828 * To keep track of callid mappings. Should really use some generic
829 * conversation support instead.
831 static GHashTable *dcerpc_cn_calls=NULL;
832 static GHashTable *dcerpc_dg_calls=NULL;
834 typedef struct _dcerpc_cn_call_key {
835 conversation_t *conv;
838 } dcerpc_cn_call_key;
840 typedef struct _dcerpc_dg_call_key {
841 conversation_t *conv;
844 } dcerpc_dg_call_key;
846 static GMemChunk *dcerpc_cn_call_key_chunk=NULL;
848 static GMemChunk *dcerpc_dg_call_key_chunk=NULL;
850 static GMemChunk *dcerpc_call_value_chunk=NULL;
854 dcerpc_cn_call_equal (gconstpointer k1, gconstpointer k2)
856 const dcerpc_cn_call_key *key1 = (const dcerpc_cn_call_key *)k1;
857 const dcerpc_cn_call_key *key2 = (const dcerpc_cn_call_key *)k2;
858 return (key1->conv == key2->conv
859 && key1->call_id == key2->call_id
860 && key1->smb_fid == key2->smb_fid);
864 dcerpc_dg_call_equal (gconstpointer k1, gconstpointer k2)
866 const dcerpc_dg_call_key *key1 = (const dcerpc_dg_call_key *)k1;
867 const dcerpc_dg_call_key *key2 = (const dcerpc_dg_call_key *)k2;
868 return (key1->conv == key2->conv
869 && key1->seqnum == key2->seqnum
870 && (memcmp (&key1->act_id, &key2->act_id, sizeof (e_uuid_t)) == 0));
874 dcerpc_cn_call_hash (gconstpointer k)
876 const dcerpc_cn_call_key *key = (const dcerpc_cn_call_key *)k;
877 return GPOINTER_TO_UINT(key->conv) + key->call_id + key->smb_fid;
881 dcerpc_dg_call_hash (gconstpointer k)
883 const dcerpc_dg_call_key *key = (const dcerpc_dg_call_key *)k;
884 return (GPOINTER_TO_UINT(key->conv) + key->seqnum + key->act_id.Data1
885 + (key->act_id.Data2 << 16) + key->act_id.Data3
886 + (key->act_id.Data4[0] << 24) + (key->act_id.Data4[1] << 16)
887 + (key->act_id.Data4[2] << 8) + (key->act_id.Data4[3] << 0)
888 + (key->act_id.Data4[4] << 24) + (key->act_id.Data4[5] << 16)
889 + (key->act_id.Data4[6] << 8) + (key->act_id.Data4[7] << 0));
892 /* to keep track of matched calls/responses
893 this one uses the same value struct as calls, but the key is the frame id
894 and call id; there can be more than one call in a frame.
896 XXX - why not just use the same keys as are used for calls?
899 static GHashTable *dcerpc_matched=NULL;
901 typedef struct _dcerpc_matched_key {
904 } dcerpc_matched_key;
906 static GMemChunk *dcerpc_matched_key_chunk=NULL;
909 dcerpc_matched_equal (gconstpointer k1, gconstpointer k2)
911 const dcerpc_matched_key *key1 = (const dcerpc_matched_key *)k1;
912 const dcerpc_matched_key *key2 = (const dcerpc_matched_key *)k2;
913 return (key1->frame == key2->frame
914 && key1->call_id == key2->call_id);
918 dcerpc_matched_hash (gconstpointer k)
920 const dcerpc_matched_key *key = (const dcerpc_matched_key *)k;
927 * Utility functions. Modeled after packet-rpc.c
931 dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
932 proto_tree *tree, guint8 *drep,
933 int hfindex, guint8 *pdata)
937 data = tvb_get_guint8 (tvb, offset);
939 proto_tree_add_item (tree, hfindex, tvb, offset, 1, (drep[0] & 0x10));
947 dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
948 proto_tree *tree, guint8 *drep,
949 int hfindex, guint16 *pdata)
953 data = ((drep[0] & 0x10)
954 ? tvb_get_letohs (tvb, offset)
955 : tvb_get_ntohs (tvb, offset));
958 proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10));
966 dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
967 proto_tree *tree, guint8 *drep,
968 int hfindex, guint32 *pdata)
972 data = ((drep[0] & 0x10)
973 ? tvb_get_letohl (tvb, offset)
974 : tvb_get_ntohl (tvb, offset));
977 proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10));
984 /* handles 32 bit unix time_t */
986 dissect_dcerpc_time_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
987 proto_tree *tree, guint8 *drep,
988 int hfindex, guint32 *pdata)
993 data = ((drep[0] & 0x10)
994 ? tvb_get_letohl (tvb, offset)
995 : tvb_get_ntohl (tvb, offset));
1000 if(data==0xffffffff){
1001 /* special case, no time specified */
1002 proto_tree_add_time_format(tree, hfindex, tvb, offset, 4, &tv, "%s: No time specified", proto_registrar_get_nth(hfindex)->name);
1004 proto_tree_add_time (tree, hfindex, tvb, offset, 4, &tv);
1014 dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1015 proto_tree *tree, guint8 *drep,
1016 int hfindex, guint64 *pdata)
1020 data = ((drep[0] & 0x10)
1021 ? tvb_get_letoh64 (tvb, offset)
1022 : tvb_get_ntoh64 (tvb, offset));
1025 proto_tree_add_item(tree, hfindex, tvb, offset, 8, (drep[0] & 0x10));
1034 dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1035 proto_tree *tree, guint8 *drep,
1036 int hfindex, gfloat *pdata)
1042 case(DCE_RPC_DREP_FP_IEEE):
1043 data = ((drep[0] & 0x10)
1044 ? tvb_get_letohieee_float(tvb, offset)
1045 : tvb_get_ntohieee_float(tvb, offset));
1047 proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
1050 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
1051 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1052 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
1054 /* ToBeDone: non IEEE floating formats */
1055 /* Set data to a negative infinity value */
1058 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep[1]);
1068 dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1069 proto_tree *tree, guint8 *drep,
1070 int hfindex, gdouble *pdata)
1076 case(DCE_RPC_DREP_FP_IEEE):
1077 data = ((drep[0] & 0x10)
1078 ? tvb_get_letohieee_double(tvb, offset)
1079 : tvb_get_ntohieee_double(tvb, offset));
1081 proto_tree_add_double(tree, hfindex, tvb, offset, 8, data);
1084 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
1085 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1086 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
1088 /* ToBeDone: non IEEE double formats */
1089 /* Set data to a negative infinity value */
1090 data = -G_MAXDOUBLE;
1092 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep[1]);
1102 dissect_dcerpc_uuid_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1103 proto_tree *tree, char *drep,
1104 int hfindex, e_uuid_t *pdata)
1107 header_field_info* hfi;
1113 dcerpc_tvb_get_uuid (tvb, offset, drep, &uuid);
1115 /* get name of protocol field to prepend it later */
1116 hfi = proto_registrar_get_nth(hfindex);
1119 /* XXX - get the name won't work correct, as we don't know the version of this uuid (if it has one) */
1120 /* look for a registered uuid name */
1121 uuid_name = dcerpc_get_uuid_name(&uuid, 0);
1124 /* we know the name of this uuid */
1125 proto_tree_add_string_format (tree, hfindex, tvb, offset, 16, "",
1126 "%s: %s (%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x)",
1127 hfi->name, uuid_name,
1128 uuid.Data1, uuid.Data2, uuid.Data3,
1129 uuid.Data4[0], uuid.Data4[1],
1130 uuid.Data4[2], uuid.Data4[3],
1131 uuid.Data4[4], uuid.Data4[5],
1132 uuid.Data4[6], uuid.Data4[7]);
1135 /* GUID have changed from FT_STRING to FT_GUID
1136 but we havent changed all dissectors yet.
1138 if(hfi->type==FT_GUID){
1139 proto_tree_add_item(tree, hfindex, tvb, offset, 16, (drep[0] & 0x10));
1141 /* we don't know the name of this uuid */
1142 proto_tree_add_string_format (tree, hfindex, tvb, offset, 16, "",
1143 "%s: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1145 uuid.Data1, uuid.Data2, uuid.Data3,
1146 uuid.Data4[0], uuid.Data4[1],
1147 uuid.Data4[2], uuid.Data4[3],
1148 uuid.Data4[4], uuid.Data4[5],
1149 uuid.Data4[6], uuid.Data4[7]);
1163 * a couple simpler things
1166 dcerpc_tvb_get_ntohs (tvbuff_t *tvb, gint offset, guint8 *drep)
1168 if (drep[0] & 0x10) {
1169 return tvb_get_letohs (tvb, offset);
1171 return tvb_get_ntohs (tvb, offset);
1176 dcerpc_tvb_get_ntohl (tvbuff_t *tvb, gint offset, guint8 *drep)
1178 if (drep[0] & 0x10) {
1179 return tvb_get_letohl (tvb, offset);
1181 return tvb_get_ntohl (tvb, offset);
1186 dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, guint8 *drep, e_uuid_t *uuid)
1189 uuid->Data1 = dcerpc_tvb_get_ntohl (tvb, offset, drep);
1190 uuid->Data2 = dcerpc_tvb_get_ntohs (tvb, offset+4, drep);
1191 uuid->Data3 = dcerpc_tvb_get_ntohs (tvb, offset+6, drep);
1193 for (i=0; i<sizeof (uuid->Data4); i++) {
1194 uuid->Data4[i] = tvb_get_guint8 (tvb, offset+8+i);
1201 /* function to dissect a unidimensional conformant array */
1203 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1204 proto_tree *tree, guint8 *drep,
1205 dcerpc_dissect_fnct_t *fnct)
1211 di=pinfo->private_data;
1212 if(di->conformant_run){
1213 /* conformant run, just dissect the max_count header */
1215 di->conformant_run=0;
1216 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1217 hf_dcerpc_array_max_count, &di->array_max_count);
1218 di->array_max_count_offset=offset-4;
1219 di->conformant_run=1;
1220 di->conformant_eaten=offset-old_offset;
1222 /* we don't remember where in the bytestream this field was */
1223 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1225 /* real run, dissect the elements */
1226 for(i=0;i<di->array_max_count;i++){
1227 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1233 /* function to dissect a unidimensional conformant and varying array */
1235 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1236 proto_tree *tree, guint8 *drep,
1237 dcerpc_dissect_fnct_t *fnct)
1243 di=pinfo->private_data;
1244 if(di->conformant_run){
1245 /* conformant run, just dissect the max_count header */
1247 di->conformant_run=0;
1248 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1249 hf_dcerpc_array_max_count, &di->array_max_count);
1250 di->array_max_count_offset=offset-4;
1251 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1252 hf_dcerpc_array_offset, &di->array_offset);
1253 di->array_offset_offset=offset-4;
1254 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1255 hf_dcerpc_array_actual_count, &di->array_actual_count);
1256 di->array_actual_count_offset=offset-4;
1257 di->conformant_run=1;
1258 di->conformant_eaten=offset-old_offset;
1260 /* we dont dont remember where in the bytestream these fields were */
1261 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1262 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
1263 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
1265 /* real run, dissect the elements */
1266 for(i=0;i<di->array_actual_count;i++){
1267 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1273 /* function to dissect a unidimensional varying array */
1275 dissect_ndr_uvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1276 proto_tree *tree, guint8 *drep,
1277 dcerpc_dissect_fnct_t *fnct)
1283 di=pinfo->private_data;
1284 if(di->conformant_run){
1285 /* conformant run, just dissect the max_count header */
1287 di->conformant_run=0;
1288 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1289 hf_dcerpc_array_offset, &di->array_offset);
1290 di->array_offset_offset=offset-4;
1291 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1292 hf_dcerpc_array_actual_count, &di->array_actual_count);
1293 di->array_actual_count_offset=offset-4;
1294 di->conformant_run=1;
1295 di->conformant_eaten=offset-old_offset;
1297 /* we dont dont remember where in the bytestream these fields were */
1298 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
1299 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
1301 /* real run, dissect the elements */
1302 for(i=0;i<di->array_actual_count;i++){
1303 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1310 /* Dissect an string of bytes. This corresponds to
1311 IDL of the form '[string] byte *foo'.
1313 It can also be used for a conformant varying array of bytes if
1314 the contents of the array should be shown as a big blob, rather
1315 than showing each byte as an individual element.
1317 XXX - which of those is really the IDL type for, for example,
1318 the encrypted data in some MAPI packets? (Microsoft haven't
1321 XXX - does this need to do all the conformant array stuff that
1322 "dissect_ndr_ucvarray()" does? These are presumably for strings
1323 that are conformant and varying - they're stored like conformant
1324 varying arrays of bytes. */
1326 dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo,
1327 proto_tree *tree, guint8 *drep)
1332 di=pinfo->private_data;
1333 if(di->conformant_run){
1334 /* just a run to handle conformant arrays, no scalars to dissect */
1338 /* NDR array header */
1340 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1341 hf_dcerpc_array_max_count, NULL);
1343 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1344 hf_dcerpc_array_offset, NULL);
1346 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1347 hf_dcerpc_array_actual_count, &len);
1350 tvb_ensure_bytes_exist(tvb, offset, len);
1351 proto_tree_add_item(tree, hf_dcerpc_array_buffer,
1352 tvb, offset, len, drep[0] & 0x10);
1360 /* For dissecting arrays that are to be interpreted as strings. */
1362 /* Dissect an NDR conformant varying string of elements.
1363 The length of each element is given by the 'size_is' parameter;
1364 the elements are assumed to be characters or wide characters.
1366 XXX - does this need to do all the conformant array stuff that
1367 "dissect_ndr_ucvarray()" does? */
1369 dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1370 proto_tree *tree, guint8 *drep, int size_is,
1371 int hfindex, gboolean add_subtree, char **data)
1374 proto_item *string_item;
1375 proto_tree *string_tree;
1376 guint32 len, buffer_len;
1378 header_field_info *hfinfo;
1380 di=pinfo->private_data;
1381 if(di->conformant_run){
1382 /* just a run to handle conformant arrays, no scalars to dissect */
1387 string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1388 proto_registrar_get_name(hfindex));
1389 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1395 /* NDR array header */
1397 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1398 hf_dcerpc_array_max_count, NULL);
1400 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1401 hf_dcerpc_array_offset, NULL);
1403 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1404 hf_dcerpc_array_actual_count, &len);
1406 buffer_len = size_is * len;
1409 if (offset % size_is)
1410 offset += size_is - (offset % size_is);
1412 if (size_is == sizeof(guint16)) {
1413 /* XXX - use drep to determine the byte order? */
1414 s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
1416 * XXX - we don't support a string type with Unicode
1417 * characters, so if this is a string item, we make
1418 * its value be the "fake Unicode" string.
1420 if (tree && buffer_len) {
1421 hfinfo = proto_registrar_get_nth(hfindex);
1422 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1423 if (hfinfo->type == FT_STRING) {
1424 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1427 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1428 buffer_len, drep[0] & 0x10);
1433 * "tvb_get_string()" throws an exception if the entire string
1434 * isn't in the tvbuff. If the length is bogus, this should
1435 * keep us from trying to allocate an immensely large buffer.
1436 * (It won't help if the length is *valid* but immensely large,
1437 * but that's another matter; in any case, that would happen only
1438 * if we had an immensely large tvbuff....)
1440 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1441 s = tvb_get_string(tvb, offset, buffer_len);
1442 if (tree && buffer_len)
1443 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1444 buffer_len, drep[0] & 0x10);
1447 if (string_item != NULL)
1448 proto_item_append_text(string_item, ": %s", s);
1455 offset += buffer_len;
1457 proto_item_set_end(string_item, tvb, offset);
1462 /* Dissect an conformant varying string of chars.
1463 This corresponds to IDL of the form '[string] char *foo'.
1465 XXX - at least according to the DCE RPC 1.1 spec, a string has
1466 a null terminator, which isn't necessary as a terminator for
1467 the transfer language (as there's a length), but is presumably
1468 there for the benefit of null-terminated-string languages
1469 such as C. Is this ever used for purely counted strings?
1470 (Not that it matters if it is.) */
1472 dissect_ndr_char_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1473 proto_tree *tree, guint8 *drep)
1476 di=pinfo->private_data;
1478 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1479 sizeof(guint8), di->hf_index,
1483 /* Dissect a conformant varying string of wchars (wide characters).
1484 This corresponds to IDL of the form '[string] wchar *foo'
1486 XXX - at least according to the DCE RPC 1.1 spec, a string has
1487 a null terminator, which isn't necessary as a terminator for
1488 the transfer language (as there's a length), but is presumably
1489 there for the benefit of null-terminated-string languages
1490 such as C. Is this ever used for purely counted strings?
1491 (Not that it matters if it is.) */
1493 dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1494 proto_tree *tree, guint8 *drep)
1497 di=pinfo->private_data;
1499 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1500 sizeof(guint16), di->hf_index,
1504 /* Dissect an NDR varying string of elements.
1505 The length of each element is given by the 'size_is' parameter;
1506 the elements are assumed to be characters or wide characters.
1509 dissect_ndr_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1510 proto_tree *tree, guint8 *drep, int size_is,
1511 int hfindex, gboolean add_subtree, char **data)
1514 proto_item *string_item;
1515 proto_tree *string_tree;
1516 guint32 len, buffer_len;
1518 header_field_info *hfinfo;
1520 di=pinfo->private_data;
1521 if(di->conformant_run){
1522 /* just a run to handle conformant arrays, no scalars to dissect */
1527 string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1528 proto_registrar_get_name(hfindex));
1529 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1535 /* NDR array header */
1536 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1537 hf_dcerpc_array_offset, NULL);
1539 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1540 hf_dcerpc_array_actual_count, &len);
1542 buffer_len = size_is * len;
1545 if (offset % size_is)
1546 offset += size_is - (offset % size_is);
1548 if (size_is == sizeof(guint16)) {
1549 /* XXX - use drep to determine the byte order? */
1550 s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
1552 * XXX - we don't support a string type with Unicode
1553 * characters, so if this is a string item, we make
1554 * its value be the "fake Unicode" string.
1556 if (tree && buffer_len) {
1557 hfinfo = proto_registrar_get_nth(hfindex);
1558 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1559 if (hfinfo->type == FT_STRING) {
1560 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1563 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1564 buffer_len, drep[0] & 0x10);
1569 * "tvb_get_string()" throws an exception if the entire string
1570 * isn't in the tvbuff. If the length is bogus, this should
1571 * keep us from trying to allocate an immensely large buffer.
1572 * (It won't help if the length is *valid* but immensely large,
1573 * but that's another matter; in any case, that would happen only
1574 * if we had an immensely large tvbuff....)
1576 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1577 s = tvb_get_string(tvb, offset, buffer_len);
1578 if (tree && buffer_len)
1579 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1580 buffer_len, drep[0] & 0x10);
1583 if (string_item != NULL)
1584 proto_item_append_text(string_item, ": %s", s);
1591 offset += buffer_len;
1593 proto_item_set_end(string_item, tvb, offset);
1597 /* Dissect an varying string of chars.
1598 This corresponds to IDL of the form '[string] char *foo'.
1600 XXX - at least according to the DCE RPC 1.1 spec, a string has
1601 a null terminator, which isn't necessary as a terminator for
1602 the transfer language (as there's a length), but is presumably
1603 there for the benefit of null-terminated-string languages
1604 such as C. Is this ever used for purely counted strings?
1605 (Not that it matters if it is.) */
1607 dissect_ndr_char_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1608 proto_tree *tree, guint8 *drep)
1611 di=pinfo->private_data;
1613 return dissect_ndr_vstring(tvb, offset, pinfo, tree, drep,
1614 sizeof(guint8), di->hf_index,
1618 /* Dissect a varying string of wchars (wide characters).
1619 This corresponds to IDL of the form '[string] wchar *foo'
1621 XXX - at least according to the DCE RPC 1.1 spec, a string has
1622 a null terminator, which isn't necessary as a terminator for
1623 the transfer language (as there's a length), but is presumably
1624 there for the benefit of null-terminated-string languages
1625 such as C. Is this ever used for purely counted strings?
1626 (Not that it matters if it is.) */
1628 dissect_ndr_wchar_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1629 proto_tree *tree, guint8 *drep)
1632 di=pinfo->private_data;
1634 return dissect_ndr_vstring(tvb, offset, pinfo, tree, drep,
1635 sizeof(guint16), di->hf_index,
1640 /* ndr pointer handling */
1641 /* list of pointers encountered so far */
1642 static GSList *ndr_pointer_list = NULL;
1644 /* position where in the list to insert newly encountered pointers */
1645 static int ndr_pointer_list_pos=0;
1647 /* boolean controlling whether pointers are top-level or embedded */
1648 static gboolean pointers_are_top_level = TRUE;
1650 /* as a kludge, we represent all embedded reference pointers as id==-1
1651 hoping that his will not collide with any non-ref pointers */
1652 typedef struct ndr_pointer_data {
1654 proto_item *item; /* proto_item for pointer */
1655 proto_tree *tree; /* subtree of above item */
1656 dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
1658 dcerpc_callback_fnct_t *callback;
1659 void *callback_args;
1660 } ndr_pointer_data_t;
1663 init_ndr_pointer_list(packet_info *pinfo)
1667 di=pinfo->private_data;
1668 di->conformant_run=0;
1670 while(ndr_pointer_list){
1671 ndr_pointer_data_t *npd;
1673 npd=g_slist_nth_data(ndr_pointer_list, 0);
1674 ndr_pointer_list=g_slist_remove(ndr_pointer_list, npd);
1680 ndr_pointer_list=NULL;
1681 ndr_pointer_list_pos=0;
1682 pointers_are_top_level=TRUE;
1686 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, guint8 *drep)
1688 int found_new_pointer;
1694 di=pinfo->private_data;
1698 found_new_pointer=0;
1699 len=g_slist_length(ndr_pointer_list);
1700 for(i=next_pointer;i<len;i++){
1701 ndr_pointer_data_t *tnpd;
1702 tnpd=g_slist_nth_data(ndr_pointer_list, i);
1704 dcerpc_dissect_fnct_t *fnct;
1707 found_new_pointer=1;
1710 ndr_pointer_list_pos=i+1;
1711 di->hf_index=tnpd->hf_index;
1712 /* first a run to handle any conformant
1714 di->conformant_run=1;
1715 di->conformant_eaten=0;
1716 old_offset = offset;
1717 offset = (*(fnct))(tvb, offset, pinfo, NULL, drep);
1719 DISSECTOR_ASSERT((offset-old_offset)==di->conformant_eaten);
1720 /* This is to check for any bugs in the dissectors.
1722 * Basically, the NDR representation will store all
1723 * arrays in two blocks, one block with the dimension
1724 * discreption, like size, number of elements and such,
1725 * and another block that contains the actual data stored
1727 * If the array is embedded directly inside another,
1728 * encapsulating aggregate type, like a union or struct,
1729 * then these two blocks will be stored at different places
1730 * in the bytestream, with other data between the blocks.
1732 * For this reason, all pointers to types (both aggregate
1733 * and scalar, for simplicity no distinction is made)
1734 * will have its dissector called twice.
1735 * The dissector will first be called with conformant_run==1
1736 * in which mode the dissector MUST NOT consume any data from
1737 * the tvbuff (i.e. may not dissect anything) except the
1738 * initial control block for arrays.
1739 * The second time the dissector is called, with
1740 * conformant_run==0, all other data for the type will be
1743 * All dissect_ndr_<type> dissectors are already prepared
1744 * for this and knows when it should eat data from the tvb
1745 * and when not to, so implementors of dissectors will
1746 * normally not need to worry about this or even know about
1747 * it. However, if a dissector for an aggregate type calls
1748 * a subdissector from outside packet-dcerpc.c, such as
1749 * the dissector in packet-smb.c for NT Security Descriptors
1750 * as an example, then it is VERY important to encapsulate
1751 * this call to an external subdissector with the appropriate
1752 * test for conformant_run, i.e. it will need something like
1756 * di=pinfo->private_data;
1757 * if(di->conformant_run){
1761 * to make sure it makes the right thing.
1762 * This assert will signal when someone has forgotten to
1763 * make the dissector aware of this requirement.
1766 /* now we dissect the actual pointer */
1767 di->conformant_run=0;
1768 old_offset = offset;
1769 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, drep);
1771 tnpd->callback(pinfo, tnpd->tree, tnpd->item, tvb, old_offset, offset, tnpd->callback_args);
1775 } while(found_new_pointer);
1782 add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
1783 dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index,
1784 dcerpc_callback_fnct_t *callback, void *callback_args)
1786 ndr_pointer_data_t *npd;
1788 /* check if this pointer is valid */
1791 dcerpc_call_value *value;
1793 di=pinfo->private_data;
1794 value=di->call_data;
1796 if(di->ptype == PDU_REQ){
1797 if(!(pinfo->fd->flags.visited)){
1798 if(id>value->max_ptr){
1803 /* if we havent seen the request bail out since we cant
1804 know whether this is the first non-NULL instance
1806 if(value->req_frame==0){
1807 /* XXX THROW EXCEPTION */
1810 /* We saw this one in the request frame, nothing to
1812 if(id<=value->max_ptr){
1818 npd=g_malloc(sizeof(ndr_pointer_data_t));
1823 npd->hf_index=hf_index;
1824 npd->callback=callback;
1825 npd->callback_args=callback_args;
1826 ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
1827 ndr_pointer_list_pos);
1828 ndr_pointer_list_pos++;
1833 find_pointer_index(guint32 id)
1835 ndr_pointer_data_t *npd;
1838 len=g_slist_length(ndr_pointer_list);
1840 npd=g_slist_nth_data(ndr_pointer_list, i);
1851 /* This function dissects an NDR pointer and stores the callback for later
1852 * deferred dissection.
1854 * fnct is the callback function for when we have reached this object in
1857 * type is what type of pointer.
1859 * this is text is what text we should put in any created tree node.
1861 * hf_index is what hf value we want to pass to the callback function when
1862 * it is called, the callback can later pich this one up from di->hf_index.
1864 * callback is executed after the pointer has been dereferenced.
1866 * callback_args is passed as an argument to the callback function
1868 * See packet-dcerpc-samr.c for examples
1871 dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1872 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
1873 int type, const char *text, int hf_index,
1874 dcerpc_callback_fnct_t *callback, void *callback_args)
1877 proto_tree *tr = NULL;
1878 gint start_offset = offset;
1880 di=pinfo->private_data;
1881 if(di->conformant_run){
1882 /* this call was only for dissecting the header for any
1883 embedded conformant array. we will not parse any
1884 pointers in this mode.
1889 /*TOP LEVEL REFERENCE POINTER*/
1890 if( pointers_are_top_level
1891 &&(type==NDR_POINTER_REF) ){
1894 /* we must find out a nice way to do the length here */
1895 item=proto_tree_add_text(tree, tvb, offset, 0,
1897 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1899 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1900 hf_index, callback, callback_args);
1904 /*TOP LEVEL FULL POINTER*/
1905 if( pointers_are_top_level
1906 && (type==NDR_POINTER_PTR) ){
1911 /* get the referent id */
1912 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1914 tvb_ensure_bytes_exist(tvb, offset-4, 4);
1915 /* we got a NULL pointer */
1917 proto_tree_add_text(tree, tvb, offset-4, 4,
1918 "(NULL pointer) %s",text);
1922 /* see if we have seen this pointer before */
1923 idx=find_pointer_index(id);
1925 /* we have seen this pointer before */
1927 proto_tree_add_text(tree, tvb, offset-4, 4,
1928 "(duplicate PTR) %s",text);
1933 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1935 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1936 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1937 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
1938 callback, callback_args);
1941 /*TOP LEVEL UNIQUE POINTER*/
1942 if( pointers_are_top_level
1943 && (type==NDR_POINTER_UNIQUE) ){
1947 /* get the referent id */
1948 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1950 tvb_ensure_bytes_exist(tvb, offset-4, 4);
1951 /* we got a NULL pointer */
1953 proto_tree_add_text(tree, tvb, offset-4, 4,
1954 "(NULL pointer) %s",text);
1959 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1961 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1962 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1963 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1964 hf_index, callback, callback_args);
1968 /*EMBEDDED REFERENCE POINTER*/
1969 if( (!pointers_are_top_level)
1970 && (type==NDR_POINTER_REF) ){
1974 /* get the referent id */
1975 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1977 tvb_ensure_bytes_exist(tvb, offset-4, 4);
1979 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1981 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1982 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1983 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1984 hf_index, callback, callback_args);
1988 /*EMBEDDED UNIQUE POINTER*/
1989 if( (!pointers_are_top_level)
1990 && (type==NDR_POINTER_UNIQUE) ){
1994 /* get the referent id */
1995 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1997 tvb_ensure_bytes_exist(tvb, offset-4, 4);
1998 /* we got a NULL pointer */
2000 proto_tree_add_text(tree, tvb, offset-4, 4,
2001 "(NULL pointer) %s", text);
2006 item=proto_tree_add_text(tree, tvb, offset-4, 4,
2008 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2009 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
2010 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
2011 hf_index, callback, callback_args);
2015 /*EMBEDDED FULL POINTER*/
2016 if( (!pointers_are_top_level)
2017 && (type==NDR_POINTER_PTR) ){
2022 /* get the referent id */
2023 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
2025 tvb_ensure_bytes_exist(tvb, offset-4, 4);
2026 /* we got a NULL pointer */
2028 proto_tree_add_text(tree, tvb, offset-4, 4,
2029 "(NULL pointer) %s",text);
2033 /* see if we have seen this pointer before */
2034 idx=find_pointer_index(id);
2036 /* we have seen this pointer before */
2038 proto_tree_add_text(tree, tvb, offset-4, 4,
2039 "(duplicate PTR) %s",text);
2044 item=proto_tree_add_text(tree, tvb, offset-4, 4,
2046 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2047 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
2048 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
2049 callback, callback_args);
2055 /* After each top level pointer we have dissected we have to
2056 dissect all deferrals before we move on to the next top level
2058 if(pointers_are_top_level==TRUE){
2059 pointers_are_top_level=FALSE;
2060 offset = dissect_deferred_pointers(pinfo, tvb, offset, drep);
2061 pointers_are_top_level=TRUE;
2064 /* Set the length for the new subtree */
2066 proto_item_set_len(tr, offset-start_offset);
2072 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2073 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2074 int type, const char *text, int hf_index)
2076 return dissect_ndr_pointer_cb(
2077 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
2081 dissect_ndr_toplevel_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2082 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2083 int type, const char *text, int hf_index)
2087 pointers_are_top_level=TRUE;
2088 ret=dissect_ndr_pointer_cb(
2089 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
2094 dissect_ndr_embedded_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2095 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2096 int type, const char *text, int hf_index)
2100 pointers_are_top_level=FALSE;
2101 ret=dissect_ndr_pointer_cb(
2102 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
2108 show_stub_data (tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
2109 dcerpc_auth_info *auth_info, gboolean is_encrypted)
2111 int length, plain_length, auth_pad_len;
2112 guint auth_pad_offset;
2115 * We don't show stub data unless we have some in the tvbuff;
2116 * however, in the protocol tree, we show, as the number of
2117 * bytes, the reported number of bytes, not the number of bytes
2118 * that happen to be in the tvbuff.
2120 if (tvb_length_remaining (tvb, offset) > 0) {
2121 auth_pad_len = auth_info?auth_info->auth_pad_len:0;
2122 length = tvb_reported_length_remaining (tvb, offset);
2124 /* if auth_pad_len is larger than length then we ignore auth_pad_len totally */
2125 plain_length = length - auth_pad_len;
2126 if (plain_length < 1) {
2127 plain_length = length;
2130 auth_pad_offset = offset + plain_length;
2132 if (auth_info != NULL &&
2133 auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
2135 tvb_ensure_bytes_exist(tvb, offset, length);
2136 proto_tree_add_text(dcerpc_tree, tvb, offset, length,
2137 "Encrypted stub data (%d byte%s)",
2138 length, plurality(length, "", "s"));
2139 /* is the padding is still inside the encrypted blob, don't display it explicit */
2142 tvb_ensure_bytes_exist(tvb, offset, plain_length);
2143 proto_tree_add_text(dcerpc_tree, tvb, offset, plain_length,
2144 "Decrypted stub data (%d byte%s)",
2145 plain_length, plurality(plain_length, "", "s"));
2148 tvb_ensure_bytes_exist(tvb, offset, plain_length);
2149 proto_tree_add_text (dcerpc_tree, tvb, offset, plain_length,
2150 "Stub data (%d byte%s)", plain_length,
2151 plurality(plain_length, "", "s"));
2153 /* If there is auth padding at the end of the stub, display it */
2154 if (auth_pad_len != 0) {
2155 tvb_ensure_bytes_exist(tvb, auth_pad_offset, auth_pad_len);
2156 proto_tree_add_text (dcerpc_tree, tvb, auth_pad_offset,
2158 "Auth Padding (%u byte%s)",
2160 plurality(auth_pad_len, "", "s"));
2166 dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
2167 proto_tree *dcerpc_tree,
2168 tvbuff_t *volatile tvb, tvbuff_t *decrypted_tvb,
2169 guint8 *drep, dcerpc_info *info,
2170 dcerpc_auth_info *auth_info)
2172 volatile gint offset = 0;
2173 dcerpc_uuid_key key;
2174 dcerpc_uuid_value *sub_proto;
2175 proto_tree *volatile sub_tree = NULL;
2176 dcerpc_sub_dissector *proc;
2177 const gchar *name = NULL;
2178 dcerpc_dissect_fnct_t *volatile sub_dissect;
2179 const char *volatile saved_proto;
2180 void *volatile saved_private_data;
2181 guint length, reported_length;
2182 tvbuff_t *volatile stub_tvb;
2183 volatile guint auth_pad_len;
2184 volatile int auth_pad_offset;
2186 char UUID_NAME[MAX_PATH];
2188 proto_item *sub_item;
2190 key.uuid = info->call_data->uuid;
2191 key.ver = info->call_data->ver;
2194 if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == NULL
2195 || !proto_is_protocol_enabled(sub_proto->proto)) {
2197 * We don't have a dissector for this UUID, or the protocol
2198 * for that UUID is disabled.
2201 proto_tree_add_boolean_hidden(dcerpc_tree, hf_dcerpc_unknown_if_id,
2202 tvb, offset, 0, TRUE);
2203 if (check_col (pinfo->cinfo, COL_INFO)) {
2205 if(ResolveWin32UUID(info->call_data->uuid, UUID_NAME, MAX_PATH))
2206 col_append_fstr (pinfo->cinfo, COL_INFO, " [%s] UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x rpcver: %u",
2207 UUID_NAME, info->call_data->uuid.Data1, info->call_data->uuid.Data2, info->call_data->uuid.Data3, info->call_data->uuid.Data4[0],
2208 info->call_data->uuid.Data4[1], info->call_data->uuid.Data4[2], info->call_data->uuid.Data4[3],
2209 info->call_data->uuid.Data4[4], info->call_data->uuid.Data4[5], info->call_data->uuid.Data4[6],
2210 info->call_data->uuid.Data4[7], info->call_data->ver);
2213 col_append_fstr (pinfo->cinfo, COL_INFO, " UNKUUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x rpcver: %u",
2214 info->call_data->uuid.Data1, info->call_data->uuid.Data2, info->call_data->uuid.Data3, info->call_data->uuid.Data4[0],
2215 info->call_data->uuid.Data4[1], info->call_data->uuid.Data4[2], info->call_data->uuid.Data4[3],
2216 info->call_data->uuid.Data4[4], info->call_data->uuid.Data4[5], info->call_data->uuid.Data4[6],
2217 info->call_data->uuid.Data4[7], info->call_data->ver);
2220 if (decrypted_tvb != NULL) {
2221 show_stub_data (decrypted_tvb, 0, dcerpc_tree, auth_info,
2224 show_stub_data (tvb, 0, dcerpc_tree, auth_info, TRUE);
2228 for (proc = sub_proto->procs; proc->name; proc++) {
2229 if (proc->num == info->call_data->opnum) {
2238 if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
2239 col_set_str (pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
2242 if (check_col (pinfo->cinfo, COL_INFO)) {
2243 col_add_fstr (pinfo->cinfo, COL_INFO, "%s %s",
2244 name, (info->ptype == PDU_REQ) ? "request" : "response");
2248 sub_item = proto_tree_add_item (tree, sub_proto->proto_id, tvb, 0,
2252 sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
2253 proto_item_append_text(sub_item, ", %s", name);
2257 * Put the operation number into the tree along with
2258 * the operation's name.
2261 if (sub_proto->opnum_hf != -1)
2262 proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
2263 tvb, 0, 0, info->call_data->opnum,
2264 "Operation: %s (%u)",
2265 name, info->call_data->opnum);
2267 proto_tree_add_uint_format(sub_tree, hf_dcerpc_op, tvb,
2268 0, 0, info->call_data->opnum,
2269 "Operation: %s (%u)",
2270 name, info->call_data->opnum);
2273 sub_dissect = (info->ptype == PDU_REQ) ?
2274 proc->dissect_rqst : proc->dissect_resp;
2276 if (decrypted_tvb != NULL) {
2277 /* Either there was no encryption or we successfully decrypted
2278 the entrypted payload. */
2280 /* We have a subdissector - call it. */
2281 saved_proto = pinfo->current_proto;
2282 saved_private_data = pinfo->private_data;
2283 pinfo->current_proto = sub_proto->name;
2284 pinfo->private_data = (void *)info;
2286 init_ndr_pointer_list(pinfo);
2289 * Remove the authentication padding from the stub data.
2291 if (auth_info != NULL && auth_info->auth_pad_len != 0) {
2292 length = tvb_length(decrypted_tvb);
2293 reported_length = tvb_reported_length(decrypted_tvb);
2294 if (reported_length >= auth_info->auth_pad_len) {
2296 * OK, the padding length isn't so big that it
2297 * exceeds the stub length. Trim the reported
2298 * length of the tvbuff.
2300 reported_length -= auth_info->auth_pad_len;
2303 * If that exceeds the actual amount of data in
2304 * the tvbuff (which means we have at least one
2305 * byte of authentication padding in the tvbuff),
2306 * trim the actual amount.
2308 if (length > reported_length)
2309 length = reported_length;
2311 stub_tvb = tvb_new_subset(tvb, 0, length, reported_length);
2312 auth_pad_len = auth_info->auth_pad_len;
2313 auth_pad_offset = reported_length;
2316 * The padding length exceeds the stub length.
2317 * Don't bother dissecting the stub, trim the padding
2318 * length to what's in the stub data, and show the
2319 * entire stub as authentication padding.
2322 auth_pad_len = reported_length;
2323 auth_pad_offset = 0;
2327 * No authentication padding.
2329 stub_tvb = decrypted_tvb;
2331 auth_pad_offset = 0;
2334 if (stub_tvb != NULL) {
2336 * Catch all exceptions other than BoundsError, so that even
2337 * if the stub data is bad, we still show the authentication
2340 * If we get BoundsError, it means the frame was cut short
2341 * by a snapshot length, so there's nothing more to
2342 * dissect; just re-throw that exception.
2345 offset = sub_dissect (decrypted_tvb, 0, pinfo, sub_tree,
2348 proto_item_set_len(sub_item, offset);
2351 /* If we have a subdissector and it didn't dissect all
2352 data in the tvb, make a note of it. */
2353 /* XXX - don't do this, as this could be just another RPC Req./Resp. in this PDU */
2354 /*if (tvb_reported_length_remaining(stub_tvb, offset) > 0) {
2355 if (check_col(pinfo->cinfo, COL_INFO))
2356 col_append_fstr(pinfo->cinfo, COL_INFO,
2357 "[Long frame (%d bytes)]",
2358 tvb_reported_length_remaining(stub_tvb, offset));
2360 } CATCH(BoundsError) {
2363 show_exception(decrypted_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
2367 /* If there is auth padding at the end of the stub, display it */
2368 if (auth_pad_len != 0) {
2369 tvb_ensure_bytes_exist(tvb, auth_pad_offset, auth_pad_len);
2370 proto_tree_add_text (sub_tree, decrypted_tvb, auth_pad_offset,
2372 "Auth Padding (%u byte%s)",
2374 plurality(auth_pad_len, "", "s"));
2377 pinfo->current_proto = saved_proto;
2378 pinfo->private_data = saved_private_data;
2380 /* No subdissector - show it as stub data. */
2382 show_stub_data (decrypted_tvb, 0, sub_tree, auth_info, FALSE);
2384 show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
2388 show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
2390 tap_queue_packet(dcerpc_tap, pinfo, info);
2395 dissect_dcerpc_verifier (tvbuff_t *tvb, packet_info *pinfo,
2396 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
2397 dcerpc_auth_info *auth_info)
2401 auth_info->auth_data = NULL;
2403 if (auth_info->auth_size != 0) {
2404 dcerpc_auth_subdissector_fns *auth_fns;
2407 auth_offset = hdr->frag_len - hdr->auth_len;
2409 auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
2412 auth_info->auth_data = auth_tvb;
2414 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
2415 auth_info->auth_type))) {
2417 * Catch all exceptions, so that even if the verifier is bad
2418 * or we don't have all of it, we still show the stub data.
2421 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
2424 show_exception(auth_tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
2427 tvb_ensure_bytes_exist(tvb, 0, hdr->auth_len);
2428 proto_tree_add_text (dcerpc_tree, auth_tvb, 0, hdr->auth_len,
2433 return hdr->auth_len;
2437 dissect_dcerpc_cn_auth (tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
2438 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
2439 gboolean are_credentials, dcerpc_auth_info *auth_info)
2441 volatile int offset;
2444 * Initially set auth_level and auth_type to zero to indicate that we
2445 * haven't yet seen any authentication level information.
2447 auth_info->auth_level = 0;
2448 auth_info->auth_type = 0;
2449 auth_info->auth_size = 0;
2450 auth_info->auth_pad_len = 0;
2453 * The authentication information is at the *end* of the PDU; in
2454 * request and response PDUs, the request and response stub data
2457 * Is there any authentication data (i.e., is the authentication length
2458 * non-zero), and is the authentication length valid (i.e., is it, plus
2459 * 8 bytes for the type/level/pad length/reserved/context id, less than
2460 * or equal to the fragment length minus the starting offset of the
2465 && (hdr->auth_len + 8 <= hdr->frag_len - stub_offset)) {
2468 * Yes, there is authentication data, and the length is valid.
2469 * Do we have all the bytes of stub data?
2470 * (If not, we'd throw an exception dissecting *that*, so don't
2471 * bother trying to dissect the authentication information and
2472 * throwing another exception there.)
2474 offset = hdr->frag_len - (hdr->auth_len + 8);
2475 if (offset == 0 || tvb_offset_exists(tvb, offset - 1)) {
2477 * Either there's no stub data, or the last byte of the stub
2478 * data is present in the captured data, so we shouldn't
2479 * get a BoundsError dissecting the stub data.
2481 * Try dissecting the authentication data.
2482 * Catch all exceptions, so that even if the auth info is bad
2483 * or we don't have all of it, we still show the stuff we
2484 * dissect after this, such as stub data.
2487 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2488 hf_dcerpc_auth_type,
2489 &auth_info->auth_type);
2490 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2491 hf_dcerpc_auth_level,
2492 &auth_info->auth_level);
2494 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2495 hf_dcerpc_auth_pad_len,
2496 &auth_info->auth_pad_len);
2497 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2498 hf_dcerpc_auth_rsrvd, NULL);
2499 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2500 hf_dcerpc_auth_ctx_id, NULL);
2503 * Dissect the authentication data.
2505 if (are_credentials) {
2507 dcerpc_auth_subdissector_fns *auth_fns;
2509 auth_tvb = tvb_new_subset(tvb, offset, hdr->auth_len,
2512 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
2513 auth_info->auth_type)))
2514 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
2517 proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len,
2518 "Auth Credentials");
2521 /* Compute the size of the auth block. Note that this should not
2522 include auth padding, since when NTLMSSP encryption is used, the
2523 padding is actually inside the encrypted stub */
2524 auth_info->auth_size = hdr->auth_len + 8;
2526 show_exception(tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
2533 /* We need to hash in the SMB fid number to generate a unique hash table
2534 * key as DCERPC over SMB allows several pipes over the same TCP/IP
2536 * We pass this function the transport type here to make sure we only look
2537 * at this function if it came across an SMB pipe.
2538 * Other transports might need to mix in their own extra multiplexing data
2539 * as well in the future.
2542 guint16 dcerpc_get_transport_salt (packet_info *pinfo)
2544 switch(pinfo->dcetransporttype){
2545 case DCE_CN_TRANSPORT_SMBPIPE:
2546 /* DCERPC over smb */
2547 return pinfo->dcetransportsalt;
2550 /* Some other transport... */
2555 * Connection oriented packet types
2559 dissect_dcerpc_cn_bind (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2560 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2562 conversation_t *conv = NULL;
2563 guint8 num_ctx_items = 0;
2565 gboolean saw_ctx_item = FALSE;
2567 guint8 num_trans_items;
2572 guint16 if_ver, if_ver_minor;
2573 char uuid_str[DCERPC_UUID_STR_LEN];
2575 dcerpc_auth_info auth_info;
2577 char UUID_NAME[MAX_PATH];
2580 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2581 hf_dcerpc_cn_max_xmit, NULL);
2583 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2584 hf_dcerpc_cn_max_recv, NULL);
2586 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2587 hf_dcerpc_cn_assoc_group, NULL);
2589 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2590 hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
2595 for (i = 0; i < num_ctx_items; i++) {
2596 proto_tree *ctx_tree = NULL, *iface_tree = NULL;
2598 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, NULL, hdr->drep,
2599 hf_dcerpc_cn_ctx_id, &ctx_id);
2601 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
2602 /* (if we have multiple contexts, this might cause "decode as"
2603 * to behave unpredictably) */
2604 pinfo->dcectxid = ctx_id;
2607 proto_item *ctx_item;
2609 ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_id,
2611 hdr->drep[0] & 0x10);
2613 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
2616 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, ctx_tree, hdr->drep,
2617 hf_dcerpc_cn_num_trans_items, &num_trans_items);
2622 /* XXX - use "dissect_ndr_uuid_t()"? */
2623 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
2625 proto_item *iface_item;
2627 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2628 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2629 if_id.Data1, if_id.Data2, if_id.Data3,
2630 if_id.Data4[0], if_id.Data4[1],
2631 if_id.Data4[2], if_id.Data4[3],
2632 if_id.Data4[4], if_id.Data4[5],
2633 if_id.Data4[6], if_id.Data4[7]);
2635 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2636 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2638 if(ResolveWin32UUID(if_id, UUID_NAME, MAX_PATH))
2639 iface_item = proto_tree_add_string_format (ctx_tree, hf_dcerpc_cn_bind_if_id, tvb,
2640 offset, 16, uuid_str, "Interface [%s] UUID: %s", UUID_NAME, uuid_str);
2643 iface_item = proto_tree_add_string_format (ctx_tree, hf_dcerpc_cn_bind_if_id, tvb,
2644 offset, 16, uuid_str, "Interface UUID: %s", uuid_str);
2645 iface_tree = proto_item_add_subtree(iface_item, ett_dcerpc_cn_iface);
2649 if (hdr->drep[0] & 0x10) {
2650 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2651 hf_dcerpc_cn_bind_if_ver, &if_ver);
2652 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2653 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2655 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2656 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2657 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2658 hf_dcerpc_cn_bind_if_ver, &if_ver);
2661 if (!saw_ctx_item) {
2662 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
2663 pinfo->srcport, pinfo->destport, 0);
2665 conv = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
2666 pinfo->srcport, pinfo->destport, 0);
2670 /* if this is the first time we see this packet, we need to
2671 update the dcerpc_binds table so that any later calls can
2672 match to the interface.
2673 XXX We assume that BINDs will NEVER be fragmented.
2675 if(!(pinfo->fd->flags.visited)){
2676 dcerpc_bind_key *key;
2677 dcerpc_bind_value *value;
2679 key = g_mem_chunk_alloc (dcerpc_bind_key_chunk);
2681 key->ctx_id = ctx_id;
2682 key->smb_fid = dcerpc_get_transport_salt(pinfo);
2684 value = g_mem_chunk_alloc (dcerpc_bind_value_chunk);
2685 value->uuid = if_id;
2686 value->ver = if_ver;
2688 /* add this entry to the bind table, first removing any
2689 previous ones that are identical
2691 if(g_hash_table_lookup(dcerpc_binds, key)){
2692 g_hash_table_remove(dcerpc_binds, key);
2694 g_hash_table_insert (dcerpc_binds, key, value);
2697 if (check_col (pinfo->cinfo, COL_INFO)) {
2698 dcerpc_uuid_key key;
2699 dcerpc_uuid_value *value;
2704 if (num_ctx_items > 1)
2705 col_append_fstr(pinfo->cinfo, COL_INFO, ", %u context items, 1st", num_ctx_items);
2707 if ((value = g_hash_table_lookup(dcerpc_uuids, &key)))
2708 col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %s", value->name);
2711 if(ResolveWin32UUID(if_id, UUID_NAME, MAX_PATH))
2712 col_append_fstr(pinfo->cinfo, COL_INFO, " [%s] UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
2713 UUID_NAME, if_id.Data1, if_id.Data2, if_id.Data3,
2714 if_id.Data4[0], if_id.Data4[1],
2715 if_id.Data4[2], if_id.Data4[3],
2716 if_id.Data4[4], if_id.Data4[5],
2717 if_id.Data4[6], if_id.Data4[7],
2718 if_ver, if_ver_minor);
2721 col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
2722 if_id.Data1, if_id.Data2, if_id.Data3,
2723 if_id.Data4[0], if_id.Data4[1],
2724 if_id.Data4[2], if_id.Data4[3],
2725 if_id.Data4[4], if_id.Data4[5],
2726 if_id.Data4[6], if_id.Data4[7],
2727 if_ver, if_ver_minor);
2729 saw_ctx_item = TRUE;
2732 for (j = 0; j < num_trans_items; j++) {
2733 /* XXX - use "dissect_ndr_uuid_t()"? */
2734 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2736 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2737 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2738 trans_id.Data1, trans_id.Data2, trans_id.Data3,
2739 trans_id.Data4[0], trans_id.Data4[1],
2740 trans_id.Data4[2], trans_id.Data4[3],
2741 trans_id.Data4[4], trans_id.Data4[5],
2742 trans_id.Data4[6], trans_id.Data4[7]);
2743 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2744 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2745 proto_tree_add_string_format (iface_tree, hf_dcerpc_cn_bind_trans_id, tvb,
2746 offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2750 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, iface_tree, hdr->drep,
2751 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
2756 * XXX - we should save the authentication type *if* we have
2757 * an authentication header, and associate it with an authentication
2758 * context, so subsequent PDUs can use that context.
2760 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2764 dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2765 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2767 guint16 max_xmit, max_recv;
2768 guint16 sec_addr_len;
2775 char uuid_str[DCERPC_UUID_STR_LEN];
2777 dcerpc_auth_info auth_info;
2779 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2780 hf_dcerpc_cn_max_xmit, &max_xmit);
2782 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2783 hf_dcerpc_cn_max_recv, &max_recv);
2785 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2786 hf_dcerpc_cn_assoc_group, NULL);
2788 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2789 hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
2790 if (sec_addr_len != 0) {
2791 tvb_ensure_bytes_exist(tvb, offset, sec_addr_len);
2792 proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
2793 sec_addr_len, FALSE);
2794 offset += sec_addr_len;
2798 offset += 4 - offset % 4;
2801 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2802 hf_dcerpc_cn_num_results, &num_results);
2807 for (i = 0; i < num_results; i++) {
2808 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2809 hdr->drep, hf_dcerpc_cn_ack_result,
2812 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2813 hdr->drep, hf_dcerpc_cn_ack_reason,
2817 * The reason for rejection isn't meaningful, and often isn't
2818 * set, when the syntax was accepted.
2823 /* XXX - use "dissect_ndr_uuid_t()"? */
2824 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2826 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2827 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2828 trans_id.Data1, trans_id.Data2, trans_id.Data3,
2829 trans_id.Data4[0], trans_id.Data4[1],
2830 trans_id.Data4[2], trans_id.Data4[3],
2831 trans_id.Data4[4], trans_id.Data4[5],
2832 trans_id.Data4[6], trans_id.Data4[7]);
2833 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2834 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2835 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_ack_trans_id, tvb,
2836 offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2840 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2841 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
2845 * XXX - do we need to do anything with the authentication level
2846 * we get back from this?
2848 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2850 if (check_col (pinfo->cinfo, COL_INFO)) {
2851 if (num_results != 0 && result == 0) {
2852 /* XXX - only checks the last result */
2853 col_append_fstr (pinfo->cinfo, COL_INFO,
2854 " accept max_xmit: %u max_recv: %u",
2855 max_xmit, max_recv);
2857 /* XXX - only shows the last result and reason */
2858 col_append_fstr (pinfo->cinfo, COL_INFO, " %s, reason: %s",
2859 val_to_str(result, p_cont_result_vals,
2860 "Unknown result (%u)"),
2861 val_to_str(reason, p_provider_reason_vals,
2868 dissect_dcerpc_cn_bind_nak (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2869 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2872 guint8 num_protocols;
2875 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2876 hdr->drep, hf_dcerpc_cn_reject_reason,
2879 if (check_col (pinfo->cinfo, COL_INFO)) {
2880 col_append_fstr (pinfo->cinfo, COL_INFO, " reason: %s",
2881 val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
2884 if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
2885 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2886 hf_dcerpc_cn_num_protocols,
2889 for (i = 0; i < num_protocols; i++) {
2890 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2891 hdr->drep, hf_dcerpc_cn_protocol_ver_major,
2893 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2894 hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
2900 /* Return a string describing a DCE/RPC fragment as first, middle, or end
2903 #define PFC_FRAG_MASK 0x03
2906 fragment_type(guint8 flags)
2908 flags = flags & PFC_FRAG_MASK;
2910 if (flags == PFC_FIRST_FRAG)
2916 if (flags == PFC_LAST_FRAG)
2919 if (flags == (PFC_FIRST_FRAG | PFC_LAST_FRAG))
2925 /* Dissect stub data (payload) of a DCERPC packet. */
2928 dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
2929 proto_tree *dcerpc_tree, proto_tree *tree,
2930 e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
2931 dcerpc_auth_info *auth_info, guint32 alloc_hint,
2934 gint length, reported_length;
2935 gboolean save_fragmented;
2936 fragment_data *fd_head=NULL;
2938 tvbuff_t *auth_tvb, *payload_tvb, *decrypted_tvb;
2940 proto_item *parent_pi;
2942 save_fragmented = pinfo->fragmented;
2944 length = tvb_length_remaining(tvb, offset);
2945 reported_length = tvb_reported_length_remaining(tvb, offset);
2946 if (reported_length < 0 ||
2947 (guint32)reported_length < auth_info->auth_size) {
2948 /* We don't even have enough bytes for the authentication
2952 reported_length -= auth_info->auth_size;
2953 if (length > reported_length)
2954 length = reported_length;
2955 payload_tvb = tvb_new_subset(tvb, offset, length, reported_length);
2958 /*dont bother if we dont have the entire tvb */
2959 /*XXX we should really make sure we calculate auth_info->auth_data
2960 and use that one instead of this auth_tvb hack
2962 if(tvb_length(tvb)==tvb_reported_length(tvb)){
2963 if(tvb_length_remaining(tvb, offset+length)>8){
2964 auth_tvb = tvb_new_subset(tvb, offset+length+8, -1, -1);
2968 /* Decrypt the PDU if it is encrypted */
2970 if (auth_info->auth_type &&
2971 auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
2973 * We know the authentication type, and the authentication
2974 * level is "Packet privacy", meaning the payload is
2975 * encrypted; attempt to decrypt it.
2977 dcerpc_auth_subdissector_fns *auth_fns;
2979 /* Start out assuming we won't succeed in decrypting. */
2980 decrypted_tvb = NULL;
2982 if ((auth_fns = get_auth_subdissector_fns(
2983 auth_info->auth_level, auth_info->auth_type))) {
2986 result = decode_encrypted_data(
2987 payload_tvb, auth_tvb, pinfo, auth_fns,
2988 hdr->ptype == PDU_REQ, auth_info);
2992 proto_tree_add_text(
2993 dcerpc_tree, payload_tvb, 0, -1,
2994 "Encrypted stub data (%d byte%s)",
2995 tvb_reported_length(payload_tvb),
2997 plurality(tvb_length(payload_tvb), "", "s"));
2999 add_new_data_source(
3000 pinfo, result, "Decrypted stub data");
3003 decrypted_tvb = result;
3007 decrypted_tvb = payload_tvb;
3009 /* if this packet is not fragmented, just dissect it and exit */
3010 if(PFC_NOT_FRAGMENTED(hdr)){
3011 pinfo->fragmented = FALSE;
3014 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
3015 hdr->drep, di, auth_info);
3017 pinfo->fragmented = save_fragmented;
3021 /* The packet is fragmented. */
3022 pinfo->fragmented = TRUE;
3024 /* if we are not doing reassembly and this is the first fragment
3025 then just dissect it and exit
3026 XXX - if we're not doing reassembly, can we decrypt an
3029 if( (!dcerpc_reassemble) && hdr->flags&PFC_FIRST_FRAG ){
3032 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
3033 hdr->drep, di, auth_info);
3035 if (check_col(pinfo->cinfo, COL_INFO)) {
3036 col_append_fstr(pinfo->cinfo, COL_INFO,
3037 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
3039 pinfo->fragmented = save_fragmented;
3043 /* if we have already seen this packet, see if it was reassembled
3044 and if so dissect the full pdu.
3047 if(pinfo->fd->flags.visited){
3048 fd_head=fragment_get(pinfo, frame, dcerpc_co_reassemble_table);
3052 /* if we are not doing reassembly and it was neither a complete PDU
3053 nor the first fragment then there is nothing more we can do
3054 so we just have to exit
3056 if( !dcerpc_reassemble )
3059 /* if we didnt get 'frame' we dont know where the PDU started and thus
3060 it is pointless to continue
3065 /* from now on we must attempt to reassemble the PDU
3068 /* if we get here we know it is the first time we see the packet
3069 and we also know it is only a fragment and not a full PDU,
3070 thus we must reassemble it.
3073 /* Do we have any non-encrypted data to reassemble? */
3074 if (decrypted_tvb == NULL) {
3075 /* No. We can't even try to reassemble. */
3079 /* defragmentation is a bit tricky here, as there's no offset of the fragment
3080 * in the protocol data.
3082 * Currently two possible ways:
3083 * - the transmitter sends an alloc_hint != 0, use it
3084 * - the transmitter sends an alloc_hint == 0, simply append fragments
3087 /* if this is the first fragment we need to start reassembly
3089 if(hdr->flags&PFC_FIRST_FRAG){
3090 fragment_add(decrypted_tvb, 0, pinfo, frame, dcerpc_co_reassemble_table,
3091 0, tvb_length(decrypted_tvb), TRUE);
3092 fragment_set_tot_len(pinfo, frame,
3093 dcerpc_co_reassemble_table, alloc_hint ? alloc_hint : tvb_length(decrypted_tvb));
3098 /* if this is a middle fragment, just add it and exit */
3099 if(!(hdr->flags&PFC_LAST_FRAG)){
3100 tot_len = fragment_get_tot_len(pinfo, frame,
3101 dcerpc_co_reassemble_table);
3102 tvb_ensure_bytes_exist(tvb, tot_len-alloc_hint, tvb_length(decrypted_tvb));
3103 fragment_add(decrypted_tvb, 0, pinfo, frame,
3104 dcerpc_co_reassemble_table,
3105 tot_len-alloc_hint, tvb_length(decrypted_tvb),
3107 if(alloc_hint == 0) {
3108 fragment_set_tot_len(pinfo, frame,
3109 dcerpc_co_reassemble_table, tot_len + tvb_length(decrypted_tvb));
3115 /* this was the last fragment add it to reassembly
3117 tot_len = fragment_get_tot_len(pinfo, frame,
3118 dcerpc_co_reassemble_table);
3119 tvb_ensure_bytes_exist(tvb, tot_len-alloc_hint, tvb_length(decrypted_tvb));
3120 fd_head = fragment_add(decrypted_tvb, 0, pinfo,
3122 dcerpc_co_reassemble_table,
3123 tot_len-alloc_hint, tvb_length(decrypted_tvb),
3125 if(alloc_hint == 0) {
3126 fragment_set_tot_len(pinfo, frame,
3127 dcerpc_co_reassemble_table, tot_len + tvb_length(decrypted_tvb));
3132 /* if reassembly is complete, dissect the full PDU
3134 if(fd_head && (fd_head->flags&FD_DEFRAGMENTED) ){
3136 if(pinfo->fd->num==fd_head->reassembled_in){
3138 proto_item *frag_tree_item;
3140 next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
3141 tvb_set_child_real_data_tvbuff(decrypted_tvb, next_tvb);
3142 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3143 show_fragment_tree(fd_head, &dcerpc_frag_items,
3144 dcerpc_tree, pinfo, next_tvb, &frag_tree_item);
3146 pinfo->fragmented = FALSE;
3148 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
3149 next_tvb, hdr->drep, di, auth_info);
3152 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
3153 decrypted_tvb, 0, 0, fd_head->reassembled_in);
3154 PROTO_ITEM_SET_GENERATED(pi);
3155 parent_pi = proto_tree_get_parent(dcerpc_tree);
3156 if(parent_pi != NULL) {
3157 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
3159 if (check_col(pinfo->cinfo, COL_INFO)) {
3160 col_append_fstr(pinfo->cinfo, COL_INFO,
3161 " [DCE/RPC %s fragment, reas: #%u]", fragment_type(hdr->flags), fd_head->reassembled_in);
3165 /* Reassembly not complete - some fragments
3166 are missing. Just show the stub data. */
3167 if (check_col(pinfo->cinfo, COL_INFO)) {
3168 col_append_fstr(pinfo->cinfo, COL_INFO,
3169 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
3173 show_stub_data (decrypted_tvb, 0, tree, auth_info, FALSE);
3175 show_stub_data (payload_tvb, 0, tree, auth_info, TRUE);
3179 pinfo->fragmented = save_fragmented;
3183 * Registers a conversation/UUID binding association, so that
3184 * we can invoke the proper sub-dissector for a given DCERPC
3187 * @param binding all values needed to create and bind a new conversation
3189 * @return Pointer to newly-added UUID/conversation binding.
3191 struct _dcerpc_bind_value *
3192 dcerpc_add_conv_to_bind_table(decode_dcerpc_bind_values_t *binding)
3194 dcerpc_bind_value *bind_value;
3195 dcerpc_bind_key *key;
3196 conversation_t *conv;
3198 conv = find_conversation (
3208 conv = conversation_new (
3218 bind_value = g_mem_chunk_alloc (dcerpc_bind_value_chunk);
3219 bind_value->uuid = binding->uuid;
3220 bind_value->ver = binding->ver;
3222 key = g_mem_chunk_alloc(dcerpc_bind_key_chunk);
3224 key->ctx_id = binding->ctx_id;
3225 key->smb_fid = binding->smb_fid;
3227 /* add this entry to the bind table, first removing any
3228 previous ones that are identical
3230 if(g_hash_table_lookup(dcerpc_binds, key)){
3231 g_hash_table_remove(dcerpc_binds, key);
3233 g_hash_table_insert(dcerpc_binds, key, bind_value);
3240 dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3241 proto_tree *dcerpc_tree, proto_tree *tree,
3242 e_dce_cn_common_hdr_t *hdr)
3244 conversation_t *conv;
3248 dcerpc_auth_info auth_info;
3250 char uuid_str[DCERPC_UUID_STR_LEN];
3253 proto_item *parent_pi;
3255 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3256 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3258 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3259 hf_dcerpc_cn_ctx_id, &ctx_id);
3260 parent_pi = proto_tree_get_parent(dcerpc_tree);
3261 if(parent_pi != NULL) {
3262 proto_item_append_text(parent_pi, " Ctx: %u", ctx_id);
3265 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3266 hf_dcerpc_opnum, &opnum);
3268 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3269 pinfo->dcectxid = ctx_id;
3271 if (check_col (pinfo->cinfo, COL_INFO)) {
3272 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u ctx_id: %u",
3276 if (hdr->flags & PFC_OBJECT_UUID) {
3277 /* XXX - use "dissect_ndr_uuid_t()"? */
3278 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id);
3280 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
3281 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3282 obj_id.Data1, obj_id.Data2, obj_id.Data3,
3291 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
3292 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
3293 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
3294 offset, 16, uuid_str, "Object UUID: %s", uuid_str);
3300 * XXX - what if this was set when the connection was set up,
3301 * and we just have a security context?
3303 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3305 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3306 pinfo->srcport, pinfo->destport, 0);
3308 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3310 dcerpc_matched_key matched_key, *new_matched_key;
3311 dcerpc_call_value *value;
3313 /* !!! we can NOT check flags.visited here since this will interact
3314 badly with when SMB handles (i.e. calls the subdissector)
3315 and desegmented pdu's .
3316 Instead we check if this pdu is already in the matched table or not
3318 matched_key.frame = pinfo->fd->num;
3319 matched_key.call_id = hdr->call_id;
3320 value = g_hash_table_lookup(dcerpc_matched, &matched_key);
3322 dcerpc_bind_key bind_key;
3323 dcerpc_bind_value *bind_value;
3326 bind_key.ctx_id=ctx_id;
3327 bind_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3329 if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key)) ){
3330 if(!(hdr->flags&PFC_FIRST_FRAG)){
3331 dcerpc_cn_call_key call_key;
3332 dcerpc_call_value *call_value;
3335 call_key.call_id=hdr->call_id;
3336 call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3337 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3338 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3339 *new_matched_key = matched_key;
3340 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3344 dcerpc_cn_call_key *call_key;
3345 dcerpc_call_value *call_value;
3347 /* We found the binding and it is the first fragment
3348 (or a complete PDU) of a dcerpc pdu so just add
3349 the call to both the call table and the
3352 call_key=g_mem_chunk_alloc (dcerpc_cn_call_key_chunk);
3353 call_key->conv=conv;
3354 call_key->call_id=hdr->call_id;
3355 call_key->smb_fid=dcerpc_get_transport_salt(pinfo);
3357 /* if there is already a matching call in the table
3358 remove it so it is replaced with the new one */
3359 if(g_hash_table_lookup(dcerpc_cn_calls, call_key)){
3360 g_hash_table_remove(dcerpc_cn_calls, call_key);
3363 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
3364 call_value->uuid = bind_value->uuid;
3365 call_value->ver = bind_value->ver;
3366 call_value->opnum = opnum;
3367 call_value->req_frame=pinfo->fd->num;
3368 call_value->req_time.secs=pinfo->fd->abs_secs;
3369 call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000;
3370 call_value->rep_frame=0;
3371 call_value->max_ptr=0;
3372 call_value->private_data = NULL;
3373 g_hash_table_insert (dcerpc_cn_calls, call_key, call_value);
3375 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3376 *new_matched_key = matched_key;
3377 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3387 /* handoff this call */
3389 di->call_id = hdr->call_id;
3390 di->smb_fid = dcerpc_get_transport_salt(pinfo);
3391 di->ptype = PDU_REQ;
3392 di->call_data = value;
3395 if(value->rep_frame!=0){
3396 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
3397 tvb, 0, 0, value->rep_frame);
3398 PROTO_ITEM_SET_GENERATED(pi);
3399 if(parent_pi != NULL) {
3400 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
3404 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
3405 hdr, di, &auth_info, alloc_hint,
3408 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3411 /* Dissect the verifier */
3412 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
3417 dissect_dcerpc_cn_resp (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3418 proto_tree *dcerpc_tree, proto_tree *tree,
3419 e_dce_cn_common_hdr_t *hdr)
3421 dcerpc_call_value *value = NULL;
3422 conversation_t *conv;
3424 dcerpc_auth_info auth_info;
3427 proto_item *parent_pi;
3429 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3430 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3432 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3433 hf_dcerpc_cn_ctx_id, &ctx_id);
3434 parent_pi = proto_tree_get_parent(dcerpc_tree);
3435 if(parent_pi != NULL) {
3436 proto_item_append_text(parent_pi, " Ctx: %u", ctx_id);
3439 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3440 pinfo->dcectxid = ctx_id;
3442 if (check_col (pinfo->cinfo, COL_INFO)) {
3443 col_append_fstr (pinfo->cinfo, COL_INFO, " ctx_id: %u", ctx_id);
3446 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3447 hf_dcerpc_cn_cancel_count, NULL);
3452 * XXX - what if this was set when the connection was set up,
3453 * and we just have a security context?
3455 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3457 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3458 pinfo->srcport, pinfo->destport, 0);
3461 /* no point in creating one here, really */
3462 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3464 dcerpc_matched_key matched_key, *new_matched_key;
3466 /* !!! we can NOT check flags.visited here since this will interact
3467 badly with when SMB handles (i.e. calls the subdissector)
3468 and desegmented pdu's .
3469 Instead we check if this pdu is already in the matched table or not
3471 matched_key.frame = pinfo->fd->num;
3472 matched_key.call_id = hdr->call_id;
3473 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3475 dcerpc_cn_call_key call_key;
3476 dcerpc_call_value *call_value;
3479 call_key.call_id=hdr->call_id;
3480 call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3482 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3483 /* extra sanity check, only match them if the reply
3484 came after the request */
3485 if(call_value->req_frame<pinfo->fd->num){
3486 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3487 *new_matched_key = matched_key;
3488 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3490 if(call_value->rep_frame==0){
3491 call_value->rep_frame=pinfo->fd->num;
3501 /* handoff this call */
3503 di->call_id = hdr->call_id;
3504 di->smb_fid = dcerpc_get_transport_salt(pinfo);
3505 di->ptype = PDU_RESP;
3506 di->call_data = value;
3508 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
3509 if(value->req_frame!=0){
3511 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3512 tvb, 0, 0, value->req_frame);
3513 PROTO_ITEM_SET_GENERATED(pi);
3514 if(parent_pi != NULL) {
3515 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
3517 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
3518 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
3520 ns.nsecs+=1000000000;
3523 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
3524 PROTO_ITEM_SET_GENERATED(pi);
3527 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
3528 hdr, di, &auth_info, alloc_hint,
3531 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3534 /* Dissect the verifier */
3535 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
3539 dissect_dcerpc_cn_fault (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3540 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
3542 dcerpc_call_value *value = NULL;
3543 conversation_t *conv;
3547 dcerpc_auth_info auth_info;
3550 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3551 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3553 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3554 hf_dcerpc_cn_ctx_id, &ctx_id);
3556 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3557 hf_dcerpc_cn_cancel_count, NULL);
3561 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3562 hf_dcerpc_cn_status, &status);
3564 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3565 pinfo->dcectxid = ctx_id;
3567 if (check_col (pinfo->cinfo, COL_INFO)) {
3568 col_append_fstr (pinfo->cinfo, COL_INFO,
3569 " ctx_id: %u status: %s", ctx_id,
3570 val_to_str(status, reject_status_vals,
3571 "Unknown (0x%08x)"));
3578 * XXX - what if this was set when the connection was set up,
3579 * and we just have a security context?
3581 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3583 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3584 pinfo->srcport, pinfo->destport, 0);
3586 /* no point in creating one here, really */
3588 dcerpc_matched_key matched_key, *new_matched_key;
3590 /* !!! we can NOT check flags.visited here since this will interact
3591 badly with when SMB handles (i.e. calls the subdissector)
3592 and desegmented pdu's .
3593 Instead we check if this pdu is already in the matched table or not
3595 matched_key.frame = pinfo->fd->num;
3596 matched_key.call_id = hdr->call_id;
3597 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3599 dcerpc_cn_call_key call_key;
3600 dcerpc_call_value *call_value;
3603 call_key.call_id=hdr->call_id;
3604 call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3606 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3607 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3608 *new_matched_key = matched_key;
3609 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3611 if(call_value->rep_frame==0){
3612 call_value->rep_frame=pinfo->fd->num;
3619 int length, reported_length, stub_length;
3621 proto_item *parent_pi;
3624 /* handoff this call */
3626 di->call_id = hdr->call_id;
3627 di->smb_fid = dcerpc_get_transport_salt(pinfo);
3628 di->ptype = PDU_FAULT;
3629 di->call_data = value;
3631 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
3632 if(value->req_frame!=0){
3634 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3635 tvb, 0, 0, value->req_frame);
3636 PROTO_ITEM_SET_GENERATED(pi);
3637 parent_pi = proto_tree_get_parent(dcerpc_tree);
3638 if(parent_pi != NULL) {
3639 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
3641 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
3642 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
3644 ns.nsecs+=1000000000;
3647 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
3648 PROTO_ITEM_SET_GENERATED(pi);
3651 length = tvb_length_remaining(tvb, offset);
3652 reported_length = tvb_reported_length_remaining(tvb, offset);
3653 stub_length = hdr->frag_len - offset - auth_info.auth_size;
3654 if (length > stub_length)
3655 length = stub_length;
3656 if (reported_length > stub_length)
3657 reported_length = stub_length;
3659 /* If we don't have reassembly enabled, or this packet contains
3660 the entire PDU, or if we don't have all the data in this
3661 fragment, just call the handoff directly if this is the
3662 first fragment or the PDU isn't fragmented. */
3663 if( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
3664 !tvb_bytes_exist(tvb, offset, stub_length) ){
3665 if(hdr->flags&PFC_FIRST_FRAG){
3666 /* First fragment, possibly the only fragment */
3668 * XXX - should there be a third routine for each
3669 * function in an RPC subdissector, to handle
3670 * fault responses? The DCE RPC 1.1 spec says
3671 * three's "stub data" here, which I infer means
3672 * that it's protocol-specific and call-specific.
3674 * It should probably get passed the status code
3675 * as well, as that might be protocol-specific.
3678 if (stub_length > 0) {
3679 tvb_ensure_bytes_exist(tvb, offset, stub_length);
3680 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3681 "Fault stub data (%d byte%s)",
3683 plurality(stub_length, "", "s"));
3687 /* PDU is fragmented and this isn't the first fragment */
3688 if (check_col(pinfo->cinfo, COL_INFO)) {
3689 col_append_fstr(pinfo->cinfo, COL_INFO,
3690 " [DCE/RPC fragment]");
3693 if (stub_length > 0) {
3694 tvb_ensure_bytes_exist(tvb, offset, stub_length);
3695 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3696 "Fragment data (%d byte%s)",
3698 plurality(stub_length, "", "s"));
3703 /* Reassembly is enabled, the PDU is fragmented, and
3704 we have all the data in the fragment; the first two
3705 of those mean we should attempt reassembly, and the
3706 third means we can attempt reassembly. */
3709 tvb_ensure_bytes_exist(tvb, offset, stub_length);
3710 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3711 "Fragment data (%d byte%s)",
3713 plurality(stub_length, "", "s"));
3716 if(hdr->flags&PFC_FIRST_FRAG){ /* FIRST fragment */
3717 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
3718 fragment_add(tvb, offset, pinfo, value->rep_frame,
3719 dcerpc_co_reassemble_table,
3723 fragment_set_tot_len(pinfo, value->rep_frame,
3724 dcerpc_co_reassemble_table, alloc_hint);
3726 if (check_col(pinfo->cinfo, COL_INFO)) {
3727 col_append_fstr(pinfo->cinfo, COL_INFO,
3728 " [DCE/RPC fragment]");
3730 } else if(hdr->flags&PFC_LAST_FRAG){ /* LAST fragment */
3731 if( value->rep_frame ){
3732 fragment_data *fd_head;
3735 tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
3736 dcerpc_co_reassemble_table);
3737 fd_head = fragment_add(tvb, offset, pinfo,
3739 dcerpc_co_reassemble_table,
3745 /* We completed reassembly */
3747 proto_item *frag_tree_item;
3749 next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
3750 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
3751 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3752 show_fragment_tree(fd_head, &dcerpc_frag_items,
3753 dcerpc_tree, pinfo, next_tvb, &frag_tree_item);
3756 * XXX - should there be a third routine for each
3757 * function in an RPC subdissector, to handle
3758 * fault responses? The DCE RPC 1.1 spec says
3759 * three's "stub data" here, which I infer means
3760 * that it's protocol-specific and call-specific.
3762 * It should probably get passed the status code
3763 * as well, as that might be protocol-specific.
3767 tvb_ensure_bytes_exist(tvb, offset, stub_length);
3768 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3769 "Fault stub data (%d byte%s)",
3771 plurality(stub_length, "", "s"));
3775 /* Reassembly not complete - some fragments
3777 if (check_col(pinfo->cinfo, COL_INFO)) {
3778 col_append_fstr(pinfo->cinfo, COL_INFO,
3779 " [DCE/RPC fragment]");
3783 } else { /* MIDDLE fragment(s) */
3784 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
3786 tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
3787 dcerpc_co_reassemble_table);
3788 fragment_add(tvb, offset, pinfo, value->rep_frame,
3789 dcerpc_co_reassemble_table,
3794 if (check_col(pinfo->cinfo, COL_INFO)) {
3795 col_append_fstr(pinfo->cinfo, COL_INFO,
3796 " [DCE/RPC fragment]");
3805 * DCERPC dissector for connection oriented calls.
3806 * We use transport type to later multiplex between what kind of
3807 * pinfo->private_data structure to expect.
3810 dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
3811 proto_tree *tree, gboolean can_desegment, int *pkt_len)
3813 static const guint8 nulls[4] = { 0 };
3816 proto_item *ti = NULL;
3817 proto_item *tf = NULL;
3818 proto_tree *dcerpc_tree = NULL;
3819 proto_tree *cn_flags_tree = NULL;
3820 proto_tree *drep_tree = NULL;
3821 e_dce_cn_common_hdr_t hdr;
3822 dcerpc_auth_info auth_info;
3825 * when done over nbt, dcerpc requests are padded with 4 bytes of null
3826 * data for some reason.
3828 * XXX - if that's always the case, the right way to do this would
3829 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
3830 * the 4 bytes of null padding, and make that the dissector
3831 * used for "netbios".
3833 if (tvb_memeql (tvb, offset, nulls, 4) == 0) {
3843 * Check if this looks like a C/O DCERPC call
3845 if (!tvb_bytes_exist (tvb, offset, sizeof (hdr))) {
3846 return FALSE; /* not enough information to check */
3848 start_offset = offset;
3849 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
3850 if (hdr.rpc_ver != 5)
3852 hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
3853 if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
3855 hdr.ptype = tvb_get_guint8 (tvb, offset++);
3859 hdr.flags = tvb_get_guint8 (tvb, offset++);
3860 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
3861 offset += sizeof (hdr.drep);
3863 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3865 hdr.auth_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3867 hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3870 if (check_col (pinfo->cinfo, COL_DCE_CALL)) {
3871 col_append_fstr (pinfo->cinfo, COL_DCE_CALL, "%u", hdr.call_id);
3874 if (can_desegment && pinfo->can_desegment
3875 && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
3876 pinfo->desegment_offset = start_offset;
3877 pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, start_offset);
3878 *pkt_len = 0; /* desegmentation required */
3882 if (check_col (pinfo->cinfo, COL_PROTOCOL))
3883 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
3885 if (check_col (pinfo->cinfo, COL_INFO)) {
3886 if(pinfo->dcectxid != 0) {
3887 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
3888 * append a delimiter and set a column fence */
3889 col_append_str (pinfo->cinfo, COL_INFO, " # ");
3890 col_set_fence(pinfo->cinfo,COL_INFO);
3892 col_add_fstr (pinfo->cinfo, COL_INFO, "%s: call_id: %u",
3893 pckt_vals[hdr.ptype].strptr, hdr.call_id);
3897 offset = start_offset;
3898 tvb_ensure_bytes_exist(tvb, offset, hdr.frag_len);
3899 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE);
3901 dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
3903 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver);
3904 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset++, 1, hdr.rpc_ver_minor);
3905 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype);
3906 proto_item_append_text(ti, " %s, Fragment:", val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"));
3908 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
3909 cn_flags_tree = proto_item_add_subtree (tf, ett_dcerpc_cn_flags);
3910 if (cn_flags_tree) {
3911 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
3912 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
3913 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
3914 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
3915 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
3916 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
3917 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
3918 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
3919 if( (hdr.flags & PFC_FIRST_FRAG) && (hdr.flags & PFC_LAST_FRAG) ) {
3920 proto_item_append_text(ti, " Single");
3922 if(hdr.flags & PFC_FIRST_FRAG) {
3923 proto_item_append_text(ti, " 1st");
3925 if(hdr.flags & PFC_LAST_FRAG) {
3926 proto_item_append_text(ti, " Last");
3928 if( !(hdr.flags & PFC_FIRST_FRAG) && !(hdr.flags & PFC_LAST_FRAG) ) {
3929 proto_item_append_text(ti, " Mid");
3935 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
3936 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
3938 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
3939 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
3940 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
3942 offset += sizeof (hdr.drep);
3944 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
3947 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
3950 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
3953 proto_item_append_text(ti, ", FragLen: %u, Call: %u", hdr.frag_len, hdr.call_id);
3957 * None of the stuff done above should throw an exception, because
3958 * we would have rejected this as "not DCE RPC" if we didn't have all
3959 * of it. (XXX - perhaps we should request reassembly if we have
3960 * enough of the header to consider it DCE RPC but not enough to
3961 * get the fragment length; in that case the stuff still wouldn't
3962 * throw an exception.)
3964 * The rest of the stuff might, so return the PDU length to our caller.
3965 * XXX - should we construct a tvbuff containing only the PDU and
3966 * use that? Or should we have separate "is this a DCE RPC PDU",
3967 * "how long is it", and "dissect it" routines - which might let us
3968 * do most of the work in "tcp_dissect_pdus()"?
3970 if (pkt_len != NULL)
3971 *pkt_len = hdr.frag_len + padding;
3974 * Packet type specific stuff is next.
3976 switch (hdr.ptype) {
3979 dissect_dcerpc_cn_bind (tvb, offset, pinfo, dcerpc_tree, &hdr);
3984 dissect_dcerpc_cn_bind_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3989 * Nothing after the common header other than credentials.
3991 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, TRUE,
3996 dissect_dcerpc_cn_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
4000 dissect_dcerpc_cn_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
4004 dissect_dcerpc_cn_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
4008 dissect_dcerpc_cn_bind_nak (tvb, offset, pinfo, dcerpc_tree, &hdr);
4014 * Nothing after the common header other than an authentication
4017 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
4023 * Nothing after the common header, not even an authentication
4029 /* might as well dissect the auth info */
4030 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
4038 * DCERPC dissector for connection oriented calls over packet-oriented
4042 dissect_dcerpc_cn_pk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4045 * Only one PDU per transport packet, and only one transport
4048 pinfo->dcetransporttype=DCE_TRANSPORT_UNKNOWN;
4049 if (!dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE, NULL)) {
4051 * It wasn't a DCERPC PDU.
4063 * DCERPC dissector for connection oriented calls over byte-stream
4065 * we need to distinguish here between SMB and non-TCP (more in the future?)
4066 * to be able to know what kind of private_data structure to expect.
4069 dissect_dcerpc_cn_bs_body (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4071 volatile int offset = 0;
4073 volatile gboolean dcerpc_pdus = 0;
4074 volatile gboolean ret = FALSE;
4077 * There may be multiple PDUs per transport packet; keep
4080 while (tvb_reported_length_remaining(tvb, offset) != 0) {
4082 * Catch ReportedBoundsError, so that even if the stub data is bad,
4083 * we don't abort the full DCE RPC dissection - there might be more
4084 * than one DCE RPC PDU in the data being dissected.
4086 * If we get BoundsError, it means the frame was cut short by a
4087 * snapshot length, so there's nothing more to dissect; just
4088 * re-throw that exception.
4092 if(dissect_dcerpc_cn (tvb, offset, pinfo, tree,
4093 dcerpc_cn_desegment, &pdu_len)) {
4096 } CATCH(BoundsError) {
4098 } CATCH(ReportedBoundsError) {
4099 show_reported_bounds_error(tvb, pinfo, tree);
4110 * Well, we've seen at least one DCERPC PDU.
4114 /* if we had more than one Req/Resp in this PDU change the protocol column */
4115 /* this will formerly contain the last interface name, which may not be the same for all Req/Resp */
4116 if (dcerpc_pdus >= 2 && check_col (pinfo->cinfo, COL_PROTOCOL))
4117 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "%u*DCERPC", dcerpc_pdus);
4121 * Desegmentation required - bail now, but give the user a hint that desegmentation might be done later.
4123 proto_tree_add_uint_format(tree, hf_dcerpc_cn_deseg_req, tvb, offset,
4124 tvb_reported_length_remaining(tvb, offset),
4125 tvb_reported_length_remaining(tvb, offset),
4126 "[DCE RPC: %u byte%s left, desegmentation might follow]",
4127 tvb_reported_length_remaining(tvb, offset),
4128 plurality(tvb_reported_length_remaining(tvb, offset), "", "s"));
4133 * Step to the next PDU.
4141 dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4143 pinfo->dcetransporttype=DCE_TRANSPORT_UNKNOWN;
4144 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
4148 dissect_dcerpc_cn_smbpipe (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4150 pinfo->dcetransporttype=DCE_CN_TRANSPORT_SMBPIPE;
4151 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
4157 dissect_dcerpc_dg_auth (tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
4158 e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
4160 proto_item *ti = NULL;
4161 proto_tree *auth_tree = NULL;
4162 guint8 protection_level;
4165 * Initially set "*auth_level_p" to -1 to indicate that we haven't
4166 * yet seen any authentication level information.
4168 if (auth_level_p != NULL)
4172 * The authentication information is at the *end* of the PDU; in
4173 * request and response PDUs, the request and response stub data
4176 * If the full packet is here, and there's data past the end of the
4177 * packet body, then dissect the auth info.
4179 offset += hdr->frag_len;
4180 if (tvb_length_remaining(tvb, offset) > 0) {
4181 switch (hdr->auth_proto) {
4183 case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
4184 ti = proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Kerberos authentication verifier");
4185 auth_tree = proto_item_add_subtree (ti, ett_dcerpc_krb5_auth_verf);
4186 protection_level = tvb_get_guint8 (tvb, offset);
4187 if (auth_level_p != NULL)
4188 *auth_level_p = protection_level;
4189 proto_tree_add_uint (auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
4191 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, FALSE);
4193 if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
4194 offset += 6; /* 6 bytes of padding */
4196 offset += 2; /* 6 bytes of padding */
4197 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, FALSE);
4202 proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Authentication verifier");
4209 dissect_dcerpc_dg_cancel_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
4210 proto_tree *dcerpc_tree,
4211 e_dce_dg_common_hdr_t *hdr)
4215 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4216 hdr->drep, hf_dcerpc_dg_cancel_vers,
4222 /* The only version we know about */
4223 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4224 hdr->drep, hf_dcerpc_dg_cancel_id,
4226 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
4227 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
4234 dissect_dcerpc_dg_cancel (tvbuff_t *tvb, int offset, packet_info *pinfo,
4235 proto_tree *dcerpc_tree,
4236 e_dce_dg_common_hdr_t *hdr)
4240 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4241 hdr->drep, hf_dcerpc_dg_cancel_vers,
4247 /* The only version we know about */
4248 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4249 hdr->drep, hf_dcerpc_dg_cancel_id,
4251 /* XXX - are NDR booleans 32 bits? */
4253 /* XXX - the RPC reference in chapter: "the cancel PDU" doesn't mention
4254 the accepting_cancels field (it's only in the cancel_ack PDU)! */
4255 /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4256 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
4263 dissect_dcerpc_dg_fack (tvbuff_t *tvb, int offset, packet_info *pinfo,
4264 proto_tree *dcerpc_tree,
4265 e_dce_dg_common_hdr_t *hdr)
4272 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
4273 hdr->drep, hf_dcerpc_dg_fack_vers,
4280 case 0: /* The only version documented in the DCE RPC 1.1 spec */
4281 case 1: /* This appears to be the same */
4282 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
4283 hdr->drep, hf_dcerpc_dg_fack_window_size,
4285 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4286 hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
4288 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4289 hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
4291 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
4292 hdr->drep, hf_dcerpc_dg_fack_serial_num,
4294 if (check_col (pinfo->cinfo, COL_INFO)) {
4295 col_append_fstr (pinfo->cinfo, COL_INFO, " serial: %u",
4298 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
4299 hdr->drep, hf_dcerpc_dg_fack_selack_len,
4301 for (i = 0; i < selack_len; i++) {
4302 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4303 hdr->drep, hf_dcerpc_dg_fack_selack,
4312 dissect_dcerpc_dg_reject_fault (tvbuff_t *tvb, int offset, packet_info *pinfo,
4313 proto_tree *dcerpc_tree,
4314 e_dce_dg_common_hdr_t *hdr)
4318 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4319 hdr->drep, hf_dcerpc_dg_status,
4322 if (check_col (pinfo->cinfo, COL_INFO)) {
4323 col_append_fstr (pinfo->cinfo, COL_INFO,
4325 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
4330 dissect_dcerpc_dg_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
4331 proto_tree *dcerpc_tree, proto_tree *tree,
4332 e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
4334 int length, reported_length, stub_length;
4335 gboolean save_fragmented;
4336 fragment_data *fd_head;
4339 proto_item *parent_pi;
4341 if (check_col (pinfo->cinfo, COL_INFO))
4342 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u len: %u",
4343 di->call_data->opnum, hdr->frag_len );
4345 length = tvb_length_remaining (tvb, offset);
4346 reported_length = tvb_reported_length_remaining (tvb, offset);
4347 stub_length = hdr->frag_len;
4348 if (length > stub_length)
4349 length = stub_length;
4350 if (reported_length > stub_length)
4351 reported_length = stub_length;
4353 save_fragmented = pinfo->fragmented;
4355 /* If we don't have reassembly enabled, or this packet contains
4356 the entire PDU, or if this is a short frame (or a frame
4357 not reassembled at a lower layer) that doesn't include all
4358 the data in the fragment, just call the handoff directly if
4359 this is the first fragment or the PDU isn't fragmented. */
4360 if( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
4361 !tvb_bytes_exist(tvb, offset, stub_length) ){
4362 if(hdr->frag_num == 0) {
4365 /* First fragment, possibly the only fragment */
4368 * XXX - authentication info?
4370 pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
4371 next_tvb = tvb_new_subset (tvb, offset, length,
4373 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
4374 next_tvb, hdr->drep, di, NULL);
4376 /* PDU is fragmented and this isn't the first fragment */
4377 if (check_col(pinfo->cinfo, COL_INFO)) {
4378 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
4382 tvb_ensure_bytes_exist(tvb, offset, stub_length);
4383 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
4384 "Fragment data (%d byte%s)",
4386 plurality(stub_length, "", "s"));
4391 /* Reassembly is enabled, the PDU is fragmented, and
4392 we have all the data in the fragment; the first two
4393 of those mean we should attempt reassembly, and the
4394 third means we can attempt reassembly. */
4397 tvb_ensure_bytes_exist(tvb, offset, stub_length);
4398 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
4399 "Fragment data (%d byte%s)", stub_length,
4400 plurality(stub_length, "", "s"));
4404 fd_head = fragment_add_dcerpc(tvb, offset, pinfo,
4405 hdr->seqnum, &hdr->act_id, dcerpc_cl_reassemble_table,
4406 hdr->frag_num, stub_length,
4407 !(hdr->flags1 & PFCL1_LASTFRAG));
4408 if (fd_head != NULL) {
4409 /* We completed reassembly... */
4410 if(pinfo->fd->num==fd_head->reassembled_in) {
4411 /* ...and this is the reassembled RPC PDU */
4412 next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
4413 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
4414 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
4415 show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
4416 tree, pinfo, next_tvb, &pi);
4419 * XXX - authentication info?
4421 pinfo->fragmented = FALSE;
4422 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
4423 next_tvb, hdr->drep, di, NULL);
4425 /* ...and this isn't the reassembled RPC PDU */
4426 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
4427 tvb, 0, 0, fd_head->reassembled_in);
4428 PROTO_ITEM_SET_GENERATED(pi);
4429 parent_pi = proto_tree_get_parent(dcerpc_tree);
4430 if(parent_pi != NULL) {
4431 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
4433 if (check_col(pinfo->cinfo, COL_INFO)) {
4434 col_append_fstr(pinfo->cinfo, COL_INFO,
4435 " [DCE/RPC fragment, reas: #%u]", fd_head->reassembled_in);
4439 /* Reassembly isn't completed yet */
4440 if (check_col(pinfo->cinfo, COL_INFO)) {
4441 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
4445 pinfo->fragmented = save_fragmented;
4449 dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo,
4450 proto_tree *dcerpc_tree, proto_tree *tree,
4451 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4454 dcerpc_call_value *value, v;
4455 dcerpc_matched_key matched_key, *new_matched_key;
4457 proto_item *parent_pi;
4460 if(!(pinfo->fd->flags.visited)){
4461 dcerpc_call_value *call_value;
4462 dcerpc_dg_call_key *call_key;
4464 call_key=g_mem_chunk_alloc (dcerpc_dg_call_key_chunk);
4465 call_key->conv=conv;
4466 call_key->seqnum=hdr->seqnum;
4467 call_key->act_id=hdr->act_id;
4469 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
4470 call_value->uuid = hdr->if_id;
4471 call_value->ver = hdr->if_ver;
4472 call_value->opnum = hdr->opnum;
4473 call_value->req_frame=pinfo->fd->num;
4474 call_value->req_time.secs=pinfo->fd->abs_secs;
4475 call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000;
4476 call_value->rep_frame=0;
4477 call_value->max_ptr=0;
4478 call_value->private_data = NULL;
4479 g_hash_table_insert (dcerpc_dg_calls, call_key, call_value);
4481 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
4482 new_matched_key->frame = pinfo->fd->num;
4483 new_matched_key->call_id = hdr->seqnum;
4484 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
4487 matched_key.frame = pinfo->fd->num;
4488 matched_key.call_id = hdr->seqnum;
4489 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
4491 v.uuid = hdr->if_id;
4492 v.ver = hdr->if_ver;
4493 v.opnum = hdr->opnum;
4494 v.req_frame = pinfo->fd->num;
4497 v.private_data=NULL;
4502 di->call_id = hdr->seqnum;
4504 di->ptype = PDU_REQ;
4505 di->call_data = value;
4507 if(value->rep_frame!=0){
4508 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
4509 tvb, 0, 0, value->rep_frame);
4510 PROTO_ITEM_SET_GENERATED(pi);
4511 parent_pi = proto_tree_get_parent(dcerpc_tree);
4512 if(parent_pi != NULL) {
4513 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
4516 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
4520 dissect_dcerpc_dg_resp (tvbuff_t *tvb, int offset, packet_info *pinfo,
4521 proto_tree *dcerpc_tree, proto_tree *tree,
4522 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4525 dcerpc_call_value *value, v;
4526 dcerpc_matched_key matched_key, *new_matched_key;
4528 proto_item *parent_pi;
4531 if(!(pinfo->fd->flags.visited)){
4532 dcerpc_call_value *call_value;
4533 dcerpc_dg_call_key call_key;
4536 call_key.seqnum=hdr->seqnum;
4537 call_key.act_id=hdr->act_id;
4539 if((call_value=g_hash_table_lookup(dcerpc_dg_calls, &call_key))){
4540 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
4541 new_matched_key->frame = pinfo->fd->num;
4542 new_matched_key->call_id = hdr->seqnum;
4543 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
4544 if(call_value->rep_frame==0){
4545 call_value->rep_frame=pinfo->fd->num;
4550 matched_key.frame = pinfo->fd->num;
4551 matched_key.call_id = hdr->seqnum;
4552 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
4554 v.uuid = hdr->if_id;
4555 v.ver = hdr->if_ver;
4556 v.opnum = hdr->opnum;
4558 v.rep_frame=pinfo->fd->num;
4559 v.private_data=NULL;
4566 di->ptype = PDU_RESP;
4567 di->call_data = value;
4569 if(value->req_frame!=0){
4571 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4572 tvb, 0, 0, value->req_frame);
4573 PROTO_ITEM_SET_GENERATED(pi);
4574 parent_pi = proto_tree_get_parent(dcerpc_tree);
4575 if(parent_pi != NULL) {
4576 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
4578 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
4579 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
4581 ns.nsecs+=1000000000;
4584 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
4585 PROTO_ITEM_SET_GENERATED(pi);
4587 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
4591 dissect_dcerpc_dg_ping_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
4592 proto_tree *dcerpc_tree, proto_tree *tree,
4593 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4595 proto_item *parent_pi;
4596 /* if(!(pinfo->fd->flags.visited)){*/
4597 dcerpc_call_value *call_value;
4598 dcerpc_dg_call_key call_key;
4601 call_key.seqnum=hdr->seqnum;
4602 call_key.act_id=hdr->act_id;
4604 if((call_value=g_hash_table_lookup(dcerpc_dg_calls, &call_key))){
4608 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4609 tvb, 0, 0, call_value->req_frame);
4610 PROTO_ITEM_SET_GENERATED(pi);
4611 parent_pi = proto_tree_get_parent(dcerpc_tree);
4612 if(parent_pi != NULL) {
4613 proto_item_append_text(parent_pi, ", [Req: #%u]", call_value->req_frame);
4616 if (check_col (pinfo->cinfo, COL_INFO))
4617 col_append_fstr(pinfo->cinfo, COL_INFO, " [req: #%u]", call_value->req_frame);
4619 ns.secs= pinfo->fd->abs_secs-call_value->req_time.secs;
4620 ns.nsecs=pinfo->fd->abs_usecs*1000-call_value->req_time.nsecs;
4622 ns.nsecs+=1000000000;
4625 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
4626 PROTO_ITEM_SET_GENERATED(pi);
4632 * DCERPC dissector for connectionless calls
4635 dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4637 proto_item *ti = NULL;
4638 proto_item *tf = NULL;
4639 proto_tree *dcerpc_tree = NULL;
4640 proto_tree *dg_flags1_tree = NULL;
4641 proto_tree *dg_flags2_tree = NULL;
4642 proto_tree *drep_tree = NULL;
4643 e_dce_dg_common_hdr_t hdr;
4645 conversation_t *conv;
4647 char uuid_str[DCERPC_UUID_STR_LEN];
4651 * Check if this looks like a CL DCERPC call. All dg packets
4652 * have an 80 byte header on them. Which starts with
4653 * version (4), pkt_type.
4655 if (!tvb_bytes_exist (tvb, 0, sizeof (hdr))) {
4659 /* Version must be 4 */
4660 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
4661 if (hdr.rpc_ver != 4)
4664 /* Type must be <=19 or its not DCE/RPC */
4665 hdr.ptype = tvb_get_guint8 (tvb, offset++);
4669 /* flags1 has bit 1 and 8 as reserved so if any of them are set, it is
4670 probably not a DCE/RPC packet
4672 hdr.flags1 = tvb_get_guint8 (tvb, offset++);
4676 /* flags2 has all bits except bit 2 as reserved so if any of them are set
4677 it is probably not DCE/RPC.
4679 hdr.flags2 = tvb_get_guint8 (tvb, offset++);
4684 if (check_col (pinfo->cinfo, COL_PROTOCOL))
4685 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
4686 if (check_col (pinfo->cinfo, COL_INFO))
4687 col_add_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
4689 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
4690 offset += sizeof (hdr.drep);
4691 hdr.serial_hi = tvb_get_guint8 (tvb, offset++);
4692 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.obj_id);
4694 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.if_id);
4696 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.act_id);
4698 hdr.server_boot = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4700 hdr.if_ver = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4702 hdr.seqnum = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4704 hdr.opnum = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4706 hdr.ihint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4708 hdr.ahint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4710 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4712 hdr.frag_num = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4714 hdr.auth_proto = tvb_get_guint8 (tvb, offset++);
4715 hdr.serial_lo = tvb_get_guint8 (tvb, offset++);
4718 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, -1, FALSE);
4720 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
4721 proto_item_append_text(ti, " %s, Seq: %u, Serial: %u, Frag: %u, FragLen: %u",
4722 val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"),
4723 hdr.seqnum, hdr.serial_hi*256+hdr.serial_lo,
4724 hdr.frag_num, hdr.frag_len);
4730 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
4734 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
4738 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
4739 dg_flags1_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags1);
4740 if (dg_flags1_tree) {
4741 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
4742 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
4743 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
4744 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
4745 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
4746 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
4747 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
4748 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
4750 proto_item_append_text(tf, " %s%s%s%s%s%s",
4751 (hdr.flags1 & PFCL1_BROADCAST) ? "\"Broadcast\" " : "",
4752 (hdr.flags1 & PFCL1_IDEMPOTENT) ? "\"Idempotent\" " : "",
4753 (hdr.flags1 & PFCL1_MAYBE) ? "\"Maybe\" " : "",
4754 (hdr.flags1 & PFCL1_NOFACK) ? "\"No Fack\" " : "",
4755 (hdr.flags1 & PFCL1_FRAG) ? "\"Fragment\" " : "",
4756 (hdr.flags1 & PFCL1_LASTFRAG) ? "\"Last Fragment\" " : "");
4763 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
4764 dg_flags2_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags2);
4765 if (dg_flags2_tree) {
4766 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
4767 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
4768 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
4769 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
4770 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
4771 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
4772 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
4773 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
4775 proto_item_append_text(tf, " %s",
4776 (hdr.flags2 & PFCL2_CANCEL_PENDING) ? "\"Cancel Pending\" " : "");
4783 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
4784 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
4786 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
4787 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
4788 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
4789 proto_item_append_text(tf, " (Order: %s, Char: %s, Float: %s)",
4790 val_to_str(hdr.drep[0] >> 4, drep_byteorder_vals, "Unknown"),
4791 val_to_str(hdr.drep[0] & 0x0f, drep_character_vals, "Unknown"),
4792 val_to_str(hdr.drep[1], drep_fp_vals, "Unknown"));
4795 offset += sizeof (hdr.drep);
4798 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
4802 /* XXX - use "dissect_ndr_uuid_t()"? */
4803 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
4804 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
4805 hdr.obj_id.Data1, hdr.obj_id.Data2, hdr.obj_id.Data3,
4806 hdr.obj_id.Data4[0],
4807 hdr.obj_id.Data4[1],
4808 hdr.obj_id.Data4[2],
4809 hdr.obj_id.Data4[3],
4810 hdr.obj_id.Data4[4],
4811 hdr.obj_id.Data4[5],
4812 hdr.obj_id.Data4[6],
4813 hdr.obj_id.Data4[7]);
4814 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
4815 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
4816 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
4817 offset, 16, uuid_str, "Object UUID: %s", uuid_str);
4822 /* XXX - use "dissect_ndr_uuid_t()"? */
4823 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
4824 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
4825 hdr.if_id.Data1, hdr.if_id.Data2, hdr.if_id.Data3,
4833 hdr.if_id.Data4[7]);
4834 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
4835 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
4836 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
4837 offset, 16, uuid_str, "Interface: %s", uuid_str);
4842 /* XXX - use "dissect_ndr_uuid_t()"? */
4843 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
4844 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
4845 hdr.act_id.Data1, hdr.act_id.Data2, hdr.act_id.Data3,
4846 hdr.act_id.Data4[0],
4847 hdr.act_id.Data4[1],
4848 hdr.act_id.Data4[2],
4849 hdr.act_id.Data4[3],
4850 hdr.act_id.Data4[4],
4851 hdr.act_id.Data4[5],
4852 hdr.act_id.Data4[6],
4853 hdr.act_id.Data4[7]);
4854 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
4855 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
4856 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
4857 offset, 16, uuid_str, "Activity: %s", uuid_str);
4862 nstime_t server_boot;
4864 server_boot.secs = hdr.server_boot;
4865 server_boot.nsecs = 0;
4867 if (hdr.server_boot == 0)
4868 proto_tree_add_time_format (dcerpc_tree, hf_dcerpc_dg_server_boot,
4869 tvb, offset, 4, &server_boot,
4870 "Server boot time: Unknown (0)");
4872 proto_tree_add_time (dcerpc_tree, hf_dcerpc_dg_server_boot,
4873 tvb, offset, 4, &server_boot);
4878 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
4882 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
4883 if (check_col (pinfo->cinfo, COL_INFO)) {
4884 col_append_fstr (pinfo->cinfo, COL_INFO, ": seq: %u", hdr.seqnum);
4886 if (check_col (pinfo->cinfo, COL_DCE_CALL)) {
4887 col_append_fstr (pinfo->cinfo, COL_DCE_CALL, "%u", hdr.seqnum);
4892 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
4896 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
4900 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
4904 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
4908 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
4909 if (check_col (pinfo->cinfo, COL_INFO)) {
4910 if (hdr.flags1 & PFCL1_FRAG) {
4911 /* Fragmented - put the fragment number into the Info column */
4912 col_append_fstr (pinfo->cinfo, COL_INFO, " frag: %u",
4919 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
4923 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
4924 if (check_col (pinfo->cinfo, COL_INFO)) {
4925 if (hdr.flags1 & PFCL1_FRAG) {
4926 /* Fragmented - put the serial number into the Info column */
4927 col_append_fstr (pinfo->cinfo, COL_INFO, " serial: %u",
4928 (hdr.serial_hi << 8) | hdr.serial_lo);
4935 * XXX - for Kerberos, we get a protection level; if it's
4936 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
4939 dissect_dcerpc_dg_auth (tvb, offset, dcerpc_tree, &hdr,
4944 * keeping track of the conversation shouldn't really be necessary
4945 * for connectionless packets, because everything we need to know
4946 * to dissect is in the header for each packet. Unfortunately,
4947 * Microsoft's implementation is buggy and often puts the
4948 * completely wrong if_id in the header. go figure. So, keep
4949 * track of the seqnum and use that if possible. Note: that's not
4950 * completely correct. It should really be done based on both the
4951 * activity_id and seqnum. I haven't seen anywhere that it would
4952 * make a difference, but for future reference...
4954 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
4955 pinfo->srcport, pinfo->destport, 0);
4957 conv = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
4958 pinfo->srcport, pinfo->destport, 0);
4962 * Packet type specific stuff is next.
4965 switch (hdr.ptype) {
4967 case PDU_CANCEL_ACK:
4968 /* Body is optional */
4969 /* XXX - we assume "frag_len" is the length of the body */
4970 if (hdr.frag_len != 0)
4971 dissect_dcerpc_dg_cancel_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
4976 * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
4977 * but in at least one capture none of the Cl_cancel PDUs had a
4980 /* XXX - we assume "frag_len" is the length of the body */
4981 if (hdr.frag_len != 0)
4982 dissect_dcerpc_dg_cancel (tvb, offset, pinfo, dcerpc_tree, &hdr);
4986 /* Body is optional; if present, it's the same as PDU_FACK */
4987 /* XXX - we assume "frag_len" is the length of the body */
4988 if (hdr.frag_len != 0)
4989 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
4993 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
4998 dissect_dcerpc_dg_reject_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
5002 dissect_dcerpc_dg_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
5006 dissect_dcerpc_dg_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
5009 /* these requests have no body */
5012 dissect_dcerpc_dg_ping_ack (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
5023 dcerpc_init_protocol (void)
5025 /* structures and data for BIND */
5027 g_hash_table_destroy (dcerpc_binds);
5031 dcerpc_binds = g_hash_table_new (dcerpc_bind_hash, dcerpc_bind_equal);
5034 if (dcerpc_bind_key_chunk){
5035 g_mem_chunk_destroy (dcerpc_bind_key_chunk);
5037 dcerpc_bind_key_chunk = g_mem_chunk_new ("dcerpc_bind_key_chunk",
5038 sizeof (dcerpc_bind_key),
5039 200 * sizeof (dcerpc_bind_key),
5041 if (dcerpc_bind_value_chunk){
5042 g_mem_chunk_destroy (dcerpc_bind_value_chunk);
5044 dcerpc_bind_value_chunk = g_mem_chunk_new ("dcerpc_bind_value_chunk",
5045 sizeof (dcerpc_bind_value),
5046 200 * sizeof (dcerpc_bind_value),
5048 /* structures and data for CALL */
5049 if (dcerpc_cn_calls){
5050 g_hash_table_destroy (dcerpc_cn_calls);
5052 dcerpc_cn_calls = g_hash_table_new (dcerpc_cn_call_hash, dcerpc_cn_call_equal);
5053 if (dcerpc_dg_calls){
5054 g_hash_table_destroy (dcerpc_dg_calls);
5056 dcerpc_dg_calls = g_hash_table_new (dcerpc_dg_call_hash, dcerpc_dg_call_equal);
5057 if (dcerpc_cn_call_key_chunk){
5058 g_mem_chunk_destroy (dcerpc_cn_call_key_chunk);
5060 dcerpc_cn_call_key_chunk = g_mem_chunk_new ("dcerpc_cn_call_key_chunk",
5061 sizeof (dcerpc_cn_call_key),
5062 200 * sizeof (dcerpc_cn_call_key),
5064 if (dcerpc_dg_call_key_chunk){
5065 g_mem_chunk_destroy (dcerpc_dg_call_key_chunk);
5067 dcerpc_dg_call_key_chunk = g_mem_chunk_new ("dcerpc_dg_call_key_chunk",
5068 sizeof (dcerpc_dg_call_key),
5069 200 * sizeof (dcerpc_dg_call_key),
5072 if (dcerpc_call_value_chunk){
5073 g_mem_chunk_destroy (dcerpc_call_value_chunk);
5075 dcerpc_call_value_chunk = g_mem_chunk_new ("dcerpc_call_value_chunk",
5076 sizeof (dcerpc_call_value),
5077 200 * sizeof (dcerpc_call_value),
5080 /* structure and data for MATCHED */
5081 if (dcerpc_matched){
5082 g_hash_table_destroy (dcerpc_matched);
5084 dcerpc_matched = g_hash_table_new (dcerpc_matched_hash, dcerpc_matched_equal);
5085 if (dcerpc_matched_key_chunk){
5086 g_mem_chunk_destroy (dcerpc_matched_key_chunk);
5088 dcerpc_matched_key_chunk = g_mem_chunk_new ("dcerpc_matched_key_chunk",
5089 sizeof (dcerpc_matched_key),
5090 200 * sizeof (dcerpc_matched_key),
5093 /* call the registered hooks */
5094 g_hook_list_invoke(&dcerpc_hooks_init_protos, FALSE /* not may_recurse */);
5098 proto_register_dcerpc (void)
5100 static hf_register_info hf[] = {
5101 { &hf_dcerpc_request_in,
5102 { "Request in frame", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE,
5103 NULL, 0, "This packet is a response to the packet with this number", HFILL }},
5104 { &hf_dcerpc_response_in,
5105 { "Response in frame", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
5106 NULL, 0, "This packet will be responded in the packet with this number", HFILL }},
5107 { &hf_dcerpc_referent_id,
5108 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
5109 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
5111 { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5112 { &hf_dcerpc_ver_minor,
5113 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5114 { &hf_dcerpc_packet_type,
5115 { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS (pckt_vals), 0x0, "", HFILL }},
5116 { &hf_dcerpc_cn_flags,
5117 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
5118 { &hf_dcerpc_cn_flags_first_frag,
5119 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_FIRST_FRAG, "", HFILL }},
5120 { &hf_dcerpc_cn_flags_last_frag,
5121 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_LAST_FRAG, "", HFILL }},
5122 { &hf_dcerpc_cn_flags_cancel_pending,
5123 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_PENDING_CANCEL, "", HFILL }},
5124 { &hf_dcerpc_cn_flags_reserved,
5125 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_RESERVED_1, "", HFILL }},
5126 { &hf_dcerpc_cn_flags_mpx,
5127 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_CONC_MPX, "", HFILL }},
5128 { &hf_dcerpc_cn_flags_dne,
5129 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_DID_NOT_EXECUTE, "", HFILL }},
5130 { &hf_dcerpc_cn_flags_maybe,
5131 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_MAYBE, "", HFILL }},
5132 { &hf_dcerpc_cn_flags_object,
5133 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_OBJECT_UUID, "", HFILL }},
5135 { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
5136 { &hf_dcerpc_drep_byteorder,
5137 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS (drep_byteorder_vals), 0x0, "", HFILL }},
5138 { &hf_dcerpc_drep_character,
5139 { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS (drep_character_vals), 0x0, "", HFILL }},
5140 { &hf_dcerpc_drep_fp,
5141 { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS (drep_fp_vals), 0x0, "", HFILL }},
5142 { &hf_dcerpc_cn_frag_len,
5143 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5144 { &hf_dcerpc_cn_auth_len,
5145 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5146 { &hf_dcerpc_cn_call_id,
5147 { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5148 { &hf_dcerpc_cn_max_xmit,
5149 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5150 { &hf_dcerpc_cn_max_recv,
5151 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5152 { &hf_dcerpc_cn_assoc_group,
5153 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
5154 { &hf_dcerpc_cn_num_ctx_items,
5155 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5156 { &hf_dcerpc_cn_ctx_id,
5157 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5158 { &hf_dcerpc_cn_num_trans_items,
5159 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5160 { &hf_dcerpc_cn_bind_if_id,
5161 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
5162 { &hf_dcerpc_cn_bind_if_ver,
5163 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5164 { &hf_dcerpc_cn_bind_if_ver_minor,
5165 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5166 { &hf_dcerpc_cn_bind_trans_id,
5167 { "Transfer Syntax", "dcerpc.cn_bind_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
5168 { &hf_dcerpc_cn_bind_trans_ver,
5169 { "Syntax ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5170 { &hf_dcerpc_cn_alloc_hint,
5171 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5172 { &hf_dcerpc_cn_sec_addr_len,
5173 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5174 { &hf_dcerpc_cn_sec_addr,
5175 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, "", HFILL }},
5176 { &hf_dcerpc_cn_num_results,
5177 { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5178 { &hf_dcerpc_cn_ack_result,
5179 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, "", HFILL }},
5180 { &hf_dcerpc_cn_ack_reason,
5181 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, "", HFILL }},
5182 { &hf_dcerpc_cn_ack_trans_id,
5183 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
5184 { &hf_dcerpc_cn_ack_trans_ver,
5185 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5186 { &hf_dcerpc_cn_reject_reason,
5187 { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, "", HFILL }},
5188 { &hf_dcerpc_cn_num_protocols,
5189 { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5190 { &hf_dcerpc_cn_protocol_ver_major,
5191 { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5192 { &hf_dcerpc_cn_protocol_ver_minor,
5193 { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5194 { &hf_dcerpc_cn_cancel_count,
5195 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5196 { &hf_dcerpc_cn_status,
5197 { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
5198 { &hf_dcerpc_cn_deseg_req,
5199 { "Desegmentation Required", "dcerpc.cn_deseg_req", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5200 { &hf_dcerpc_auth_type,
5201 { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
5202 { &hf_dcerpc_auth_level,
5203 { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS (authn_level_vals), 0x0, "", HFILL }},
5204 { &hf_dcerpc_auth_pad_len,
5205 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5206 { &hf_dcerpc_auth_rsrvd,
5207 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5208 { &hf_dcerpc_auth_ctx_id,
5209 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5210 { &hf_dcerpc_dg_flags1,
5211 { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
5212 { &hf_dcerpc_dg_flags1_rsrvd_01,
5213 { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_01, "", HFILL }},
5214 { &hf_dcerpc_dg_flags1_last_frag,
5215 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_LASTFRAG, "", HFILL }},
5216 { &hf_dcerpc_dg_flags1_frag,
5217 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_FRAG, "", HFILL }},
5218 { &hf_dcerpc_dg_flags1_nofack,
5219 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_NOFACK, "", HFILL }},
5220 { &hf_dcerpc_dg_flags1_maybe,
5221 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_MAYBE, "", HFILL }},
5222 { &hf_dcerpc_dg_flags1_idempotent,
5223 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_IDEMPOTENT, "", HFILL }},
5224 { &hf_dcerpc_dg_flags1_broadcast,
5225 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_BROADCAST, "", HFILL }},
5226 { &hf_dcerpc_dg_flags1_rsrvd_80,
5227 { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_80, "", HFILL }},
5228 { &hf_dcerpc_dg_flags2,
5229 { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
5230 { &hf_dcerpc_dg_flags2_rsrvd_01,
5231 { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_01, "", HFILL }},
5232 { &hf_dcerpc_dg_flags2_cancel_pending,
5233 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_CANCEL_PENDING, "", HFILL }},
5234 { &hf_dcerpc_dg_flags2_rsrvd_04,
5235 { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_04, "", HFILL }},
5236 { &hf_dcerpc_dg_flags2_rsrvd_08,
5237 { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_08, "", HFILL }},
5238 { &hf_dcerpc_dg_flags2_rsrvd_10,
5239 { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_10, "", HFILL }},
5240 { &hf_dcerpc_dg_flags2_rsrvd_20,
5241 { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_20, "", HFILL }},
5242 { &hf_dcerpc_dg_flags2_rsrvd_40,
5243 { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_40, "", HFILL }},
5244 { &hf_dcerpc_dg_flags2_rsrvd_80,
5245 { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_80, "", HFILL }},
5246 { &hf_dcerpc_dg_serial_lo,
5247 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
5248 { &hf_dcerpc_dg_serial_hi,
5249 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
5250 { &hf_dcerpc_dg_ahint,
5251 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
5252 { &hf_dcerpc_dg_ihint,
5253 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
5254 { &hf_dcerpc_dg_frag_len,
5255 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5256 { &hf_dcerpc_dg_frag_num,
5257 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5258 { &hf_dcerpc_dg_auth_proto,
5259 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
5260 { &hf_dcerpc_dg_seqnum,
5261 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5262 { &hf_dcerpc_dg_server_boot,
5263 { "Server boot time", "dcerpc.dg_server_boot", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0, "", HFILL }},
5264 { &hf_dcerpc_dg_if_ver,
5265 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5266 { &hf_dcerpc_krb5_av_prot_level,
5267 { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, "", HFILL }},
5268 { &hf_dcerpc_krb5_av_key_vers_num,
5269 { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5270 { &hf_dcerpc_krb5_av_key_auth_verifier,
5271 { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
5272 { &hf_dcerpc_obj_id,
5273 { "Object", "dcerpc.obj_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
5274 { &hf_dcerpc_dg_if_id,
5275 { "Interface", "dcerpc.dg_if_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
5276 { &hf_dcerpc_dg_act_id,
5277 { "Activity", "dcerpc.dg_act_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
5279 { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5281 { &hf_dcerpc_dg_cancel_vers,
5282 { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5284 { &hf_dcerpc_dg_cancel_id,
5285 { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5287 { &hf_dcerpc_dg_server_accepting_cancels,
5288 { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
5290 { &hf_dcerpc_dg_fack_vers,
5291 { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5293 { &hf_dcerpc_dg_fack_window_size,
5294 { "Window Size", "dcerpc.fack_window_size", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5296 { &hf_dcerpc_dg_fack_max_tsdu,
5297 { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5299 { &hf_dcerpc_dg_fack_max_frag_size,
5300 { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5302 { &hf_dcerpc_dg_fack_serial_num,
5303 { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5305 { &hf_dcerpc_dg_fack_selack_len,
5306 { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5308 { &hf_dcerpc_dg_fack_selack,
5309 { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
5311 { &hf_dcerpc_dg_status,
5312 { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
5314 { &hf_dcerpc_array_max_count,
5315 { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
5317 { &hf_dcerpc_array_offset,
5318 { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
5320 { &hf_dcerpc_array_actual_count,
5321 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
5323 { &hf_dcerpc_array_buffer,
5324 { "Buffer", "dcerpc.array.buffer", FT_BYTES, BASE_NONE, NULL, 0x0, "Buffer: Buffer containing elements of the array", HFILL }},
5327 { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5329 { &hf_dcerpc_fragments,
5330 { "Reassembled DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
5331 NULL, 0x0, "DCE/RPC Fragments", HFILL }},
5333 { &hf_dcerpc_fragment,
5334 { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM, BASE_NONE,
5335 NULL, 0x0, "DCE/RPC Fragment", HFILL }},
5337 { &hf_dcerpc_fragment_overlap,
5338 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE,
5339 NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
5341 { &hf_dcerpc_fragment_overlap_conflict,
5342 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE,
5343 NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
5345 { &hf_dcerpc_fragment_multiple_tails,
5346 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE,
5347 NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
5349 { &hf_dcerpc_fragment_too_long_fragment,
5350 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE,
5351 NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
5353 { &hf_dcerpc_fragment_error,
5354 { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE,
5355 NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
5358 { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE,
5359 NULL, 0, "Time between Request and Response for DCE-RPC calls", HFILL }},
5361 { &hf_dcerpc_reassembled_in,
5362 { "Reassembled PDU in frame", "dcerpc.reassembled_in", FT_FRAMENUM, BASE_NONE,
5363 NULL, 0x0, "The DCE/RPC PDU is completely reassembled in the packet with this number", HFILL }},
5365 { &hf_dcerpc_unknown_if_id,
5366 { "Unknown DCERPC interface id", "dcerpc.unknown_if_id", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
5368 static gint *ett[] = {
5370 &ett_dcerpc_cn_flags,
5372 &ett_dcerpc_cn_iface,
5374 &ett_dcerpc_dg_flags1,
5375 &ett_dcerpc_dg_flags2,
5376 &ett_dcerpc_pointer_data,
5378 &ett_dcerpc_fragments,
5379 &ett_dcerpc_fragment,
5380 &ett_dcerpc_krb5_auth_verf,
5382 module_t *dcerpc_module;
5384 proto_dcerpc = proto_register_protocol ("DCE RPC", "DCERPC", "dcerpc");
5385 proto_register_field_array (proto_dcerpc, hf, array_length (hf));
5386 proto_register_subtree_array (ett, array_length (ett));
5387 register_init_routine (dcerpc_init_protocol);
5388 dcerpc_module = prefs_register_protocol (proto_dcerpc, NULL);
5389 prefs_register_bool_preference (dcerpc_module,
5391 "Reassemble DCE/RPC messages spanning multiple TCP segments",
5392 "Whether the DCE/RPC dissector should reassemble messages spanning multiple TCP segments."
5393 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
5394 &dcerpc_cn_desegment);
5395 prefs_register_bool_preference (dcerpc_module,
5396 "reassemble_dcerpc",
5397 "Reassemble DCE/RPC fragments",
5398 "Whether the DCE/RPC dissector should reassemble fragmented DCE/RPC PDUs",
5399 &dcerpc_reassemble);
5400 register_init_routine(dcerpc_reassemble_init);
5401 dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
5402 dcerpc_tap=register_tap("dcerpc");
5404 g_hook_list_init(&dcerpc_hooks_init_protos, sizeof(GHook));
5408 proto_reg_handoff_dcerpc (void)
5410 heur_dissector_add ("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
5411 heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
5412 heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
5413 heur_dissector_add ("smb_transact", dissect_dcerpc_cn_smbpipe, proto_dcerpc);
5414 heur_dissector_add ("http", dissect_dcerpc_cn_bs, proto_dcerpc);
5415 dcerpc_smb_init(proto_dcerpc);