some auth padding update from metze
[obnox/wireshark/wip.git] / epan / dissectors / packet-dcerpc.c
1 /* packet-dcerpc.c
2  * Routines for DCERPC packet disassembly
3  * Copyright 2001, Todd Sabin <tas@webspan.net>
4  * Copyright 2003, Tim Potter <tpot@samba.org>
5  *
6  * $Id$
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@ethereal.com>
10  * Copyright 1998 Gerald Combs
11  *
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.
16  *
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.
21  *
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.
25  */
26
27 /* The DCE RPC specification can be found at:
28  * http://www.opengroup.org/dce/
29  */
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include <string.h>
36 #include <ctype.h>
37
38 #include <glib.h>
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>
44 #include <epan/tap.h>
45 #include <epan/dissectors/packet-frame.h>
46 #include <epan/dissectors/packet-dcerpc-nt.h>
47
48 static int dcerpc_tap = -1;
49
50
51 static const value_string pckt_vals[] = {
52     { PDU_REQ,        "Request"},
53     { PDU_PING,       "Ping"},
54     { PDU_RESP,       "Response"},
55     { PDU_FAULT,      "Fault"},
56     { PDU_WORKING,    "Working"},
57     { PDU_NOCALL,     "Nocall"},
58     { PDU_REJECT,     "Reject"},
59     { PDU_ACK,        "Ack"},
60     { PDU_CL_CANCEL,  "Cl_cancel"},
61     { PDU_FACK,       "Fack"},
62     { PDU_CANCEL_ACK, "Cancel_ack"},
63     { PDU_BIND,       "Bind"},
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"},
72     { 0,              NULL }
73 };
74
75 static const value_string drep_byteorder_vals[] = {
76     { 0, "Big-endian" },
77     { 1, "Little-endian" },
78     { 0,  NULL }
79 };
80
81 static const value_string drep_character_vals[] = {
82     { 0, "ASCII" },
83     { 1, "EBCDIC" },
84     { 0,  NULL }
85 };
86
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
91
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"  },
97     { 0,  NULL }
98 };
99
100 /*
101  * Authentication services.
102  */
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"},
116         { 0, NULL }
117 };
118
119 /*
120  * Protection levels.
121  */
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" },
129         { 0,                               NULL }
130 };
131
132 /*
133  * Flag bits in first flag field in connectionless PDU header.
134  */
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
138                                          * transmission */
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'
145                                          * request */
146 #define PFCL1_IDEMPOTENT        0x20    /* If set, the PDU is for an idempotent
147                                          * request */
148 #define PFCL1_BROADCAST         0x40    /* If set, the PDU is for a broadcast
149                                          * request */
150 #define PFCL1_RESERVED_80       0x80    /* Reserved for use by implementations */
151
152 /*
153  * Flag bits in second flag field in connectionless PDU header.
154  */
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 */
163
164 /*
165  * Flag bits in connection-oriented PDU header.
166  */
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
175                                          * execute. */
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
181                                          * is omitted. */
182
183 /*
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.
187  */
188 #define PFC_NOT_FRAGMENTED(hdr) \
189   ((hdr->flags&(PFC_FIRST_FRAG|PFC_LAST_FRAG))==(PFC_FIRST_FRAG|PFC_LAST_FRAG))
190
191 /*
192  * Presentation context negotiation result.
193  */
194 static const value_string p_cont_result_vals[] = {
195         { 0, "Acceptance" },
196         { 1, "User rejection" },
197         { 2, "Provider rejection" },
198         { 0, NULL }
199 };
200
201 /*
202  * Presentation context negotiation rejection reasons.
203  */
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" },
209         { 0, NULL }
210 };
211
212 /*
213  * Reject reasons.
214  */
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 */
223
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" },
233         { 0,                              NULL }
234 };
235
236 /*
237  * Reject status codes.
238  */
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" },
286         { 0,          NULL }
287 };
288
289
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.
292  */
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
296
297
298 static int proto_dcerpc = -1;
299
300 /* field defines */
301 static int hf_dcerpc_request_in = -1;
302 static int hf_dcerpc_time = -1;
303 static int hf_dcerpc_response_in = -1;
304 static int hf_dcerpc_ver = -1;
305 static int hf_dcerpc_ver_minor = -1;
306 static int hf_dcerpc_packet_type = -1;
307 static int hf_dcerpc_cn_flags = -1;
308 static int hf_dcerpc_cn_flags_first_frag = -1;
309 static int hf_dcerpc_cn_flags_last_frag = -1;
310 static int hf_dcerpc_cn_flags_cancel_pending = -1;
311 static int hf_dcerpc_cn_flags_reserved = -1;
312 static int hf_dcerpc_cn_flags_mpx = -1;
313 static int hf_dcerpc_cn_flags_dne = -1;
314 static int hf_dcerpc_cn_flags_maybe = -1;
315 static int hf_dcerpc_cn_flags_object = -1;
316 static int hf_dcerpc_drep = -1;
317 static int hf_dcerpc_drep_byteorder = -1;
318 static int hf_dcerpc_drep_character = -1;
319 static int hf_dcerpc_drep_fp = -1;
320 static int hf_dcerpc_cn_frag_len = -1;
321 static int hf_dcerpc_cn_auth_len = -1;
322 static int hf_dcerpc_cn_call_id = -1;
323 static int hf_dcerpc_cn_max_xmit = -1;
324 static int hf_dcerpc_cn_max_recv = -1;
325 static int hf_dcerpc_cn_assoc_group = -1;
326 static int hf_dcerpc_cn_num_ctx_items = -1;
327 static int hf_dcerpc_cn_ctx_id = -1;
328 static int hf_dcerpc_cn_num_trans_items = -1;
329 static int hf_dcerpc_cn_bind_if_id = -1;
330 static int hf_dcerpc_cn_bind_if_ver = -1;
331 static int hf_dcerpc_cn_bind_if_ver_minor = -1;
332 static int hf_dcerpc_cn_bind_trans_id = -1;
333 static int hf_dcerpc_cn_bind_trans_ver = -1;
334 static int hf_dcerpc_cn_alloc_hint = -1;
335 static int hf_dcerpc_cn_sec_addr_len = -1;
336 static int hf_dcerpc_cn_sec_addr = -1;
337 static int hf_dcerpc_cn_num_results = -1;
338 static int hf_dcerpc_cn_ack_result = -1;
339 static int hf_dcerpc_cn_ack_reason = -1;
340 static int hf_dcerpc_cn_ack_trans_id = -1;
341 static int hf_dcerpc_cn_ack_trans_ver = -1;
342 static int hf_dcerpc_cn_reject_reason = -1;
343 static int hf_dcerpc_cn_num_protocols = -1;
344 static int hf_dcerpc_cn_protocol_ver_major = -1;
345 static int hf_dcerpc_cn_protocol_ver_minor = -1;
346 static int hf_dcerpc_cn_cancel_count = -1;
347 static int hf_dcerpc_cn_status = -1;
348 static int hf_dcerpc_auth_type = -1;
349 static int hf_dcerpc_auth_level = -1;
350 static int hf_dcerpc_auth_pad_len = -1;
351 static int hf_dcerpc_auth_rsrvd = -1;
352 static int hf_dcerpc_auth_ctx_id = -1;
353 static int hf_dcerpc_dg_flags1 = -1;
354 static int hf_dcerpc_dg_flags1_rsrvd_01 = -1;
355 static int hf_dcerpc_dg_flags1_last_frag = -1;
356 static int hf_dcerpc_dg_flags1_frag = -1;
357 static int hf_dcerpc_dg_flags1_nofack = -1;
358 static int hf_dcerpc_dg_flags1_maybe = -1;
359 static int hf_dcerpc_dg_flags1_idempotent = -1;
360 static int hf_dcerpc_dg_flags1_broadcast = -1;
361 static int hf_dcerpc_dg_flags1_rsrvd_80 = -1;
362 static int hf_dcerpc_dg_flags2 = -1;
363 static int hf_dcerpc_dg_flags2_rsrvd_01 = -1;
364 static int hf_dcerpc_dg_flags2_cancel_pending = -1;
365 static int hf_dcerpc_dg_flags2_rsrvd_04 = -1;
366 static int hf_dcerpc_dg_flags2_rsrvd_08 = -1;
367 static int hf_dcerpc_dg_flags2_rsrvd_10 = -1;
368 static int hf_dcerpc_dg_flags2_rsrvd_20 = -1;
369 static int hf_dcerpc_dg_flags2_rsrvd_40 = -1;
370 static int hf_dcerpc_dg_flags2_rsrvd_80 = -1;
371 static int hf_dcerpc_dg_serial_hi = -1;
372 static int hf_dcerpc_obj_id = -1;
373 static int hf_dcerpc_dg_if_id = -1;
374 static int hf_dcerpc_dg_act_id = -1;
375 static int hf_dcerpc_dg_serial_lo = -1;
376 static int hf_dcerpc_dg_ahint = -1;
377 static int hf_dcerpc_dg_ihint = -1;
378 static int hf_dcerpc_dg_frag_len = -1;
379 static int hf_dcerpc_dg_frag_num = -1;
380 static int hf_dcerpc_dg_auth_proto = -1;
381 static int hf_dcerpc_opnum = -1;
382 static int hf_dcerpc_dg_seqnum = -1;
383 static int hf_dcerpc_dg_server_boot = -1;
384 static int hf_dcerpc_dg_if_ver = -1;
385 static int hf_dcerpc_krb5_av_prot_level = -1;
386 static int hf_dcerpc_krb5_av_key_vers_num = -1;
387 static int hf_dcerpc_krb5_av_key_auth_verifier = -1;
388 static int hf_dcerpc_dg_cancel_vers = -1;
389 static int hf_dcerpc_dg_cancel_id = -1;
390 static int hf_dcerpc_dg_server_accepting_cancels = -1;
391 static int hf_dcerpc_dg_fack_vers = -1;
392 static int hf_dcerpc_dg_fack_window_size = -1;
393 static int hf_dcerpc_dg_fack_max_tsdu = -1;
394 static int hf_dcerpc_dg_fack_max_frag_size = -1;
395 static int hf_dcerpc_dg_fack_serial_num = -1;
396 static int hf_dcerpc_dg_fack_selack_len = -1;
397 static int hf_dcerpc_dg_fack_selack = -1;
398 static int hf_dcerpc_dg_status = -1;
399 static int hf_dcerpc_array_max_count = -1;
400 static int hf_dcerpc_array_offset = -1;
401 static int hf_dcerpc_array_actual_count = -1;
402 static int hf_dcerpc_array_buffer = -1;
403 static int hf_dcerpc_op = -1;
404 static int hf_dcerpc_referent_id = -1;
405 static int hf_dcerpc_fragments = -1;
406 static int hf_dcerpc_fragment = -1;
407 static int hf_dcerpc_fragment_overlap = -1;
408 static int hf_dcerpc_fragment_overlap_conflict = -1;
409 static int hf_dcerpc_fragment_multiple_tails = -1;
410 static int hf_dcerpc_fragment_too_long_fragment = -1;
411 static int hf_dcerpc_fragment_error = -1;
412 static int hf_dcerpc_reassembled_in = -1;
413 static int hf_dcerpc_unknown_if_id = -1;
414
415 static gint ett_dcerpc = -1;
416 static gint ett_dcerpc_cn_flags = -1;
417 static gint ett_dcerpc_cn_ctx = -1;
418 static gint ett_dcerpc_cn_iface = -1;
419 static gint ett_dcerpc_drep = -1;
420 static gint ett_dcerpc_dg_flags1 = -1;
421 static gint ett_dcerpc_dg_flags2 = -1;
422 static gint ett_dcerpc_pointer_data = -1;
423 static gint ett_dcerpc_string = -1;
424 static gint ett_dcerpc_fragments = -1;
425 static gint ett_dcerpc_fragment = -1;
426 static gint ett_dcerpc_krb5_auth_verf = -1;
427
428 static const fragment_items dcerpc_frag_items = {
429         &ett_dcerpc_fragments,
430         &ett_dcerpc_fragment,
431
432         &hf_dcerpc_fragments,
433         &hf_dcerpc_fragment,
434         &hf_dcerpc_fragment_overlap,
435         &hf_dcerpc_fragment_overlap_conflict,
436         &hf_dcerpc_fragment_multiple_tails,
437         &hf_dcerpc_fragment_too_long_fragment,
438         &hf_dcerpc_fragment_error,
439         NULL,
440
441         "fragments"
442 };
443
444 /* list of hooks to be called when init_protocols is done */
445 GHookList dcerpc_hooks_init_protos;
446
447 #ifdef _WIN32
448 int ResolveWin32UUID(e_uuid_t if_id, char *UUID_NAME, int UUID_NAME_MAX_LEN)
449 {
450         char REG_UUID_NAME[MAX_PATH];
451         HKEY hKey = NULL;
452         DWORD UUID_MAX_SIZE = MAX_PATH;
453         char REG_UUID_STR[MAX_PATH];
454         
455         if(UUID_NAME_MAX_LEN < 2)
456                 return 0;
457         REG_UUID_NAME[0] = '\0';
458         snprintf(REG_UUID_STR, MAX_PATH, "SOFTWARE\\Classes\\Interface\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
459                         if_id.Data1, if_id.Data2, if_id.Data3,
460                         if_id.Data4[0], if_id.Data4[1],
461                         if_id.Data4[2], if_id.Data4[3],
462                         if_id.Data4[4], if_id.Data4[5],
463                         if_id.Data4[6], if_id.Data4[7]);
464         if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCSTR)REG_UUID_STR, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
465         {
466                 if (RegQueryValueEx(hKey, NULL, NULL, NULL, (LPBYTE)REG_UUID_NAME, &UUID_MAX_SIZE) == ERROR_SUCCESS && UUID_MAX_SIZE <= MAX_PATH)
467                         {
468                         snprintf(UUID_NAME, UUID_NAME_MAX_LEN, "%s", REG_UUID_NAME);
469                         RegCloseKey(hKey);
470                         return strlen(REG_UUID_NAME);
471                 }
472                 RegCloseKey(hKey);
473         }
474         return 0; /* we didn't find anything anyhow. Please don't use the string! */
475         
476 }
477 #endif
478
479 static dcerpc_info *
480 get_next_di(void)
481 {
482         static dcerpc_info di[20];
483         static int di_counter=0;
484
485         di_counter++;
486         if(di_counter>=20){
487                 di_counter=0;
488         }
489         return &di[di_counter];
490 }
491
492 /* try to desegment big DCE/RPC packets over TCP? */
493 static gboolean dcerpc_cn_desegment = TRUE;
494
495 /* reassemble DCE/RPC fragments */
496 /* reassembly of dcerpc fragments will not work for the case where ONE frame
497    might contain multiple dcerpc fragments for different PDUs.
498    this case would be so unusual/weird so if you got captures like that:
499         too bad
500 */
501 static gboolean dcerpc_reassemble = FALSE;
502 static GHashTable *dcerpc_co_reassemble_table = NULL;
503 static GHashTable *dcerpc_cl_reassemble_table = NULL;
504
505 static void
506 dcerpc_reassemble_init(void)
507 {
508   fragment_table_init(&dcerpc_co_reassemble_table);
509   dcerpc_fragment_table_init(&dcerpc_cl_reassemble_table);
510 }
511
512 /*
513  * Authentication subdissectors.  Used to dissect authentication blobs in
514  * DCERPC binds, requests and responses.
515  */
516
517 typedef struct _dcerpc_auth_subdissector {
518         guint8 auth_level;
519         guint8 auth_type;
520         dcerpc_auth_subdissector_fns auth_fns;
521 } dcerpc_auth_subdissector;
522
523 static GSList *dcerpc_auth_subdissector_list;
524
525 static dcerpc_auth_subdissector_fns *get_auth_subdissector_fns(
526         guint8 auth_level, guint8 auth_type)
527 {
528         gpointer data;
529         int i;
530
531         for (i = 0; (data = g_slist_nth_data(dcerpc_auth_subdissector_list, i)); i++) {
532                 dcerpc_auth_subdissector *asd = (dcerpc_auth_subdissector *)data;
533
534                 if (asd->auth_level == auth_level && 
535                     asd->auth_type == auth_type)
536                         return &asd->auth_fns;
537         }
538
539         return NULL;
540 }
541
542 void register_dcerpc_auth_subdissector(guint8 auth_level, guint8 auth_type,
543                                        dcerpc_auth_subdissector_fns *fns)
544 {
545         dcerpc_auth_subdissector *d;
546
547         if (get_auth_subdissector_fns(auth_level, auth_type))
548                 return;
549
550         d = (dcerpc_auth_subdissector *)g_malloc(sizeof(dcerpc_auth_subdissector));
551
552         d->auth_level = auth_level;
553         d->auth_type = auth_type;
554         memcpy(&d->auth_fns, fns, sizeof(dcerpc_auth_subdissector_fns));
555
556         dcerpc_auth_subdissector_list = g_slist_append(dcerpc_auth_subdissector_list, d);
557 }
558
559 /* Hand off verifier data to a registered dissector */
560
561 static void dissect_auth_verf(tvbuff_t *auth_tvb, packet_info *pinfo,
562                               proto_tree *tree, 
563                               dcerpc_auth_subdissector_fns *auth_fns,
564                               e_dce_cn_common_hdr_t *hdr, 
565                               dcerpc_auth_info *auth_info)
566 {
567         dcerpc_dissect_fnct_t *volatile fn = NULL;
568
569         switch (hdr->ptype) {
570         case PDU_BIND:
571         case PDU_ALTER:
572                 fn = auth_fns->bind_fn;
573                 break;
574         case PDU_BIND_ACK:
575         case PDU_ALTER_ACK:
576                 fn = auth_fns->bind_ack_fn;
577                 break;
578         case PDU_AUTH3:
579                 fn = auth_fns->auth3_fn;
580                 break;
581         case PDU_REQ:
582                 fn = auth_fns->req_verf_fn;
583                 break;
584         case PDU_RESP:
585                 fn = auth_fns->resp_verf_fn;
586                 break;
587
588                 /* Don't know how to handle authentication data in this 
589                    pdu type. */
590
591         default:
592                 g_warning("attempt to dissect %s pdu authentication data",
593                           val_to_str(hdr->ptype, pckt_vals, "Unknown (%u)"));
594                 break;
595         }
596
597         if (fn)
598                 fn(auth_tvb, 0, pinfo, tree, hdr->drep);
599         else
600                 proto_tree_add_text(tree, auth_tvb, 0, hdr->auth_len,
601                                     "%s Verifier", 
602                                     val_to_str(auth_info->auth_type, 
603                                                authn_protocol_vals,
604                                                "Unknown (%u)"));
605 }
606
607 /* Hand off payload data to a registered dissector */
608
609 static tvbuff_t *decode_encrypted_data(tvbuff_t *data_tvb, 
610                                        tvbuff_t *auth_tvb,
611                                        packet_info *pinfo,
612                                        dcerpc_auth_subdissector_fns *auth_fns,
613                                        gboolean is_request, 
614                                        dcerpc_auth_info *auth_info)
615 {
616         dcerpc_decode_data_fnct_t *fn;
617
618         if (is_request)
619                 fn = auth_fns->req_data_fn;
620         else
621                 fn = auth_fns->resp_data_fn;
622
623         if (fn)
624                 return fn(data_tvb, auth_tvb, 0, pinfo, auth_info);
625
626         return NULL;
627 }
628
629 /*
630  * Subdissectors
631  */
632
633 /* the registered subdissectors */
634 GHashTable *dcerpc_uuids=NULL;
635
636 static gint
637 dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2)
638 {
639     const dcerpc_uuid_key *key1 = (const dcerpc_uuid_key *)k1;
640     const dcerpc_uuid_key *key2 = (const dcerpc_uuid_key *)k2;
641     return ((memcmp (&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
642             && (key1->ver == key2->ver));
643 }
644
645 static guint
646 dcerpc_uuid_hash (gconstpointer k)
647 {
648     const dcerpc_uuid_key *key = (const dcerpc_uuid_key *)k;
649     /* This isn't perfect, but the Data1 part of these is almost always
650        unique. */
651     return key->uuid.Data1;
652 }
653
654 void
655 dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver,
656                   dcerpc_sub_dissector *procs, int opnum_hf)
657 {
658     dcerpc_uuid_key *key = g_malloc (sizeof (*key));
659     dcerpc_uuid_value *value = g_malloc (sizeof (*value));
660     header_field_info *hf_info;
661
662     key->uuid = *uuid;
663     key->ver = ver;
664
665     value->proto = find_protocol_by_id(proto);
666     value->proto_id = proto;
667     value->ett = ett;
668     value->name = proto_get_protocol_short_name (value->proto);
669     value->procs = procs;
670     value->opnum_hf = opnum_hf;
671
672     g_hash_table_insert (dcerpc_uuids, key, value);
673
674     hf_info = proto_registrar_get_nth(opnum_hf);
675     hf_info->strings = value_string_from_subdissectors(procs);
676 }
677
678
679 /* try to get registered name for this uuid */
680 gchar *dcerpc_get_uuid_name(e_uuid_t *uuid, guint16 ver)
681 {
682     dcerpc_uuid_key key;
683     dcerpc_uuid_value *sub_proto;
684
685
686         /* try to get registered uuid "name" of if_id */
687         key.uuid = *uuid;
688         key.ver = ver;
689
690         if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) != NULL
691                  && proto_is_protocol_enabled(sub_proto->proto)) {
692
693                 return sub_proto->name;
694         }
695
696         return NULL;
697 }
698
699
700 /* Function to find the name of a registered protocol
701  * or NULL if the protocol/version is not known to ethereal.
702  */
703 char *
704 dcerpc_get_proto_name(e_uuid_t *uuid, guint16 ver)
705 {
706     dcerpc_uuid_key key;
707     dcerpc_uuid_value *sub_proto;
708
709     key.uuid = *uuid;
710     key.ver = ver;
711     if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
712         return NULL;
713     }
714     return sub_proto->name;
715 }
716
717 /* Function to find the opnum hf-field of a registered protocol
718  * or -1 if the protocol/version is not known to ethereal.
719  */
720 int
721 dcerpc_get_proto_hf_opnum(e_uuid_t *uuid, guint16 ver)
722 {
723     dcerpc_uuid_key key;
724     dcerpc_uuid_value *sub_proto;
725
726     key.uuid = *uuid;
727     key.ver = ver;
728     if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
729         return -1;
730     }
731     return sub_proto->opnum_hf;
732 }
733
734 /* Create a value_string consisting of DCERPC opnum and name from a
735    subdissector array. */
736
737 value_string *value_string_from_subdissectors(dcerpc_sub_dissector *sd)
738 {
739         value_string *vs = NULL;
740         int i, num_sd = 0;
741
742  again:
743         for (i = 0; sd[i].name; i++) {
744                 if (vs) {
745                         vs[i].value = sd[i].num;
746                         vs[i].strptr = sd[i].name;
747                 } else
748                         num_sd++;
749         }
750
751         if (!vs) {
752                 vs = g_malloc((num_sd + 1) * sizeof(value_string));
753                 goto again;
754         }
755
756         vs[num_sd].value = 0;
757         vs[num_sd].strptr = NULL;
758
759         return vs;
760 }
761
762 /* Function to find the subdissector table of a registered protocol
763  * or NULL if the protocol/version is not known to ethereal.
764  */
765 dcerpc_sub_dissector *
766 dcerpc_get_proto_sub_dissector(e_uuid_t *uuid, guint16 ver)
767 {
768     dcerpc_uuid_key key;
769     dcerpc_uuid_value *sub_proto;
770
771     key.uuid = *uuid;
772     key.ver = ver;
773     if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
774         return NULL;
775     }
776     return sub_proto->procs;
777 }
778
779
780 /*
781  * To keep track of ctx_id mappings.
782  *
783  * Everytime we see a bind call we update this table.
784  * Note that we always specify a SMB FID. For non-SMB transports this
785  * value is 0.
786  */
787 static GHashTable *dcerpc_binds=NULL;
788
789 typedef struct _dcerpc_bind_key {
790     conversation_t *conv;
791     guint16 ctx_id;
792     guint16 smb_fid;
793 } dcerpc_bind_key;
794
795 typedef struct _dcerpc_bind_value {
796         e_uuid_t uuid;
797         guint16 ver;
798 } dcerpc_bind_value;
799
800 static GMemChunk *dcerpc_bind_key_chunk=NULL;
801 static GMemChunk *dcerpc_bind_value_chunk=NULL;
802
803 static gint
804 dcerpc_bind_equal (gconstpointer k1, gconstpointer k2)
805 {
806     const dcerpc_bind_key *key1 = (const dcerpc_bind_key *)k1;
807     const dcerpc_bind_key *key2 = (const dcerpc_bind_key *)k2;
808     return (key1->conv == key2->conv
809             && key1->ctx_id == key2->ctx_id
810             && key1->smb_fid == key2->smb_fid);
811 }
812
813 static guint
814 dcerpc_bind_hash (gconstpointer k)
815 {
816     const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
817     guint hash;
818
819     hash=GPOINTER_TO_UINT(key->conv) + key->ctx_id + key->smb_fid;
820     return hash;
821
822 }
823
824 /*
825  * To keep track of callid mappings.  Should really use some generic
826  * conversation support instead.
827  */
828 static GHashTable *dcerpc_cn_calls=NULL;
829 static GHashTable *dcerpc_dg_calls=NULL;
830
831 typedef struct _dcerpc_cn_call_key {
832     conversation_t *conv;
833     guint32 call_id;
834     guint16 smb_fid;
835 } dcerpc_cn_call_key;
836
837 typedef struct _dcerpc_dg_call_key {
838     conversation_t *conv;
839     guint32 seqnum;
840     e_uuid_t act_id ;
841 } dcerpc_dg_call_key;
842
843 static GMemChunk *dcerpc_cn_call_key_chunk=NULL;
844
845 static GMemChunk *dcerpc_dg_call_key_chunk=NULL;
846
847 static GMemChunk *dcerpc_call_value_chunk=NULL;
848
849
850 static gint
851 dcerpc_cn_call_equal (gconstpointer k1, gconstpointer k2)
852 {
853     const dcerpc_cn_call_key *key1 = (const dcerpc_cn_call_key *)k1;
854     const dcerpc_cn_call_key *key2 = (const dcerpc_cn_call_key *)k2;
855     return (key1->conv == key2->conv
856             && key1->call_id == key2->call_id
857             && key1->smb_fid == key2->smb_fid);
858 }
859
860 static gint
861 dcerpc_dg_call_equal (gconstpointer k1, gconstpointer k2)
862 {
863     const dcerpc_dg_call_key *key1 = (const dcerpc_dg_call_key *)k1;
864     const dcerpc_dg_call_key *key2 = (const dcerpc_dg_call_key *)k2;
865     return (key1->conv == key2->conv
866             && key1->seqnum == key2->seqnum
867             && (memcmp (&key1->act_id, &key2->act_id, sizeof (e_uuid_t)) == 0));
868 }
869
870 static guint
871 dcerpc_cn_call_hash (gconstpointer k)
872 {
873     const dcerpc_cn_call_key *key = (const dcerpc_cn_call_key *)k;
874     return GPOINTER_TO_UINT(key->conv) + key->call_id + key->smb_fid;
875 }
876
877 static guint
878 dcerpc_dg_call_hash (gconstpointer k)
879 {
880     const dcerpc_dg_call_key *key = (const dcerpc_dg_call_key *)k;
881     return (GPOINTER_TO_UINT(key->conv) + key->seqnum + key->act_id.Data1
882             + (key->act_id.Data2 << 16) + key->act_id.Data3
883             + (key->act_id.Data4[0] << 24) + (key->act_id.Data4[1] << 16)
884             + (key->act_id.Data4[2] << 8) + (key->act_id.Data4[3] << 0)
885             + (key->act_id.Data4[4] << 24) + (key->act_id.Data4[5] << 16)
886             + (key->act_id.Data4[6] << 8) + (key->act_id.Data4[7] << 0));
887 }
888
889 /* to keep track of matched calls/responses
890    this one uses the same value struct as calls, but the key is the frame id
891    and call id; there can be more than one call in a frame.
892
893    XXX - why not just use the same keys as are used for calls?
894 */
895
896 static GHashTable *dcerpc_matched=NULL;
897
898 typedef struct _dcerpc_matched_key {
899     guint32 frame;
900     guint32 call_id;
901 } dcerpc_matched_key;
902
903 static GMemChunk *dcerpc_matched_key_chunk=NULL;
904
905 static gint
906 dcerpc_matched_equal (gconstpointer k1, gconstpointer k2)
907 {
908     const dcerpc_matched_key *key1 = (const dcerpc_matched_key *)k1;
909     const dcerpc_matched_key *key2 = (const dcerpc_matched_key *)k2;
910     return (key1->frame == key2->frame
911             && key1->call_id == key2->call_id);
912 }
913
914 static guint
915 dcerpc_matched_hash (gconstpointer k)
916 {
917     const dcerpc_matched_key *key = (const dcerpc_matched_key *)k;
918     return key->frame;
919 }
920
921
922
923 /*
924  * Utility functions.  Modeled after packet-rpc.c
925  */
926
927 int
928 dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
929                       proto_tree *tree, guint8 *drep,
930                       int hfindex, guint8 *pdata)
931 {
932     guint8 data;
933
934     data = tvb_get_guint8 (tvb, offset);
935     if (tree) {
936         proto_tree_add_item (tree, hfindex, tvb, offset, 1, (drep[0] & 0x10));
937     }
938     if (pdata)
939         *pdata = data;
940     return offset + 1;
941 }
942
943 int
944 dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
945                        proto_tree *tree, guint8 *drep,
946                        int hfindex, guint16 *pdata)
947 {
948     guint16 data;
949
950     data = ((drep[0] & 0x10)
951             ? tvb_get_letohs (tvb, offset)
952             : tvb_get_ntohs (tvb, offset));
953
954     if (tree) {
955         proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10));
956     }
957     if (pdata)
958         *pdata = data;
959     return offset + 2;
960 }
961
962 int
963 dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
964                        proto_tree *tree, guint8 *drep,
965                        int hfindex, guint32 *pdata)
966 {
967     guint32 data;
968
969     data = ((drep[0] & 0x10)
970             ? tvb_get_letohl (tvb, offset)
971             : tvb_get_ntohl (tvb, offset));
972
973     if (tree) {
974         proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10));
975     }
976     if (pdata)
977         *pdata = data;
978     return offset+4;
979 }
980
981 /* handles 32 bit unix time_t */
982 int
983 dissect_dcerpc_time_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
984                        proto_tree *tree, guint8 *drep,
985                        int hfindex, guint32 *pdata)
986 {
987     guint32 data;
988     nstime_t tv;
989
990     data = ((drep[0] & 0x10)
991             ? tvb_get_letohl (tvb, offset)
992             : tvb_get_ntohl (tvb, offset));
993
994     tv.secs=data;
995     tv.nsecs=0;
996     if (tree) {
997         if(data==0xffffffff){
998             /* special case,   no time specified */
999             proto_tree_add_time_format(tree, hfindex, tvb, offset, 4, &tv, "%s: No time specified", proto_registrar_get_nth(hfindex)->name);
1000         } else {
1001             proto_tree_add_time (tree, hfindex, tvb, offset, 4, &tv);
1002         }
1003     }
1004     if (pdata)
1005         *pdata = data;
1006
1007     return offset+4;
1008 }
1009
1010 int
1011 dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1012                        proto_tree *tree, guint8 *drep,
1013                        int hfindex, guint64 *pdata)
1014 {
1015     guint64 data;
1016
1017     data = ((drep[0] & 0x10)
1018             ? tvb_get_letoh64 (tvb, offset)
1019             : tvb_get_ntoh64 (tvb, offset));
1020
1021     if (tree) {
1022         proto_tree_add_item(tree, hfindex, tvb, offset, 8, (drep[0] & 0x10));
1023     }
1024     if (pdata)
1025         *pdata = data;
1026     return offset+8;
1027 }
1028
1029
1030 int
1031 dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1032                     proto_tree *tree, guint8 *drep, 
1033                     int hfindex, gfloat *pdata)
1034 {
1035         gfloat data;
1036
1037
1038         switch(drep[1]) {
1039                 case(DCE_RPC_DREP_FP_IEEE):
1040                         data = ((drep[0] & 0x10)
1041                                         ? tvb_get_letohieee_float(tvb, offset)
1042                                         : tvb_get_ntohieee_float(tvb, offset));
1043                         if (tree) {
1044                                 proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
1045                         }
1046                         break;
1047                 case(DCE_RPC_DREP_FP_VAX):  /* (fall trough) */
1048                 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1049                 case(DCE_RPC_DREP_FP_IBM):  /* (fall trough) */
1050                 default:
1051                         /* ToBeDone: non IEEE floating formats */
1052                         /* Set data to a negative infinity value */
1053                         data = -G_MAXFLOAT;
1054                         if (tree) {
1055                                 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep[1]);
1056                         }
1057         }
1058     if (pdata)
1059         *pdata = data;
1060     return offset + 4;
1061 }
1062
1063
1064 int
1065 dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1066                     proto_tree *tree, guint8 *drep, 
1067                     int hfindex, gdouble *pdata)
1068 {
1069     gdouble data;
1070
1071
1072         switch(drep[1]) {
1073                 case(DCE_RPC_DREP_FP_IEEE):
1074                         data = ((drep[0] & 0x10)
1075                                         ? tvb_get_letohieee_double(tvb, offset)
1076                                         : tvb_get_ntohieee_double(tvb, offset));
1077                         if (tree) {
1078                                 proto_tree_add_double(tree, hfindex, tvb, offset, 8, data);
1079                         }
1080                         break;
1081                 case(DCE_RPC_DREP_FP_VAX):  /* (fall trough) */
1082                 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1083                 case(DCE_RPC_DREP_FP_IBM):  /* (fall trough) */
1084                 default:
1085                         /* ToBeDone: non IEEE double formats */
1086                         /* Set data to a negative infinity value */
1087                         data = -G_MAXDOUBLE;
1088                         if (tree) {
1089                                 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep[1]);
1090                         }
1091         }
1092     if (pdata)
1093         *pdata = data;
1094     return offset + 8;
1095 }
1096
1097
1098 int
1099 dissect_dcerpc_uuid_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1100                     proto_tree *tree, char *drep,
1101                     int hfindex, e_uuid_t *pdata)
1102 {
1103     e_uuid_t uuid;
1104         header_field_info* hfi;
1105 #if 0
1106         gchar *uuid_name;
1107 #endif
1108
1109
1110     dcerpc_tvb_get_uuid (tvb, offset, drep, &uuid);
1111     if (tree) {
1112                 /* get name of protocol field to prepend it later */
1113                 hfi = proto_registrar_get_nth(hfindex);
1114
1115 #if 0
1116         /* XXX - get the name won't work correct, as we don't know the version of this uuid (if it has one) */
1117                 /* look for a registered uuid name */
1118                 uuid_name = dcerpc_get_uuid_name(&uuid, 0);
1119
1120                 if (uuid_name) {
1121                         /* we know the name of this uuid */
1122                         proto_tree_add_string_format (tree, hfindex, tvb, offset, 16, "",
1123                                       "%s: %s (%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x)",
1124                                                                           hfi->name, uuid_name,
1125                                       uuid.Data1, uuid.Data2, uuid.Data3,
1126                                       uuid.Data4[0], uuid.Data4[1],
1127                                       uuid.Data4[2], uuid.Data4[3],
1128                                       uuid.Data4[4], uuid.Data4[5],
1129                                       uuid.Data4[6], uuid.Data4[7]);
1130                 } else {
1131 #endif
1132                         /* we don't know the name of this uuid */
1133                         proto_tree_add_string_format (tree, hfindex, tvb, offset, 16, "",
1134                                       "%s: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1135                                                                           hfi->name,
1136                                       uuid.Data1, uuid.Data2, uuid.Data3,
1137                                       uuid.Data4[0], uuid.Data4[1],
1138                                       uuid.Data4[2], uuid.Data4[3],
1139                                       uuid.Data4[4], uuid.Data4[5],
1140                                       uuid.Data4[6], uuid.Data4[7]);
1141 #if 0
1142                 }
1143 #endif
1144     }
1145     if (pdata) {
1146         *pdata = uuid;
1147     }
1148     return offset + 16;
1149 }
1150
1151
1152 /*
1153  * a couple simpler things
1154  */
1155 guint16
1156 dcerpc_tvb_get_ntohs (tvbuff_t *tvb, gint offset, guint8 *drep)
1157 {
1158     if (drep[0] & 0x10) {
1159         return tvb_get_letohs (tvb, offset);
1160     } else {
1161         return tvb_get_ntohs (tvb, offset);
1162     }
1163 }
1164
1165 guint32
1166 dcerpc_tvb_get_ntohl (tvbuff_t *tvb, gint offset, guint8 *drep)
1167 {
1168     if (drep[0] & 0x10) {
1169         return tvb_get_letohl (tvb, offset);
1170     } else {
1171         return tvb_get_ntohl (tvb, offset);
1172     }
1173 }
1174
1175 void
1176 dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, guint8 *drep, e_uuid_t *uuid)
1177 {
1178     unsigned int i;
1179     uuid->Data1 = dcerpc_tvb_get_ntohl (tvb, offset, drep);
1180     uuid->Data2 = dcerpc_tvb_get_ntohs (tvb, offset+4, drep);
1181     uuid->Data3 = dcerpc_tvb_get_ntohs (tvb, offset+6, drep);
1182
1183     for (i=0; i<sizeof (uuid->Data4); i++) {
1184         uuid->Data4[i] = tvb_get_guint8 (tvb, offset+8+i);
1185     }
1186 }
1187
1188
1189
1190 /* NDR arrays */
1191 /* function to dissect a unidimensional conformant array */
1192 int
1193 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1194                 proto_tree *tree, guint8 *drep,
1195                 dcerpc_dissect_fnct_t *fnct)
1196 {
1197         guint32 i;
1198         dcerpc_info *di;
1199         int old_offset;
1200
1201         di=pinfo->private_data;
1202         if(di->conformant_run){
1203                 /* conformant run, just dissect the max_count header */
1204                 old_offset=offset;
1205                 di->conformant_run=0;
1206                 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1207                                 hf_dcerpc_array_max_count, &di->array_max_count);
1208                 di->array_max_count_offset=offset-4;
1209                 di->conformant_run=1;
1210                 di->conformant_eaten=offset-old_offset;
1211         } else {
1212                 /* we don't remember where in the bytestream this field was */
1213                 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1214
1215                 /* real run, dissect the elements */
1216                 for(i=0;i<di->array_max_count;i++){
1217                         offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1218                 }
1219         }
1220
1221         return offset;
1222 }
1223 /* function to dissect a unidimensional conformant and varying array */
1224 int
1225 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1226                 proto_tree *tree, guint8 *drep,
1227                 dcerpc_dissect_fnct_t *fnct)
1228 {
1229         guint32 i;
1230         dcerpc_info *di;
1231         int old_offset;
1232
1233         di=pinfo->private_data;
1234         if(di->conformant_run){
1235                 /* conformant run, just dissect the max_count header */
1236                 old_offset=offset;
1237                 di->conformant_run=0;
1238                 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1239                                 hf_dcerpc_array_max_count, &di->array_max_count);
1240                 di->array_max_count_offset=offset-4;
1241                 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1242                                 hf_dcerpc_array_offset, &di->array_offset);
1243                 di->array_offset_offset=offset-4;
1244                 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1245                                 hf_dcerpc_array_actual_count, &di->array_actual_count);
1246                 di->array_actual_count_offset=offset-4;
1247                 di->conformant_run=1;
1248                 di->conformant_eaten=offset-old_offset;
1249         } else {
1250                 /* we dont dont remember where  in the bytestream these fields were */
1251                 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1252                 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
1253                 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
1254
1255                 /* real run, dissect the elements */
1256                 for(i=0;i<di->array_actual_count;i++){
1257                         offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1258                 }
1259         }
1260
1261         return offset;
1262 }
1263 /* function to dissect a unidimensional varying array */
1264 int
1265 dissect_ndr_uvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1266                 proto_tree *tree, guint8 *drep,
1267                 dcerpc_dissect_fnct_t *fnct)
1268 {
1269         guint32 i;
1270         dcerpc_info *di;
1271         int old_offset;
1272
1273         di=pinfo->private_data;
1274         if(di->conformant_run){
1275                 /* conformant run, just dissect the max_count header */
1276                 old_offset=offset;
1277                 di->conformant_run=0;
1278                 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1279                                 hf_dcerpc_array_offset, &di->array_offset);
1280                 di->array_offset_offset=offset-4;
1281                 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1282                                 hf_dcerpc_array_actual_count, &di->array_actual_count);
1283                 di->array_actual_count_offset=offset-4;
1284                 di->conformant_run=1;
1285                 di->conformant_eaten=offset-old_offset;
1286         } else {
1287                 /* we dont dont remember where  in the bytestream these fields were */
1288                 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
1289                 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
1290
1291                 /* real run, dissect the elements */
1292                 for(i=0;i<di->array_actual_count;i++){
1293                         offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1294                 }
1295         }
1296
1297         return offset;
1298 }
1299
1300 /* Dissect an string of bytes.  This corresponds to
1301    IDL of the form '[string] byte *foo'.
1302
1303    It can also be used for a conformant varying array of bytes if
1304    the contents of the array should be shown as a big blob, rather
1305    than showing each byte as an individual element.
1306
1307    XXX - which of those is really the IDL type for, for example,
1308    the encrypted data in some MAPI packets?  (Microsoft haven't
1309    released that IDL.)
1310
1311    XXX - does this need to do all the conformant array stuff that
1312    "dissect_ndr_ucvarray()" does?  These are presumably for strings
1313    that are conformant and varying - they're stored like conformant
1314    varying arrays of bytes.  */
1315 int
1316 dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1317                             proto_tree *tree, guint8 *drep)
1318 {
1319     dcerpc_info *di;
1320     guint32 len;
1321
1322     di=pinfo->private_data;
1323     if(di->conformant_run){
1324       /* just a run to handle conformant arrays, no scalars to dissect */
1325       return offset;
1326     }
1327
1328     /* NDR array header */
1329
1330     offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1331                                 hf_dcerpc_array_max_count, NULL);
1332
1333     offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1334                                 hf_dcerpc_array_offset, NULL);
1335
1336     offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1337                                 hf_dcerpc_array_actual_count, &len);
1338
1339     if (tree && len)
1340         proto_tree_add_item(tree, hf_dcerpc_array_buffer,
1341                             tvb, offset, len, drep[0] & 0x10);
1342
1343     offset += len;
1344
1345     return offset;
1346 }
1347
1348 /* For dissecting arrays that are to be interpreted as strings.  */
1349
1350 /* Dissect an NDR conformant varying string of elements.
1351    The length of each element is given by the 'size_is' parameter;
1352    the elements are assumed to be characters or wide characters.
1353
1354    XXX - does this need to do all the conformant array stuff that
1355    "dissect_ndr_ucvarray()" does?  */
1356 int
1357 dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1358                      proto_tree *tree, guint8 *drep, int size_is,
1359                      int hfindex, gboolean add_subtree, char **data)
1360 {
1361     dcerpc_info *di;
1362     proto_item *string_item;
1363     proto_tree *string_tree;
1364     guint32 len, buffer_len;
1365     char *s;
1366     header_field_info *hfinfo;
1367
1368     di=pinfo->private_data;
1369     if(di->conformant_run){
1370       /* just a run to handle conformant arrays, no scalars to dissect */
1371       return offset;
1372     }
1373
1374     if (add_subtree) {
1375         string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1376                                           proto_registrar_get_name(hfindex));
1377         string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1378     } else {
1379         string_item = NULL;
1380         string_tree = tree;
1381     }
1382
1383     /* NDR array header */
1384
1385     offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1386                                 hf_dcerpc_array_max_count, NULL);
1387
1388     offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1389                                 hf_dcerpc_array_offset, NULL);
1390
1391     offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1392                                 hf_dcerpc_array_actual_count, &len);
1393
1394     buffer_len = size_is * len;
1395
1396     /* Adjust offset */
1397     if (offset % size_is)
1398         offset += size_is - (offset % size_is);
1399
1400     if (size_is == sizeof(guint16)) {
1401         /* XXX - use drep to determine the byte order? */
1402         s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
1403         /*
1404          * XXX - we don't support a string type with Unicode
1405          * characters, so if this is a string item, we make
1406          * its value be the "fake Unicode" string.
1407          */
1408         if (tree && buffer_len) {
1409             hfinfo = proto_registrar_get_nth(hfindex);
1410             if (hfinfo->type == FT_STRING) {
1411                 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1412                                       buffer_len, s);
1413             } else {
1414                 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1415                                     buffer_len, drep[0] & 0x10);
1416             }
1417         }
1418     } else {
1419         /*
1420          * "tvb_get_string()" throws an exception if the entire string
1421          * isn't in the tvbuff.  If the length is bogus, this should
1422          * keep us from trying to allocate an immensely large buffer.
1423          * (It won't help if the length is *valid* but immensely large,
1424          * but that's another matter; in any case, that would happen only
1425          * if we had an immensely large tvbuff....)
1426          */
1427         s = tvb_get_string(tvb, offset, buffer_len);
1428         if (tree && buffer_len)
1429             proto_tree_add_item(string_tree, hfindex, tvb, offset,
1430                                 buffer_len, drep[0] & 0x10);
1431     }
1432
1433     if (string_item != NULL)
1434         proto_item_append_text(string_item, ": %s", s);
1435
1436     if (data)
1437             *data = s;
1438     else
1439             g_free(s);
1440     
1441     offset += buffer_len;
1442
1443     proto_item_set_end(string_item, tvb, offset);
1444
1445     return offset;
1446 }
1447
1448 /* Dissect an conformant varying string of chars.
1449    This corresponds to IDL of the form '[string] char *foo'.
1450
1451    XXX - at least according to the DCE RPC 1.1 spec, a string has
1452    a null terminator, which isn't necessary as a terminator for
1453    the transfer language (as there's a length), but is presumably
1454    there for the benefit of null-terminated-string languages
1455    such as C.  Is this ever used for purely counted strings?
1456    (Not that it matters if it is.) */
1457 int
1458 dissect_ndr_char_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1459                         proto_tree *tree, guint8 *drep)
1460 {
1461     dcerpc_info *di;
1462     di=pinfo->private_data;
1463
1464     return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1465                                 sizeof(guint8), di->hf_index,
1466                                 FALSE, NULL);
1467 }
1468
1469 /* Dissect a conformant varying string of wchars (wide characters).
1470    This corresponds to IDL of the form '[string] wchar *foo'
1471
1472    XXX - at least according to the DCE RPC 1.1 spec, a string has
1473    a null terminator, which isn't necessary as a terminator for
1474    the transfer language (as there's a length), but is presumably
1475    there for the benefit of null-terminated-string languages
1476    such as C.  Is this ever used for purely counted strings?
1477    (Not that it matters if it is.) */
1478 int
1479 dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1480                         proto_tree *tree, guint8 *drep)
1481 {
1482     dcerpc_info *di;
1483     di=pinfo->private_data;
1484
1485     return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1486                                 sizeof(guint16), di->hf_index,
1487                                 FALSE, NULL);
1488 }
1489
1490 /* Dissect an NDR varying string of elements.
1491    The length of each element is given by the 'size_is' parameter;
1492    the elements are assumed to be characters or wide characters.
1493 */
1494 int
1495 dissect_ndr_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1496                      proto_tree *tree, guint8 *drep, int size_is,
1497                      int hfindex, gboolean add_subtree, char **data)
1498 {
1499     dcerpc_info *di;
1500     proto_item *string_item;
1501     proto_tree *string_tree;
1502     guint32 len, buffer_len;
1503     char *s;
1504     header_field_info *hfinfo;
1505
1506     di=pinfo->private_data;
1507     if(di->conformant_run){
1508       /* just a run to handle conformant arrays, no scalars to dissect */
1509       return offset;
1510     }
1511
1512     if (add_subtree) {
1513         string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1514                                           proto_registrar_get_name(hfindex));
1515         string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1516     } else {
1517         string_item = NULL;
1518         string_tree = tree;
1519     }
1520
1521     /* NDR array header */
1522     offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1523                                 hf_dcerpc_array_offset, NULL);
1524
1525     offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1526                                 hf_dcerpc_array_actual_count, &len);
1527
1528     buffer_len = size_is * len;
1529
1530     /* Adjust offset */
1531     if (offset % size_is)
1532         offset += size_is - (offset % size_is);
1533
1534     if (size_is == sizeof(guint16)) {
1535         /* XXX - use drep to determine the byte order? */
1536         s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
1537         /*
1538          * XXX - we don't support a string type with Unicode
1539          * characters, so if this is a string item, we make
1540          * its value be the "fake Unicode" string.
1541          */
1542         if (tree && buffer_len) {
1543             hfinfo = proto_registrar_get_nth(hfindex);
1544             if (hfinfo->type == FT_STRING) {
1545                 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1546                                       buffer_len, s);
1547             } else {
1548                 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1549                                     buffer_len, drep[0] & 0x10);
1550             }
1551         }
1552     } else {
1553         /*
1554          * "tvb_get_string()" throws an exception if the entire string
1555          * isn't in the tvbuff.  If the length is bogus, this should
1556          * keep us from trying to allocate an immensely large buffer.
1557          * (It won't help if the length is *valid* but immensely large,
1558          * but that's another matter; in any case, that would happen only
1559          * if we had an immensely large tvbuff....)
1560          */
1561         s = tvb_get_string(tvb, offset, buffer_len);
1562         if (tree && buffer_len)
1563             proto_tree_add_item(string_tree, hfindex, tvb, offset,
1564                                 buffer_len, drep[0] & 0x10);
1565     }
1566
1567     if (string_item != NULL)
1568         proto_item_append_text(string_item, ": %s", s);
1569
1570     if (data)
1571             *data = s;
1572     else
1573             g_free(s);
1574     
1575     offset += buffer_len;
1576
1577     proto_item_set_end(string_item, tvb, offset);
1578
1579     return offset;
1580 }
1581 /* Dissect an varying string of chars.
1582    This corresponds to IDL of the form '[string] char *foo'.
1583
1584    XXX - at least according to the DCE RPC 1.1 spec, a string has
1585    a null terminator, which isn't necessary as a terminator for
1586    the transfer language (as there's a length), but is presumably
1587    there for the benefit of null-terminated-string languages
1588    such as C.  Is this ever used for purely counted strings?
1589    (Not that it matters if it is.) */
1590 int
1591 dissect_ndr_char_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1592                         proto_tree *tree, guint8 *drep)
1593 {
1594     dcerpc_info *di;
1595     di=pinfo->private_data;
1596
1597     return dissect_ndr_vstring(tvb, offset, pinfo, tree, drep,
1598                                 sizeof(guint8), di->hf_index,
1599                                 FALSE, NULL);
1600 }
1601
1602 /* Dissect a varying string of wchars (wide characters).
1603    This corresponds to IDL of the form '[string] wchar *foo'
1604
1605    XXX - at least according to the DCE RPC 1.1 spec, a string has
1606    a null terminator, which isn't necessary as a terminator for
1607    the transfer language (as there's a length), but is presumably
1608    there for the benefit of null-terminated-string languages
1609    such as C.  Is this ever used for purely counted strings?
1610    (Not that it matters if it is.) */
1611 int
1612 dissect_ndr_wchar_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1613                         proto_tree *tree, guint8 *drep)
1614 {
1615     dcerpc_info *di;
1616     di=pinfo->private_data;
1617
1618     return dissect_ndr_vstring(tvb, offset, pinfo, tree, drep,
1619                                 sizeof(guint16), di->hf_index,
1620                                 FALSE, NULL);
1621 }
1622
1623
1624 /* ndr pointer handling */
1625 /* list of pointers encountered so far */
1626 static GSList *ndr_pointer_list = NULL;
1627
1628 /* position where in the list to insert newly encountered pointers */
1629 static int ndr_pointer_list_pos=0;
1630
1631 /* boolean controlling whether pointers are top-level or embedded */
1632 static gboolean pointers_are_top_level = TRUE;
1633
1634 /* as a kludge, we represent all embedded reference pointers as id==-1
1635    hoping that his will not collide with any non-ref pointers */
1636 typedef struct ndr_pointer_data {
1637         guint32 id;
1638         proto_item *item;       /* proto_item for pointer */
1639         proto_tree *tree;       /* subtree of above item */
1640         dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
1641         int hf_index;
1642         dcerpc_callback_fnct_t *callback;
1643         void *callback_args;
1644 } ndr_pointer_data_t;
1645
1646 void
1647 init_ndr_pointer_list(packet_info *pinfo)
1648 {
1649         dcerpc_info *di;
1650
1651         di=pinfo->private_data;
1652         di->conformant_run=0;
1653
1654         while(ndr_pointer_list){
1655                 ndr_pointer_data_t *npd;
1656
1657                 npd=g_slist_nth_data(ndr_pointer_list, 0);
1658                 ndr_pointer_list=g_slist_remove(ndr_pointer_list, npd);
1659                 if(npd){
1660                         g_free(npd);
1661                 }
1662         }
1663
1664         ndr_pointer_list=NULL;
1665         ndr_pointer_list_pos=0;
1666         pointers_are_top_level=TRUE;
1667 }
1668
1669 static int
1670 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, guint8 *drep)
1671 {
1672         int found_new_pointer;
1673         dcerpc_info *di;
1674         int old_offset;
1675         int next_pointer;
1676
1677         next_pointer=0;
1678         di=pinfo->private_data;
1679         do{
1680                 int i, len;
1681
1682                 found_new_pointer=0;
1683                 len=g_slist_length(ndr_pointer_list);
1684                 for(i=next_pointer;i<len;i++){
1685                         ndr_pointer_data_t *tnpd;
1686                         tnpd=g_slist_nth_data(ndr_pointer_list, i);
1687                         if(tnpd->fnct){
1688                                 dcerpc_dissect_fnct_t *fnct;
1689
1690                                 next_pointer=i+1;
1691                                 found_new_pointer=1;
1692                                 fnct=tnpd->fnct;
1693                                 tnpd->fnct=NULL;
1694                                 ndr_pointer_list_pos=i+1;
1695                                 di->hf_index=tnpd->hf_index;
1696                                 /* first a run to handle any conformant
1697                                    array headers */
1698                                 di->conformant_run=1;
1699                                 di->conformant_eaten=0;
1700                                 old_offset = offset;
1701                                 offset = (*(fnct))(tvb, offset, pinfo, NULL, drep);
1702
1703                                 g_assert((offset-old_offset)==di->conformant_eaten);
1704                                 /* This is to check for any bugs in the dissectors.
1705                                  *
1706                                  * Basically, the NDR representation will store all
1707                                  * arrays in two blocks, one block with the dimension
1708                                  * discreption, like size, number of elements and such,
1709                                  * and another block that contains the actual data stored
1710                                  * in the array.
1711                                  * If the array is embedded directly inside another,
1712                                  * encapsulating aggregate type, like a union or struct,
1713                                  * then these two blocks will be stored at different places
1714                                  * in the bytestream, with other data between the blocks.
1715                                  *
1716                                  * For this reason, all pointers to types (both aggregate
1717                                  * and scalar, for simplicity no distinction is made)
1718                                  * will have its dissector called twice.
1719                                  * The dissector will first be called with conformant_run==1
1720                                  * in which mode the dissector MUST NOT consume any data from
1721                                  * the tvbuff (i.e. may not dissect anything) except the
1722                                  * initial control block for arrays.
1723                                  * The second time the dissector is called, with
1724                                  * conformant_run==0, all other data for the type will be
1725                                  * dissected.
1726                                  *
1727                                  * All dissect_ndr_<type> dissectors are already prepared
1728                                  * for this and knows when it should eat data from the tvb
1729                                  * and when not to, so implementors of dissectors will
1730                                  * normally not need to worry about this or even know about
1731                                  * it. However, if a dissector for an aggregate type calls
1732                                  * a subdissector from outside packet-dcerpc.c, such as
1733                                  * the dissector in packet-smb.c for NT Security Descriptors
1734                                  * as an example, then it is VERY important to encapsulate
1735                                  * this call to an external subdissector with the appropriate
1736                                  * test for conformant_run, i.e. it will need something like
1737                                  *
1738                                  *      dcerpc_info *di;
1739                                  *
1740                                  *      di=pinfo->private_data;
1741                                  *      if(di->conformant_run){
1742                                  *              return offset;
1743                                  *      }
1744                                  *
1745                                  * to make sure it makes the right thing.
1746                                  * This assert will signal when someone has forgotten to
1747                                  * make the dissector aware of this requirement.
1748                                  */
1749
1750                                 /* now we dissect the actual pointer */
1751                                 di->conformant_run=0;
1752                                 old_offset = offset;
1753                                 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, drep);
1754                                 if (tnpd->callback)
1755                                         tnpd->callback(pinfo, tnpd->tree, tnpd->item, tvb, old_offset, offset, tnpd->callback_args);
1756                                 break;
1757                         }
1758                 }
1759         } while(found_new_pointer);
1760
1761         return offset;
1762 }
1763
1764
1765 static void
1766 add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
1767                     dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index, 
1768                     dcerpc_callback_fnct_t *callback, void *callback_args)
1769 {
1770         ndr_pointer_data_t *npd;
1771
1772         /* check if this pointer is valid */
1773         if(id!=0xffffffff){
1774                 dcerpc_info *di;
1775                 dcerpc_call_value *value;
1776
1777                 di=pinfo->private_data;
1778                 value=di->call_data;
1779
1780                 if(di->ptype == PDU_REQ){
1781                         if(!(pinfo->fd->flags.visited)){
1782                                 if(id>value->max_ptr){
1783                                         value->max_ptr=id;
1784                                 }
1785                         }
1786                 } else {
1787                         /* if we havent seen the request bail out since we cant
1788                            know whether this is the first non-NULL instance
1789                            or not */
1790                         if(value->req_frame==0){
1791                                 /* XXX THROW EXCEPTION */
1792                         }
1793
1794                         /* We saw this one in the request frame, nothing to
1795                            dissect later */
1796                         if(id<=value->max_ptr){
1797                                 return;
1798                         }
1799                 }
1800         }
1801
1802         npd=g_malloc(sizeof(ndr_pointer_data_t));
1803         npd->id=id;
1804         npd->tree=tree;
1805         npd->item=item;
1806         npd->fnct=fnct;
1807         npd->hf_index=hf_index;
1808         npd->callback=callback;
1809         npd->callback_args=callback_args;
1810         ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
1811                                         ndr_pointer_list_pos);
1812         ndr_pointer_list_pos++;
1813 }
1814
1815
1816 static int
1817 find_pointer_index(guint32 id)
1818 {
1819         ndr_pointer_data_t *npd;
1820         int i,len;
1821
1822         len=g_slist_length(ndr_pointer_list);
1823         for(i=0;i<len;i++){
1824                 npd=g_slist_nth_data(ndr_pointer_list, i);
1825                 if(npd){
1826                         if(npd->id==id){
1827                                 return i;
1828                         }
1829                 }
1830         }
1831
1832         return -1;
1833 }
1834
1835 /* This function dissects an NDR pointer and stores the callback for later
1836  * deferred dissection.
1837  *
1838  *   fnct is the callback function for when we have reached this object in
1839  *   the bytestream.
1840  *
1841  *   type is what type of pointer.
1842  *
1843  *   this is text is what text we should put in any created tree node.
1844  *
1845  *   hf_index is what hf value we want to pass to the callback function when
1846  *   it is called, the callback can later pich this one up from di->hf_index.
1847  *
1848  *   callback is executed after the pointer has been dereferenced.
1849  *
1850  *   callback_args is passed as an argument to the callback function
1851  *
1852  * See packet-dcerpc-samr.c for examples
1853  */
1854 int
1855 dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1856                     proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
1857                     int type, char *text, int hf_index, 
1858                     dcerpc_callback_fnct_t *callback, void *callback_args)
1859 {
1860         dcerpc_info *di;
1861
1862         di=pinfo->private_data;
1863         if(di->conformant_run){
1864                 /* this call was only for dissecting the header for any
1865                    embedded conformant array. we will not parse any
1866                    pointers in this mode.
1867                 */
1868                 return offset;
1869         }
1870
1871         /*TOP LEVEL REFERENCE POINTER*/
1872         if( pointers_are_top_level
1873         &&(type==NDR_POINTER_REF) ){
1874                 proto_item *item;
1875                 proto_tree *tr;
1876
1877                 /* we must find out a nice way to do the length here */
1878                 item=proto_tree_add_text(tree, tvb, offset, 0,
1879                         "%s", text);
1880                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1881
1882                 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff, 
1883                                     hf_index, callback, callback_args);
1884                 goto after_ref_id;
1885         }
1886
1887         /*TOP LEVEL FULL POINTER*/
1888         if( pointers_are_top_level
1889         && (type==NDR_POINTER_PTR) ){
1890                 int idx;
1891                 guint32 id;
1892                 proto_item *item;
1893                 proto_tree *tr;
1894
1895                 /* get the referent id */
1896                 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1897
1898                 /* we got a NULL pointer */
1899                 if(id==0){
1900                         proto_tree_add_text(tree, tvb, offset-4, 4,
1901                                 "(NULL pointer) %s",text);
1902                         goto after_ref_id;
1903                 }
1904
1905                 /* see if we have seen this pointer before */
1906                 idx=find_pointer_index(id);
1907
1908                 /* we have seen this pointer before */
1909                 if(idx>=0){
1910                         proto_tree_add_text(tree, tvb, offset-4, 4,
1911                                 "(duplicate PTR) %s",text);
1912                         goto after_ref_id;
1913                 }
1914
1915                 /* new pointer */
1916                 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1917                         "%s", text);
1918                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1919                 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1920                 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index, 
1921                                     callback, callback_args);
1922                 goto after_ref_id;
1923         }
1924         /*TOP LEVEL UNIQUE POINTER*/
1925         if( pointers_are_top_level
1926         && (type==NDR_POINTER_UNIQUE) ){
1927                 guint32 id;
1928                 proto_item *item;
1929                 proto_tree *tr;
1930
1931                 /* get the referent id */
1932                 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1933
1934                 /* we got a NULL pointer */
1935                 if(id==0){
1936                         proto_tree_add_text(tree, tvb, offset-4, 4,
1937                                 "(NULL pointer) %s",text);
1938                         goto after_ref_id;
1939                 }
1940
1941                 /* new pointer */
1942                 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1943                         "%s", text);
1944                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1945                 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1946                 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff, 
1947                                     hf_index, callback, callback_args);
1948                 goto after_ref_id;
1949         }
1950
1951         /*EMBEDDED REFERENCE POINTER*/
1952         if( (!pointers_are_top_level)
1953         && (type==NDR_POINTER_REF) ){
1954                 guint32 id;
1955                 proto_item *item;
1956                 proto_tree *tr;
1957
1958                 /* get the referent id */
1959                 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1960
1961                 /* new pointer */
1962                 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1963                         "%s",text);
1964                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1965                 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1966                 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff, 
1967                                     hf_index, callback, callback_args);
1968                 goto after_ref_id;
1969         }
1970
1971         /*EMBEDDED UNIQUE POINTER*/
1972         if( (!pointers_are_top_level)
1973         && (type==NDR_POINTER_UNIQUE) ){
1974                 guint32 id;
1975                 proto_item *item;
1976                 proto_tree *tr;
1977
1978                 /* get the referent id */
1979                 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1980
1981                 /* we got a NULL pointer */
1982                 if(id==0){
1983                         proto_tree_add_text(tree, tvb, offset-4, 4,
1984                                 "(NULL pointer) %s", text);
1985                         goto after_ref_id;
1986                 }
1987
1988                 /* new pointer */
1989                 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1990                         "%s",text);
1991                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1992                 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1993                 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff, 
1994                                     hf_index, callback, callback_args);
1995                 goto after_ref_id;
1996         }
1997
1998         /*EMBEDDED FULL POINTER*/
1999         if( (!pointers_are_top_level)
2000         && (type==NDR_POINTER_PTR) ){
2001                 int idx;
2002                 guint32 id;
2003                 proto_item *item;
2004                 proto_tree *tr;
2005
2006                 /* get the referent id */
2007                 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
2008
2009                 /* we got a NULL pointer */
2010                 if(id==0){
2011                         proto_tree_add_text(tree, tvb, offset-4, 4,
2012                                 "(NULL pointer) %s",text);
2013                         goto after_ref_id;
2014                 }
2015
2016                 /* see if we have seen this pointer before */
2017                 idx=find_pointer_index(id);
2018
2019                 /* we have seen this pointer before */
2020                 if(idx>=0){
2021                         proto_tree_add_text(tree, tvb, offset-4, 4,
2022                                 "(duplicate PTR) %s",text);
2023                         goto after_ref_id;
2024                 }
2025
2026                 /* new pointer */
2027                 item=proto_tree_add_text(tree, tvb, offset-4, 4,
2028                         "%s", text);
2029                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2030                 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
2031                 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index, 
2032                                     callback, callback_args);
2033                 goto after_ref_id;
2034         }
2035
2036
2037 after_ref_id:
2038         /* After each top level pointer we have dissected we have to
2039            dissect all deferrals before we move on to the next top level
2040            argument */
2041         if(pointers_are_top_level==TRUE){
2042                 pointers_are_top_level=FALSE;
2043                 offset = dissect_deferred_pointers(pinfo, tvb, offset, drep);
2044                 pointers_are_top_level=TRUE;
2045         }
2046
2047         return offset;
2048 }
2049
2050 int
2051 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2052                     proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2053                     int type, char *text, int hf_index)
2054 {
2055         return dissect_ndr_pointer_cb(
2056                 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
2057                 NULL, NULL);
2058 }
2059
2060 static void
2061 show_stub_data (tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
2062                 dcerpc_auth_info *auth_info, gboolean is_encrypted)
2063 {
2064     int length, plain_length, auth_pad_len;
2065     guint auth_pad_offset;
2066
2067     /*
2068      * We don't show stub data unless we have some in the tvbuff;
2069      * however, in the protocol tree, we show, as the number of
2070      * bytes, the reported number of bytes, not the number of bytes
2071      * that happen to be in the tvbuff.
2072      */
2073     if (tvb_length_remaining (tvb, offset) > 0) {
2074         auth_pad_len = auth_info?auth_info->auth_pad_len:0;
2075         length = tvb_reported_length_remaining (tvb, offset);
2076
2077         /* if auth_pad_len is larger than length then we ignore auth_pad_len totally */
2078         plain_length = length - auth_pad_len;
2079         if (plain_length < 1) {
2080             plain_length = length;
2081             auth_pad_len = 0;
2082         }
2083         auth_pad_offset = offset + plain_length;
2084
2085         if (auth_info != NULL &&
2086             auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
2087             if (is_encrypted) {
2088                 proto_tree_add_text(dcerpc_tree, tvb, offset, length,
2089                                     "Encrypted stub data (%d byte%s)",
2090                                     length, plurality(length, "", "s"));
2091                 /* is the padding is still inside the encrypted blob, don't display it explicit */
2092                 auth_pad_len = 0;
2093             } else {
2094                 proto_tree_add_text(dcerpc_tree, tvb, offset, plain_length,
2095                                     "Decrypted stub data (%d byte%s)",
2096                                     plain_length, plurality(plain_length, "", "s"));
2097             }
2098         } else {
2099             proto_tree_add_text (dcerpc_tree, tvb, offset, plain_length,
2100                                  "Stub data (%d byte%s)", plain_length,
2101                                  plurality(plain_length, "", "s"));
2102         }
2103         /* If there is auth padding at the end of the stub, display it */
2104         if (auth_pad_len != 0) {
2105                 proto_tree_add_text (dcerpc_tree, tvb, auth_pad_offset,
2106                                      auth_pad_len,
2107                                      "Auth Padding (%u byte%s)",
2108                                      auth_pad_len,
2109                                      plurality(auth_pad_len, "", "s"));
2110             }
2111     }
2112 }
2113
2114 static int
2115 dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
2116                     proto_tree *dcerpc_tree,
2117                     tvbuff_t *volatile tvb, tvbuff_t *decrypted_tvb,
2118                     guint8 *drep, dcerpc_info *info,
2119                     dcerpc_auth_info *auth_info)
2120 {
2121     volatile gint offset = 0;
2122     dcerpc_uuid_key key;
2123     dcerpc_uuid_value *sub_proto;
2124     proto_tree *volatile sub_tree = NULL;
2125     dcerpc_sub_dissector *proc;
2126     gchar *name = NULL;
2127     dcerpc_dissect_fnct_t *volatile sub_dissect;
2128     const char *volatile saved_proto;
2129     void *volatile saved_private_data;
2130     guint length, reported_length;
2131     tvbuff_t *volatile stub_tvb;
2132     volatile guint auth_pad_len;
2133     volatile int auth_pad_offset;
2134 #ifdef _WIN32
2135     char UUID_NAME[MAX_PATH];
2136 #endif
2137
2138     key.uuid = info->call_data->uuid;
2139     key.ver = info->call_data->ver;
2140
2141
2142     if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == NULL
2143          || !proto_is_protocol_enabled(sub_proto->proto)) {
2144         /*
2145          * We don't have a dissector for this UUID, or the protocol
2146          * for that UUID is disabled.
2147          */
2148
2149         proto_tree_add_boolean_hidden(dcerpc_tree, hf_dcerpc_unknown_if_id,
2150                                           tvb, offset, 0, TRUE);
2151         if (check_col (pinfo->cinfo, COL_INFO)) {
2152 #ifdef _WIN32
2153                 if(ResolveWin32UUID(info->call_data->uuid, UUID_NAME, MAX_PATH))
2154                         col_append_fstr (pinfo->cinfo, COL_INFO, " [%s] UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x rpcver: %u",
2155                                 UUID_NAME, info->call_data->uuid.Data1, info->call_data->uuid.Data2, info->call_data->uuid.Data3, info->call_data->uuid.Data4[0],
2156                                 info->call_data->uuid.Data4[1], info->call_data->uuid.Data4[2], info->call_data->uuid.Data4[3],
2157                                 info->call_data->uuid.Data4[4], info->call_data->uuid.Data4[5], info->call_data->uuid.Data4[6],
2158                                 info->call_data->uuid.Data4[7], info->call_data->ver);
2159 else
2160 #endif
2161                 col_append_fstr (pinfo->cinfo, COL_INFO, " UNKUUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x rpcver: %u",
2162                         info->call_data->uuid.Data1, info->call_data->uuid.Data2, info->call_data->uuid.Data3, info->call_data->uuid.Data4[0],
2163                         info->call_data->uuid.Data4[1], info->call_data->uuid.Data4[2], info->call_data->uuid.Data4[3],
2164                         info->call_data->uuid.Data4[4], info->call_data->uuid.Data4[5], info->call_data->uuid.Data4[6],
2165                         info->call_data->uuid.Data4[7], info->call_data->ver);
2166         }
2167
2168         if (decrypted_tvb != NULL) {
2169             show_stub_data (decrypted_tvb, 0, dcerpc_tree, auth_info,
2170                             FALSE);
2171         } else
2172             show_stub_data (tvb, 0, dcerpc_tree, auth_info, TRUE);
2173         return -1;
2174     }
2175
2176     for (proc = sub_proto->procs; proc->name; proc++) {
2177         if (proc->num == info->call_data->opnum) {
2178             name = proc->name;
2179             break;
2180         }
2181     }
2182
2183     if (!name)
2184         name = "Unknown?!";
2185
2186     if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
2187         col_set_str (pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
2188     }
2189
2190     if (check_col (pinfo->cinfo, COL_INFO)) {
2191         col_add_fstr (pinfo->cinfo, COL_INFO, "%s %s",
2192                       name, (info->ptype == PDU_REQ) ? "request" : "response");
2193     }
2194
2195     if (tree) {
2196         proto_item *sub_item;
2197         sub_item = proto_tree_add_item (tree, sub_proto->proto_id, tvb, 0,
2198                                         -1, FALSE);
2199
2200         if (sub_item) {
2201             sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
2202             proto_item_append_text(sub_item, ", %s", name);
2203         }
2204
2205         /*
2206          * Put the operation number into the tree along with
2207          * the operation's name.
2208          */
2209
2210         if (sub_proto->opnum_hf != -1)
2211             proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
2212                                        tvb, 0, 0, info->call_data->opnum,
2213                                        "Operation: %s (%u)",
2214                                        name, info->call_data->opnum);
2215         else
2216             proto_tree_add_uint_format(sub_tree, hf_dcerpc_op, tvb,
2217                                        0, 0, info->call_data->opnum,
2218                                        "Operation: %s (%u)",
2219                                        name, info->call_data->opnum);
2220     }
2221
2222     sub_dissect = (info->ptype == PDU_REQ) ? 
2223             proc->dissect_rqst : proc->dissect_resp;
2224
2225     if (decrypted_tvb != NULL) {
2226         /* Either there was no encryption or we successfully decrypted
2227            the entrypted payload. */
2228         if (sub_dissect) {
2229             /* We have a subdissector - call it. */
2230             saved_proto = pinfo->current_proto;
2231             saved_private_data = pinfo->private_data;
2232             pinfo->current_proto = sub_proto->name;
2233             pinfo->private_data = (void *)info;
2234             
2235             init_ndr_pointer_list(pinfo);
2236
2237             /*
2238              * Remove the authentication padding from the stub data.
2239              */
2240             if (auth_info != NULL && auth_info->auth_pad_len != 0) {
2241                 length = tvb_length(decrypted_tvb);
2242                 reported_length = tvb_reported_length(decrypted_tvb);
2243                 if (reported_length >= auth_info->auth_pad_len) {
2244                     /*
2245                      * OK, the padding length isn't so big that it
2246                      * exceeds the stub length.  Trim the reported
2247                      * length of the tvbuff.
2248                      */
2249                     reported_length -= auth_info->auth_pad_len;
2250
2251                     /*
2252                      * If that exceeds the actual amount of data in
2253                      * the tvbuff (which means we have at least one
2254                      * byte of authentication padding in the tvbuff),
2255                      * trim the actual amount.
2256                      */
2257                     if (length > reported_length)
2258                         length = reported_length;
2259
2260                     stub_tvb = tvb_new_subset(tvb, 0, length, reported_length);
2261                     auth_pad_len = auth_info->auth_pad_len;
2262                     auth_pad_offset = reported_length;
2263                 } else {
2264                     /*
2265                      * The padding length exceeds the stub length.
2266                      * Don't bother dissecting the stub, trim the padding
2267                      * length to what's in the stub data, and show the
2268                      * entire stub as authentication padding.
2269                      */
2270                     stub_tvb = NULL;
2271                     auth_pad_len = reported_length;
2272                     auth_pad_offset = 0;
2273                 }
2274             } else {
2275                 /*
2276                  * No authentication padding.
2277                  */
2278                 stub_tvb = decrypted_tvb;
2279                 auth_pad_len = 0;
2280                 auth_pad_offset = 0;
2281             }
2282
2283             if (stub_tvb != NULL) {
2284                 /*
2285                  * Catch all exceptions other than BoundsError, so that even
2286                  * if the stub data is bad, we still show the authentication
2287                  * padding, if any.
2288                  *
2289                  * If we get BoundsError, it means the frame was cut short
2290                  * by a snapshot length, so there's nothing more to
2291                  * dissect; just re-throw that exception.
2292                  */
2293                 TRY {
2294                     offset = sub_dissect (decrypted_tvb, 0, pinfo, sub_tree,
2295                                           drep);
2296
2297                     /* If we have a subdissector and it didn't dissect all
2298                        data in the tvb, make a note of it. */
2299
2300                     if (tvb_reported_length_remaining(stub_tvb, offset) > 0) {
2301                         if (check_col(pinfo->cinfo, COL_INFO))
2302                             col_append_fstr(pinfo->cinfo, COL_INFO,
2303                                             "[Long frame (%d bytes)]",
2304                                             tvb_reported_length_remaining(stub_tvb, offset));
2305                     }
2306                 } CATCH(BoundsError) {
2307                     RETHROW;
2308                 } CATCH_ALL {
2309                     show_exception(decrypted_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
2310                 } ENDTRY;
2311             }
2312
2313             /* If there is auth padding at the end of the stub, display it */
2314             if (auth_pad_len != 0) {
2315                 proto_tree_add_text (sub_tree, decrypted_tvb, auth_pad_offset,
2316                                      auth_pad_len,
2317                                      "Auth Padding (%u byte%s)",
2318                                      auth_pad_len,
2319                                      plurality(auth_pad_len, "", "s"));
2320             }
2321
2322             pinfo->current_proto = saved_proto;
2323             pinfo->private_data = saved_private_data;
2324         } else {
2325             /* No subdissector - show it as stub data. */
2326             if(decrypted_tvb){
2327                show_stub_data (decrypted_tvb, 0, sub_tree, auth_info, FALSE);
2328             } else {
2329                show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
2330             }
2331         }
2332     } else
2333         show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
2334
2335     tap_queue_packet(dcerpc_tap, pinfo, info);
2336     return 0;
2337 }
2338
2339 static int
2340 dissect_dcerpc_verifier (tvbuff_t *tvb, packet_info *pinfo, 
2341                          proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
2342                          dcerpc_auth_info *auth_info)
2343 {
2344     int auth_offset;
2345
2346     auth_info->auth_data = NULL;
2347
2348     if (auth_info->auth_size != 0) {
2349         dcerpc_auth_subdissector_fns *auth_fns;
2350         tvbuff_t *auth_tvb;
2351
2352         auth_offset = hdr->frag_len - hdr->auth_len;
2353
2354         auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
2355                                   hdr->auth_len);
2356
2357         auth_info->auth_data = auth_tvb;
2358
2359         if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
2360                                                   auth_info->auth_type))) {
2361             /*
2362              * Catch all exceptions, so that even if the verifier is bad
2363              * or we don't have all of it, we still show the stub data.
2364              */
2365             TRY {
2366                 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
2367                                   hdr, auth_info);
2368             } CATCH_ALL {
2369                 show_exception(auth_tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
2370             } ENDTRY;
2371         } else {
2372             proto_tree_add_text (dcerpc_tree, auth_tvb, 0, hdr->auth_len,
2373                                  "Auth Verifier");
2374         }
2375     }
2376
2377     return hdr->auth_len;
2378 }
2379
2380 static void
2381 dissect_dcerpc_cn_auth (tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
2382                         proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
2383                         gboolean are_credentials, dcerpc_auth_info *auth_info)
2384 {
2385     volatile int offset;
2386
2387     /*
2388      * Initially set auth_level and auth_type to zero to indicate that we 
2389      * haven't yet seen any authentication level information.
2390      */
2391     auth_info->auth_level = 0;
2392     auth_info->auth_type = 0;
2393     auth_info->auth_size = 0;
2394     auth_info->auth_pad_len = 0;
2395     
2396     /*
2397      * The authentication information is at the *end* of the PDU; in
2398      * request and response PDUs, the request and response stub data
2399      * come before it.
2400      *
2401      * Is there any authentication data (i.e., is the authentication length
2402      * non-zero), and is the authentication length valid (i.e., is it, plus
2403      * 8 bytes for the type/level/pad length/reserved/context id, less than
2404      * or equal to the fragment length minus the starting offset of the
2405      * stub data?)
2406      */
2407
2408     if (hdr->auth_len
2409         && (hdr->auth_len + 8 <= hdr->frag_len - stub_offset)) {
2410
2411         /*
2412          * Yes, there is authentication data, and the length is valid.
2413          * Do we have all the bytes of stub data?
2414          * (If not, we'd throw an exception dissecting *that*, so don't
2415          * bother trying to dissect the authentication information and
2416          * throwing another exception there.)
2417          */
2418         offset = hdr->frag_len - (hdr->auth_len + 8);
2419         if (offset == 0 || tvb_offset_exists(tvb, offset - 1)) {
2420             /*
2421              * Either there's no stub data, or the last byte of the stub
2422              * data is present in the captured data, so we shouldn't
2423              * get a BoundsError dissecting the stub data.
2424              *
2425              * Try dissecting the authentication data.
2426              * Catch all exceptions, so that even if the auth info is bad
2427              * or we don't have all of it, we still show the stuff we
2428              * dissect after this, such as stub data.
2429              */
2430             TRY {
2431                 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2432                                                hf_dcerpc_auth_type, 
2433                                                &auth_info->auth_type);
2434                 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2435                                                hf_dcerpc_auth_level, 
2436                                                &auth_info->auth_level);
2437
2438                 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2439                                                hf_dcerpc_auth_pad_len, 
2440                                                &auth_info->auth_pad_len);
2441                 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2442                                                hf_dcerpc_auth_rsrvd, NULL);
2443                 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2444                                                 hf_dcerpc_auth_ctx_id, NULL);
2445
2446                 /*
2447                  * Dissect the authentication data.
2448                  */
2449                 if (are_credentials) {
2450                     tvbuff_t *auth_tvb;
2451                     dcerpc_auth_subdissector_fns *auth_fns;
2452
2453                     auth_tvb = tvb_new_subset(tvb, offset, hdr->auth_len,
2454                                               hdr->auth_len);
2455
2456                     if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
2457                                                               auth_info->auth_type)))
2458                         dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns, 
2459                                           hdr, auth_info);
2460                     else
2461                         proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len,
2462                                              "Auth Credentials");
2463                 }
2464         
2465                 /* Compute the size of the auth block.  Note that this should not 
2466                    include auth padding, since when NTLMSSP encryption is used, the
2467                    padding is actually inside the encrypted stub */
2468                    auth_info->auth_size = hdr->auth_len + 8;
2469             } CATCH_ALL {
2470                 show_exception(tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
2471             } ENDTRY;
2472         }
2473     }
2474 }
2475
2476
2477 /* We need to hash in the SMB fid number to generate a unique hash table
2478  * key as DCERPC over SMB allows several pipes over the same TCP/IP
2479  * socket. 
2480  * We pass this function the transport type here to make sure we only look
2481  * at this function if it came across an SMB pipe.
2482  * Other transports might need to mix in their own extra multiplexing data
2483  * as well in the future.
2484  */
2485
2486 guint16 dcerpc_get_transport_salt (packet_info *pinfo)
2487 {
2488     switch(pinfo->dcetransporttype){
2489         case DCE_CN_TRANSPORT_SMBPIPE:
2490             /* DCERPC over smb */
2491             return pinfo->dcetransportsalt;
2492     }
2493
2494     /* Some other transport... */
2495     return 0;
2496 }
2497
2498 /*
2499  * Connection oriented packet types
2500  */
2501
2502 static void
2503 dissect_dcerpc_cn_bind (tvbuff_t *tvb, gint offset, packet_info *pinfo, 
2504                         proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2505 {
2506     conversation_t *conv = NULL;
2507     guint8 num_ctx_items = 0;
2508     guint i;
2509     gboolean saw_ctx_item = FALSE;
2510     guint16 ctx_id;
2511     guint8 num_trans_items;
2512     guint j;
2513     e_uuid_t if_id;
2514     e_uuid_t trans_id;
2515     guint32 trans_ver;
2516     guint16 if_ver, if_ver_minor;
2517     char uuid_str[DCERPC_UUID_STR_LEN]; 
2518     int uuid_str_len;
2519     dcerpc_auth_info auth_info;
2520 #ifdef _WIN32
2521     char UUID_NAME[MAX_PATH];
2522 #endif
2523
2524     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2525                                     hf_dcerpc_cn_max_xmit, NULL);
2526
2527     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2528                                     hf_dcerpc_cn_max_recv, NULL);
2529
2530     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2531                                     hf_dcerpc_cn_assoc_group, NULL);
2532
2533     offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2534                                     hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
2535
2536     /* padding */
2537     offset += 3;
2538
2539     for (i = 0; i < num_ctx_items; i++) {
2540             proto_tree *ctx_tree = NULL, *iface_tree = NULL;
2541
2542       offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, NULL, hdr->drep,
2543                                       hf_dcerpc_cn_ctx_id, &ctx_id);
2544
2545       /* save context ID for use with dcerpc_add_conv_to_bind_table() */
2546       /* (if we have multiple contexts, this might cause "decode as"
2547        *  to behave unpredictably) */
2548       pinfo->dcectxid = ctx_id;
2549
2550       if (dcerpc_tree) {
2551               proto_item *ctx_item;
2552
2553               ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_id,
2554                                              tvb, offset - 2, 2, 
2555                                              hdr->drep[0] & 0x10);
2556
2557               ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
2558       }
2559
2560       offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, ctx_tree, hdr->drep,
2561                                       hf_dcerpc_cn_num_trans_items, &num_trans_items);
2562
2563       /* padding */
2564       offset += 1;
2565
2566       /* XXX - use "dissect_ndr_uuid_t()"? */
2567       dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
2568       if (ctx_tree) {
2569           proto_item *iface_item;
2570
2571           uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, 
2572                                   "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2573                                   if_id.Data1, if_id.Data2, if_id.Data3,
2574                                   if_id.Data4[0], if_id.Data4[1],
2575                                   if_id.Data4[2], if_id.Data4[3],
2576                                   if_id.Data4[4], if_id.Data4[5],
2577                                   if_id.Data4[6], if_id.Data4[7]);
2578
2579           if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2580                   memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2581 #ifdef _WIN32
2582           if(ResolveWin32UUID(if_id, UUID_NAME, MAX_PATH))
2583                   iface_item = proto_tree_add_string_format (ctx_tree, hf_dcerpc_cn_bind_if_id, tvb,
2584                                         offset, 16, uuid_str, "Interface [%s] UUID: %s", UUID_NAME, uuid_str);
2585           else
2586 #endif
2587           iface_item = proto_tree_add_string_format (ctx_tree, hf_dcerpc_cn_bind_if_id, tvb,
2588                                         offset, 16, uuid_str, "Interface UUID: %s", uuid_str);
2589           iface_tree = proto_item_add_subtree(iface_item, ett_dcerpc_cn_iface);
2590       }
2591       offset += 16;
2592
2593       if (hdr->drep[0] & 0x10) {
2594           offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2595                                           hf_dcerpc_cn_bind_if_ver, &if_ver);
2596           offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2597                                           hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2598       } else {
2599           offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2600                                           hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2601           offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2602                                           hf_dcerpc_cn_bind_if_ver, &if_ver);
2603       }
2604
2605       if (!saw_ctx_item) {
2606         conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
2607                                   pinfo->srcport, pinfo->destport, 0);
2608         if (conv == NULL) {
2609             conv = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
2610                                      pinfo->srcport, pinfo->destport, 0);
2611         }
2612
2613
2614         /* if this is the first time we see this packet, we need to
2615            update the dcerpc_binds table so that any later calls can
2616            match to the interface.
2617            XXX We assume that BINDs will NEVER be fragmented.
2618         */
2619         if(!(pinfo->fd->flags.visited)){
2620                 dcerpc_bind_key *key;
2621                 dcerpc_bind_value *value;
2622
2623                 key = g_mem_chunk_alloc (dcerpc_bind_key_chunk);
2624                 key->conv = conv;
2625                 key->ctx_id = ctx_id;
2626                 key->smb_fid = dcerpc_get_transport_salt(pinfo);
2627
2628                 value = g_mem_chunk_alloc (dcerpc_bind_value_chunk);
2629                 value->uuid = if_id;
2630                 value->ver = if_ver;
2631
2632                 /* add this entry to the bind table, first removing any
2633                    previous ones that are identical
2634                  */
2635                 if(g_hash_table_lookup(dcerpc_binds, key)){
2636                         g_hash_table_remove(dcerpc_binds, key);
2637                 }
2638                 g_hash_table_insert (dcerpc_binds, key, value);
2639         }
2640
2641         if (check_col (pinfo->cinfo, COL_INFO)) {
2642           dcerpc_uuid_key key;
2643           dcerpc_uuid_value *value;
2644
2645           key.uuid = if_id;
2646           key.ver = if_ver;
2647
2648           if (num_ctx_items > 1)
2649                   col_append_fstr(pinfo->cinfo, COL_INFO, ", %u context items, 1st", num_ctx_items);
2650                 
2651           if ((value = g_hash_table_lookup(dcerpc_uuids, &key)))
2652                   col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %s", value->name);
2653           else
2654 #ifdef _WIN32
2655                 if(ResolveWin32UUID(if_id, UUID_NAME, MAX_PATH))
2656                         col_append_fstr(pinfo->cinfo, COL_INFO, " [%s] UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
2657                            UUID_NAME, if_id.Data1, if_id.Data2, if_id.Data3,
2658                            if_id.Data4[0], if_id.Data4[1],
2659                            if_id.Data4[2], if_id.Data4[3],
2660                            if_id.Data4[4], if_id.Data4[5],
2661                            if_id.Data4[6], if_id.Data4[7],
2662                            if_ver, if_ver_minor);
2663           else
2664 #endif
2665                         col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
2666                            if_id.Data1, if_id.Data2, if_id.Data3,
2667                            if_id.Data4[0], if_id.Data4[1],
2668                            if_id.Data4[2], if_id.Data4[3],
2669                            if_id.Data4[4], if_id.Data4[5],
2670                            if_id.Data4[6], if_id.Data4[7],
2671                            if_ver, if_ver_minor);
2672         }
2673         saw_ctx_item = TRUE;
2674       }
2675
2676       for (j = 0; j < num_trans_items; j++) {
2677         /* XXX - use "dissect_ndr_uuid_t()"? */
2678         dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2679         if (iface_tree) {
2680             uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, 
2681                                   "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2682                                   trans_id.Data1, trans_id.Data2, trans_id.Data3,
2683                                   trans_id.Data4[0], trans_id.Data4[1],
2684                                   trans_id.Data4[2], trans_id.Data4[3],
2685                                   trans_id.Data4[4], trans_id.Data4[5],
2686                                   trans_id.Data4[6], trans_id.Data4[7]);
2687             if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2688                 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2689             proto_tree_add_string_format (iface_tree, hf_dcerpc_cn_bind_trans_id, tvb,
2690                                           offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2691         }
2692         offset += 16;
2693
2694         offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, iface_tree, hdr->drep,
2695                                         hf_dcerpc_cn_bind_trans_ver, &trans_ver);
2696       }
2697     }
2698
2699     /*
2700      * XXX - we should save the authentication type *if* we have
2701      * an authentication header, and associate it with an authentication
2702      * context, so subsequent PDUs can use that context.
2703      */
2704     dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2705 }
2706
2707 static void
2708 dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, gint offset, packet_info *pinfo, 
2709                             proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2710 {
2711     guint16 max_xmit, max_recv;
2712     guint16 sec_addr_len;
2713     guint8 num_results;
2714     guint i;
2715     guint16 result;
2716     guint16 reason;
2717     e_uuid_t trans_id;
2718     guint32 trans_ver;
2719     char uuid_str[DCERPC_UUID_STR_LEN]; 
2720     int uuid_str_len;
2721     dcerpc_auth_info auth_info;
2722
2723     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2724                                     hf_dcerpc_cn_max_xmit, &max_xmit);
2725
2726     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2727                                     hf_dcerpc_cn_max_recv, &max_recv);
2728
2729     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2730                                     hf_dcerpc_cn_assoc_group, NULL);
2731
2732     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2733                                     hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
2734     if (sec_addr_len != 0) {
2735         proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
2736                              sec_addr_len, FALSE);
2737         offset += sec_addr_len;
2738     }
2739
2740     if (offset % 4) {
2741         offset += 4 - offset % 4;
2742     }
2743
2744     offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2745                                    hf_dcerpc_cn_num_results, &num_results);
2746
2747     /* padding */
2748     offset += 3;
2749
2750     for (i = 0; i < num_results; i++) {
2751         offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2752                                         hdr->drep, hf_dcerpc_cn_ack_result,
2753                                         &result);
2754         if (result != 0) {
2755             offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2756                                             hdr->drep, hf_dcerpc_cn_ack_reason,
2757                                             &reason);
2758         } else {
2759             /*
2760              * The reason for rejection isn't meaningful, and often isn't
2761              * set, when the syntax was accepted.
2762              */
2763             offset += 2;
2764         }
2765
2766         /* XXX - use "dissect_ndr_uuid_t()"? */
2767         dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2768         if (dcerpc_tree) {
2769             uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, 
2770                                   "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2771                                   trans_id.Data1, trans_id.Data2, trans_id.Data3,
2772                                   trans_id.Data4[0], trans_id.Data4[1],
2773                                   trans_id.Data4[2], trans_id.Data4[3],
2774                                   trans_id.Data4[4], trans_id.Data4[5],
2775                                   trans_id.Data4[6], trans_id.Data4[7]);
2776             if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2777                   memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2778             proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_ack_trans_id, tvb,
2779                                           offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2780         }
2781         offset += 16;
2782
2783         offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2784                                         hf_dcerpc_cn_ack_trans_ver, &trans_ver);
2785     }
2786
2787     /*
2788      * XXX - do we need to do anything with the authentication level
2789      * we get back from this?
2790      */
2791     dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2792
2793     if (check_col (pinfo->cinfo, COL_INFO)) {
2794         if (num_results != 0 && result == 0) {
2795             /* XXX - only checks the last result */
2796             col_append_fstr (pinfo->cinfo, COL_INFO,
2797                              " accept max_xmit: %u max_recv: %u",
2798                              max_xmit, max_recv);
2799         } else {
2800             /* XXX - only shows the last result and reason */
2801             col_append_fstr (pinfo->cinfo, COL_INFO, " %s, reason: %s",
2802                              val_to_str(result, p_cont_result_vals,
2803                                         "Unknown result (%u)"),
2804                              val_to_str(reason, p_provider_reason_vals,
2805                                         "Unknown (%u)"));
2806         }
2807     }
2808 }
2809
2810 static void
2811 dissect_dcerpc_cn_bind_nak (tvbuff_t *tvb, gint offset, packet_info *pinfo, 
2812                             proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2813 {
2814     guint16 reason;
2815     guint8 num_protocols;
2816     guint i;
2817
2818     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2819                                     hdr->drep, hf_dcerpc_cn_reject_reason,
2820                                     &reason);
2821
2822     if (check_col (pinfo->cinfo, COL_INFO)) {
2823         col_append_fstr (pinfo->cinfo, COL_INFO, " reason: %s",
2824                       val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
2825     }
2826
2827     if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
2828         offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2829                                        hf_dcerpc_cn_num_protocols,
2830                                        &num_protocols);
2831
2832         for (i = 0; i < num_protocols; i++) {
2833             offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2834                                         hdr->drep, hf_dcerpc_cn_protocol_ver_major,
2835                                         NULL);
2836             offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2837                                         hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
2838                                         NULL);
2839         }
2840     }
2841 }
2842
2843 /* Return a string describing a DCE/RPC fragment as first, middle, or end
2844    fragment. */
2845
2846 #define PFC_FRAG_MASK  0x03
2847
2848 static char *
2849 fragment_type(guint8 flags)
2850 {
2851         flags = flags & PFC_FRAG_MASK;
2852
2853         if (flags == PFC_FIRST_FRAG)
2854                 return "first";
2855
2856         if (flags == 0)
2857                 return "middle";
2858
2859         if (flags == PFC_LAST_FRAG)
2860                 return "last";
2861
2862         if (flags == (PFC_FIRST_FRAG | PFC_LAST_FRAG))
2863                 return "whole";
2864
2865         return "unknown";
2866 }
2867
2868 /* Dissect stub data (payload) of a DCERPC packet. */
2869
2870 static void
2871 dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
2872                         proto_tree *dcerpc_tree, proto_tree *tree,
2873                         e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
2874                         dcerpc_auth_info *auth_info, guint32 alloc_hint,
2875                         guint32 frame)
2876 {
2877     gint length, reported_length;
2878     gboolean save_fragmented;
2879     fragment_data *fd_head=NULL;
2880     guint32 tot_len;
2881     tvbuff_t *auth_tvb, *payload_tvb, *decrypted_tvb;
2882     proto_item *pi;
2883
2884     save_fragmented = pinfo->fragmented;
2885
2886     length = tvb_length_remaining(tvb, offset);
2887     reported_length = tvb_reported_length_remaining(tvb, offset);
2888     if (reported_length < 0 ||
2889         (guint32)reported_length < auth_info->auth_size) {
2890         /* We don't even have enough bytes for the authentication
2891            stuff. */
2892         return;
2893     }
2894     reported_length -= auth_info->auth_size;
2895     if (length > reported_length)
2896         length = reported_length;
2897     payload_tvb = tvb_new_subset(tvb, offset, length, reported_length);
2898
2899     auth_tvb=NULL;
2900     /*dont bother if we dont have the entire tvb */
2901     /*XXX we should really make sure we calculate auth_info->auth_data
2902         and use that one instead of this auth_tvb hack
2903     */
2904     if(tvb_length(tvb)==tvb_reported_length(tvb)){
2905         if(tvb_length_remaining(tvb, offset+length)>8){
2906             auth_tvb = tvb_new_subset(tvb, offset+length+8, -1, -1);
2907         }
2908     }
2909
2910     /* Decrypt the PDU if it is encrypted */
2911
2912     if (auth_info->auth_type &&
2913         auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
2914             /*
2915              * We know the authentication type, and the authentication
2916              * level is "Packet privacy", meaning the payload is
2917              * encrypted; attempt to decrypt it.
2918              */
2919             dcerpc_auth_subdissector_fns *auth_fns;
2920             
2921             /* Start out assuming we won't succeed in decrypting. */
2922             decrypted_tvb = NULL;
2923
2924             if ((auth_fns = get_auth_subdissector_fns(
2925                          auth_info->auth_level, auth_info->auth_type))) {
2926                     tvbuff_t *result;
2927
2928                     result = decode_encrypted_data(
2929                             payload_tvb, auth_tvb, pinfo, auth_fns,
2930                             hdr->ptype == PDU_REQ, auth_info);      
2931                     
2932                     if (result) {
2933                             if (dcerpc_tree)
2934                                 proto_tree_add_text(
2935                                             dcerpc_tree, payload_tvb, 0, -1,
2936                                             "Encrypted stub data (%d byte%s)",
2937                                             tvb_reported_length(payload_tvb),
2938
2939                             plurality(tvb_length(payload_tvb), "", "s"));
2940
2941                             add_new_data_source(
2942                                     pinfo, result, "Decrypted stub data");
2943                             
2944                             /* We succeeded. */
2945                             decrypted_tvb = result;
2946                     }
2947             }
2948     } else
2949             decrypted_tvb = payload_tvb;
2950
2951     /* if this packet is not fragmented, just dissect it and exit */
2952     if(PFC_NOT_FRAGMENTED(hdr)){
2953         pinfo->fragmented = FALSE;
2954
2955         dcerpc_try_handoff(
2956                 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
2957                 hdr->drep, di, auth_info);
2958         
2959         pinfo->fragmented = save_fragmented;
2960         return;
2961     }
2962
2963     /* The packet is fragmented. */
2964     pinfo->fragmented = TRUE;
2965
2966     /* if we are not doing reassembly and this is the first fragment
2967        then just dissect it and exit
2968        XXX - if we're not doing reassembly, can we decrypt an
2969        encrypted stub?
2970     */
2971     if( (!dcerpc_reassemble) && hdr->flags&PFC_FIRST_FRAG ){
2972
2973         dcerpc_try_handoff(
2974                 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
2975                 hdr->drep, di, auth_info);
2976         
2977         if (check_col(pinfo->cinfo, COL_INFO)) {
2978             col_append_fstr(pinfo->cinfo, COL_INFO,
2979                             " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
2980         }
2981         pinfo->fragmented = save_fragmented;
2982         return;
2983     }
2984
2985     /* if we have already seen this packet, see if it was reassembled
2986        and if so dissect the full pdu.
2987        then exit 
2988     */
2989     if(pinfo->fd->flags.visited){
2990         fd_head=fragment_get(pinfo, frame, dcerpc_co_reassemble_table);
2991         goto end_cn_stub;
2992     }
2993
2994     /* if we are not doing reassembly and it was neither a complete PDU
2995        nor the first fragment then there is nothing more we can do
2996        so we just have to exit
2997     */
2998     if( !dcerpc_reassemble )
2999         goto end_cn_stub;
3000
3001     /* if we didnt get 'frame' we dont know where the PDU started and thus
3002        it is pointless to continue 
3003     */
3004     if(!frame)
3005         goto end_cn_stub;
3006
3007     /* from now on we must attempt to reassemble the PDU 
3008     */
3009
3010     /* if we get here we know it is the first time we see the packet
3011        and we also know it is only a fragment and not a full PDU,
3012        thus we must reassemble it.
3013     */
3014
3015     /* Do we have any non-encrypted data to reassemble? */
3016     if (decrypted_tvb == NULL) {
3017       /* No.  We can't even try to reassemble.  */
3018       goto end_cn_stub;
3019     }
3020
3021     /* defragmentation is a bit tricky here, as there's no offset of the fragment 
3022      * in the protocol data.
3023      *
3024      * Currently two possible ways:
3025      * - the transmitter sends an alloc_hint != 0, use it
3026      * - the transmitter sends an alloc_hint == 0, simply append fragments
3027      */
3028
3029     /* if this is the first fragment we need to start reassembly
3030     */
3031     if(hdr->flags&PFC_FIRST_FRAG){
3032         fragment_add(decrypted_tvb, 0, pinfo, frame, dcerpc_co_reassemble_table,
3033                      0, tvb_length(decrypted_tvb), TRUE);
3034         fragment_set_tot_len(pinfo, frame,
3035         dcerpc_co_reassemble_table, alloc_hint ? alloc_hint : tvb_length(decrypted_tvb));
3036
3037         goto end_cn_stub;
3038     }
3039
3040     /* if this is a middle fragment, just add it and exit */
3041     if(!(hdr->flags&PFC_LAST_FRAG)){
3042         tot_len = fragment_get_tot_len(pinfo, frame,
3043                  dcerpc_co_reassemble_table);
3044         fragment_add(decrypted_tvb, 0, pinfo, frame,
3045                  dcerpc_co_reassemble_table,
3046                  tot_len-alloc_hint, tvb_length(decrypted_tvb),
3047                  TRUE);
3048         if(alloc_hint == 0) {
3049              fragment_set_tot_len(pinfo, frame,
3050                   dcerpc_co_reassemble_table, tot_len + tvb_length(decrypted_tvb));
3051         }
3052
3053         goto end_cn_stub;
3054     }
3055
3056     /* this was the last fragment add it to reassembly
3057     */
3058     tot_len = fragment_get_tot_len(pinfo, frame,
3059                 dcerpc_co_reassemble_table);
3060     fd_head = fragment_add(decrypted_tvb, 0, pinfo,
3061                 frame,
3062                 dcerpc_co_reassemble_table,
3063                 tot_len-alloc_hint, tvb_length(decrypted_tvb),
3064                 TRUE);
3065         if(alloc_hint == 0) {           
3066             fragment_set_tot_len(pinfo, frame,
3067                   dcerpc_co_reassemble_table, tot_len + tvb_length(decrypted_tvb));
3068     }
3069
3070 end_cn_stub:
3071
3072     /* if reassembly is complete, dissect the full PDU
3073     */
3074     if(fd_head && (fd_head->flags&FD_DEFRAGMENTED) ){
3075
3076         if(pinfo->fd->num==fd_head->reassembled_in){
3077             tvbuff_t *next_tvb;
3078
3079             next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
3080             tvb_set_child_real_data_tvbuff(decrypted_tvb, next_tvb);
3081             add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3082             show_fragment_tree(fd_head, &dcerpc_frag_items,
3083                 dcerpc_tree, pinfo, next_tvb);
3084
3085             pinfo->fragmented = FALSE;
3086
3087             dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
3088                 next_tvb, hdr->drep, di, auth_info);
3089
3090         } else {
3091             pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
3092                                 decrypted_tvb, 0, 0, fd_head->reassembled_in);
3093         PROTO_ITEM_SET_GENERATED(pi);
3094             if (check_col(pinfo->cinfo, COL_INFO)) {
3095                 col_append_fstr(pinfo->cinfo, COL_INFO,
3096                         " [DCE/RPC %s fragment, reas: #%u]", fragment_type(hdr->flags), fd_head->reassembled_in);
3097             }
3098         }
3099     } else {
3100         /* Reassembly not complete - some fragments
3101            are missing.  Just show the stub data. */
3102
3103         if (check_col(pinfo->cinfo, COL_INFO)) {
3104             col_append_fstr(pinfo->cinfo, COL_INFO,
3105                         " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
3106         }
3107
3108         if(decrypted_tvb){
3109                 show_stub_data (decrypted_tvb, 0, tree, auth_info, FALSE);
3110         } else {
3111                 show_stub_data (payload_tvb, 0, tree, auth_info, TRUE);
3112         }
3113     }
3114
3115     pinfo->fragmented = save_fragmented;
3116 }
3117
3118 /**
3119  *  Registers a conversation/UUID binding association, so that
3120  *  we can invoke the proper sub-dissector for a given DCERPC
3121  *  conversation.
3122  * 
3123  *  @param binding all values needed to create and bind a new conversation
3124  * 
3125  *  @return Pointer to newly-added UUID/conversation binding.
3126  */
3127 struct _dcerpc_bind_value *
3128 dcerpc_add_conv_to_bind_table(decode_dcerpc_bind_values_t *binding)
3129 {
3130     dcerpc_bind_value *bind_value;
3131     dcerpc_bind_key *key;
3132     conversation_t *conv;
3133
3134     conv = find_conversation (
3135         0, 
3136         &binding->addr_a, 
3137         &binding->addr_b, 
3138         binding->ptype, 
3139         binding->port_a, 
3140         binding->port_b, 
3141         0);
3142
3143     if (!conv) {
3144         conv = conversation_new (
3145             0, 
3146             &binding->addr_a, 
3147             &binding->addr_b, 
3148             binding->ptype, 
3149             binding->port_a, 
3150             binding->port_b, 
3151             0);
3152     }
3153     
3154     bind_value = g_mem_chunk_alloc (dcerpc_bind_value_chunk);
3155     bind_value->uuid = binding->uuid;
3156     bind_value->ver = binding->ver;
3157
3158     key = g_mem_chunk_alloc(dcerpc_bind_key_chunk);
3159     key->conv = conv;
3160     key->ctx_id = binding->ctx_id;
3161     key->smb_fid = binding->smb_fid;
3162  
3163     /* add this entry to the bind table, first removing any
3164        previous ones that are identical
3165      */
3166     if(g_hash_table_lookup(dcerpc_binds, key)){
3167             g_hash_table_remove(dcerpc_binds, key);
3168     }
3169     g_hash_table_insert(dcerpc_binds, key, bind_value);
3170
3171     return bind_value;
3172
3173 }
3174
3175 static void
3176 dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo, 
3177                         proto_tree *dcerpc_tree, proto_tree *tree,
3178                         e_dce_cn_common_hdr_t *hdr)
3179 {
3180     conversation_t *conv;
3181     guint16 ctx_id;
3182     guint16 opnum;
3183     e_uuid_t obj_id;
3184     dcerpc_auth_info auth_info;
3185     guint32 alloc_hint;
3186     char uuid_str[DCERPC_UUID_STR_LEN]; 
3187     int uuid_str_len;
3188     proto_item *pi;
3189
3190     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3191                                     hf_dcerpc_cn_alloc_hint, &alloc_hint);
3192
3193     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3194                                     hf_dcerpc_cn_ctx_id, &ctx_id);
3195
3196     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3197                                     hf_dcerpc_opnum, &opnum);
3198
3199     /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3200     pinfo->dcectxid = ctx_id;
3201
3202     if (check_col (pinfo->cinfo, COL_INFO)) {
3203         col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u ctx_id: %u",
3204                          opnum, ctx_id);
3205     }
3206
3207     if (hdr->flags & PFC_OBJECT_UUID) {
3208         /* XXX - use "dissect_ndr_uuid_t()"? */
3209         dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id);
3210         if (dcerpc_tree) {
3211             uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, 
3212                                     "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3213                                     obj_id.Data1, obj_id.Data2, obj_id.Data3,
3214                                     obj_id.Data4[0],
3215                                     obj_id.Data4[1],
3216                                     obj_id.Data4[2],
3217                                     obj_id.Data4[3],
3218                                     obj_id.Data4[4],
3219                                     obj_id.Data4[5],
3220                                     obj_id.Data4[6],
3221                                     obj_id.Data4[7]);
3222             if (uuid_str_len >= DCERPC_UUID_STR_LEN)
3223                   memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
3224             proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
3225                                           offset, 16, uuid_str, "Object UUID: %s", uuid_str);
3226         }
3227         offset += 16;
3228     }
3229
3230     /*
3231      * XXX - what if this was set when the connection was set up,
3232      * and we just have a security context?
3233      */
3234     dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3235
3236     conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3237                               pinfo->srcport, pinfo->destport, 0);
3238     if (!conv)
3239         show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3240     else {
3241         dcerpc_matched_key matched_key, *new_matched_key;
3242         dcerpc_call_value *value;
3243
3244         /* !!! we can NOT check flags.visited here since this will interact
3245            badly with when SMB handles (i.e. calls the subdissector)
3246            and desegmented pdu's .
3247            Instead we check if this pdu is already in the matched table or not
3248         */
3249         matched_key.frame = pinfo->fd->num;
3250         matched_key.call_id = hdr->call_id;
3251         value = g_hash_table_lookup(dcerpc_matched, &matched_key);
3252         if(!value){
3253                 dcerpc_bind_key bind_key;
3254                 dcerpc_bind_value *bind_value;
3255
3256                 bind_key.conv=conv;
3257                 bind_key.ctx_id=ctx_id;
3258                 bind_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3259
3260                 if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key)) ){
3261                         if(!(hdr->flags&PFC_FIRST_FRAG)){
3262                                 dcerpc_cn_call_key call_key;
3263                                 dcerpc_call_value *call_value;
3264
3265                                 call_key.conv=conv;
3266                                 call_key.call_id=hdr->call_id;
3267                                 call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3268                                 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3269                                         new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3270                                         *new_matched_key = matched_key;
3271                                         g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3272                                         value = call_value;
3273                                 }
3274                         } else {
3275                                 dcerpc_cn_call_key *call_key;
3276                                 dcerpc_call_value *call_value;
3277
3278                                 /* We found the binding and it is the first fragment 
3279                                    (or a complete PDU) of a dcerpc pdu so just add 
3280                                    the call to both the call table and the 
3281                                    matched table
3282                                 */
3283                                 call_key=g_mem_chunk_alloc (dcerpc_cn_call_key_chunk);
3284                                 call_key->conv=conv;
3285                                 call_key->call_id=hdr->call_id;
3286                                 call_key->smb_fid=dcerpc_get_transport_salt(pinfo);
3287
3288                                 /* if there is already a matching call in the table
3289                                    remove it so it is replaced with the new one */
3290                                 if(g_hash_table_lookup(dcerpc_cn_calls, call_key)){
3291                                         g_hash_table_remove(dcerpc_cn_calls, call_key);
3292                                 }
3293
3294                                 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
3295                                 call_value->uuid = bind_value->uuid;
3296                                 call_value->ver = bind_value->ver;
3297                                 call_value->opnum = opnum;
3298                                 call_value->req_frame=pinfo->fd->num;
3299                                 call_value->req_time.secs=pinfo->fd->abs_secs;
3300                                 call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000;
3301                                 call_value->rep_frame=0;
3302                                 call_value->max_ptr=0;
3303                                 call_value->private_data = NULL;
3304                                 g_hash_table_insert (dcerpc_cn_calls, call_key, call_value);
3305
3306                                 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3307                                 *new_matched_key = matched_key;
3308                                 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3309                                 value = call_value;
3310                         }
3311                 }
3312         }
3313
3314         if (value) {
3315             dcerpc_info *di;
3316
3317             di=get_next_di();
3318             /* handoff this call */
3319             di->conv = conv;
3320             di->call_id = hdr->call_id;
3321             di->smb_fid = dcerpc_get_transport_salt(pinfo);
3322             di->ptype = PDU_REQ;
3323             di->call_data = value;
3324                 di->hf_index = -1;
3325
3326             if(value->rep_frame!=0){
3327                 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
3328                                     tvb, 0, 0, value->rep_frame);
3329         PROTO_ITEM_SET_GENERATED(pi);
3330             }
3331
3332             dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
3333                                     hdr, di, &auth_info, alloc_hint,
3334                                     value->req_frame);
3335         } else
3336             show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3337     }
3338
3339     /* Dissect the verifier */
3340     dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
3341
3342 }
3343
3344 static void
3345 dissect_dcerpc_cn_resp (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3346                         proto_tree *dcerpc_tree, proto_tree *tree,
3347                         e_dce_cn_common_hdr_t *hdr)
3348 {
3349     dcerpc_call_value *value = NULL;
3350     conversation_t *conv;
3351     guint16 ctx_id;
3352     dcerpc_auth_info auth_info;
3353     guint32 alloc_hint;
3354     proto_item *pi;
3355
3356     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3357                                     hf_dcerpc_cn_alloc_hint, &alloc_hint);
3358
3359     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3360                                     hf_dcerpc_cn_ctx_id, &ctx_id);
3361
3362     /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3363     pinfo->dcectxid = ctx_id;
3364
3365     if (check_col (pinfo->cinfo, COL_INFO)) {
3366         col_append_fstr (pinfo->cinfo, COL_INFO, " ctx_id: %u", ctx_id);
3367     }
3368
3369     offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3370                                    hf_dcerpc_cn_cancel_count, NULL);
3371     /* padding */
3372     offset++;
3373
3374     /*
3375      * XXX - what if this was set when the connection was set up,
3376      * and we just have a security context?
3377      */
3378     dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3379
3380     conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3381                               pinfo->srcport, pinfo->destport, 0);
3382
3383     if (!conv) {
3384         /* no point in creating one here, really */
3385         show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3386     } else {
3387         dcerpc_matched_key matched_key, *new_matched_key;
3388
3389         /* !!! we can NOT check flags.visited here since this will interact
3390            badly with when SMB handles (i.e. calls the subdissector)
3391            and desegmented pdu's .
3392            Instead we check if this pdu is already in the matched table or not
3393         */
3394         matched_key.frame = pinfo->fd->num;
3395         matched_key.call_id = hdr->call_id;
3396         value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3397         if(!value){
3398                 dcerpc_cn_call_key call_key;
3399                 dcerpc_call_value *call_value;
3400
3401                 call_key.conv=conv;
3402                 call_key.call_id=hdr->call_id;
3403                 call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3404
3405                 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3406                         /* extra sanity check,  only match them if the reply
3407                            came after the request */
3408                         if(call_value->req_frame<pinfo->fd->num){
3409                                 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3410                                 *new_matched_key = matched_key;
3411                                 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3412                                 value = call_value;
3413                                 if(call_value->rep_frame==0){
3414                                         call_value->rep_frame=pinfo->fd->num;
3415                                 }
3416                         }
3417                 }
3418         }
3419
3420         if (value) {
3421             dcerpc_info *di;
3422
3423             di=get_next_di();
3424             /* handoff this call */
3425             di->conv = conv;
3426             di->call_id = hdr->call_id;
3427             di->smb_fid = dcerpc_get_transport_salt(pinfo);
3428             di->ptype = PDU_RESP;
3429             di->call_data = value;
3430
3431             proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
3432             if(value->req_frame!=0){
3433                 nstime_t ns;
3434                 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3435                                     tvb, 0, 0, value->req_frame);
3436         PROTO_ITEM_SET_GENERATED(pi);
3437                 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
3438                 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
3439                 if(ns.nsecs<0){
3440                         ns.nsecs+=1000000000;
3441                         ns.secs--;
3442                 }
3443                 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
3444         PROTO_ITEM_SET_GENERATED(pi);
3445             }
3446
3447             dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
3448                                     hdr, di, &auth_info, alloc_hint,
3449                                     value->rep_frame);
3450         } else
3451             show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3452     }
3453
3454     /* Dissect the verifier */
3455     dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
3456 }
3457
3458 static void
3459 dissect_dcerpc_cn_fault (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3460                          proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
3461 {
3462     dcerpc_call_value *value = NULL;
3463     conversation_t *conv;
3464     guint16 ctx_id;
3465     guint32 status;
3466     guint32 alloc_hint;
3467     dcerpc_auth_info auth_info;
3468     proto_item *pi;
3469
3470     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3471                                     hf_dcerpc_cn_alloc_hint, &alloc_hint);
3472
3473     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3474                                     hf_dcerpc_cn_ctx_id, &ctx_id);
3475
3476     offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3477                                    hf_dcerpc_cn_cancel_count, NULL);
3478     /* padding */
3479     offset++;
3480
3481     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3482                                     hf_dcerpc_cn_status, &status);
3483
3484     /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3485     pinfo->dcectxid = ctx_id;
3486
3487     if (check_col (pinfo->cinfo, COL_INFO)) {
3488         col_append_fstr (pinfo->cinfo, COL_INFO,
3489                       " ctx_id: %u status: %s", ctx_id,
3490                       val_to_str(status, reject_status_vals,
3491                                  "Unknown (0x%08x)"));
3492     }
3493
3494     /* padding */
3495     offset += 4;
3496
3497     /*
3498      * XXX - what if this was set when the connection was set up,
3499      * and we just have a security context?
3500      */
3501     dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3502
3503     conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3504                               pinfo->srcport, pinfo->destport, 0);
3505     if (!conv) {
3506         /* no point in creating one here, really */
3507     } else {
3508         dcerpc_matched_key matched_key, *new_matched_key;
3509
3510         /* !!! we can NOT check flags.visited here since this will interact
3511            badly with when SMB handles (i.e. calls the subdissector)
3512            and desegmented pdu's .
3513            Instead we check if this pdu is already in the matched table or not
3514         */
3515         matched_key.frame = pinfo->fd->num;
3516         matched_key.call_id = hdr->call_id;
3517         value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3518         if(!value){
3519                 dcerpc_cn_call_key call_key;
3520                 dcerpc_call_value *call_value;
3521
3522                 call_key.conv=conv;
3523                 call_key.call_id=hdr->call_id;
3524                 call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3525
3526                 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3527                         new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3528                         *new_matched_key = matched_key;
3529                         g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3530                         value = call_value;
3531                         if(call_value->rep_frame==0){
3532                                 call_value->rep_frame=pinfo->fd->num;
3533                         }
3534
3535                 }
3536         }
3537
3538         if (value) {
3539             int length, reported_length, stub_length;
3540             dcerpc_info *di;
3541
3542             di=get_next_di();
3543             /* handoff this call */
3544             di->conv = conv;
3545             di->call_id = hdr->call_id;
3546             di->smb_fid = dcerpc_get_transport_salt(pinfo);
3547             di->ptype = PDU_FAULT;
3548             di->call_data = value;
3549
3550             proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
3551             if(value->req_frame!=0){
3552                 nstime_t ns;
3553                 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3554                                     tvb, 0, 0, value->req_frame);
3555         PROTO_ITEM_SET_GENERATED(pi);
3556                 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
3557                 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
3558                 if(ns.nsecs<0){
3559                         ns.nsecs+=1000000000;
3560                         ns.secs--;
3561                 }
3562                 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
3563         PROTO_ITEM_SET_GENERATED(pi);
3564             }
3565
3566             length = tvb_length_remaining(tvb, offset);
3567             reported_length = tvb_reported_length_remaining(tvb, offset);
3568             stub_length = hdr->frag_len - offset - auth_info.auth_size;
3569             if (length > stub_length)
3570               length = stub_length;
3571             if (reported_length > stub_length)
3572               reported_length = stub_length;
3573
3574             /* If we don't have reassembly enabled, or this packet contains
3575                the entire PDU, or if we don't have all the data in this
3576                fragment, just call the handoff directly if this is the
3577                first fragment or the PDU isn't fragmented. */
3578             if( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
3579                         !tvb_bytes_exist(tvb, offset, stub_length) ){
3580                 if(hdr->flags&PFC_FIRST_FRAG){
3581                     /* First fragment, possibly the only fragment */
3582                     /*
3583                      * XXX - should there be a third routine for each
3584                      * function in an RPC subdissector, to handle
3585                      * fault responses?  The DCE RPC 1.1 spec says
3586                      * three's "stub data" here, which I infer means
3587                      * that it's protocol-specific and call-specific.
3588                      *
3589                      * It should probably get passed the status code
3590                      * as well, as that might be protocol-specific.
3591                      */
3592                     if (dcerpc_tree) {
3593                         if (stub_length > 0) {
3594                             proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3595                                                  "Fault stub data (%d byte%s)",
3596                                                  stub_length,
3597                                                  plurality(stub_length, "", "s"));
3598                         }
3599                     }
3600                 } else {
3601                     /* PDU is fragmented and this isn't the first fragment */
3602                     if (check_col(pinfo->cinfo, COL_INFO)) {
3603                         col_append_fstr(pinfo->cinfo, COL_INFO,
3604                                         " [DCE/RPC fragment]");
3605                     }
3606                     if (dcerpc_tree) {
3607                         if (stub_length > 0) {
3608                             proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3609                                                  "Fragment data (%d byte%s)",
3610                                                  stub_length,
3611                                                  plurality(stub_length, "", "s"));
3612                         }
3613                     }
3614                 }
3615             } else {
3616                 /* Reassembly is enabled, the PDU is fragmented, and
3617                    we have all the data in the fragment; the first two
3618                    of those mean we should attempt reassembly, and the
3619                    third means we can attempt reassembly. */
3620                 if (dcerpc_tree) {
3621                     if (length > 0) {
3622                         proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3623                                              "Fragment data (%d byte%s)",
3624                                              stub_length,
3625                                              plurality(stub_length, "", "s"));
3626                     }
3627                 }
3628                 if(hdr->flags&PFC_FIRST_FRAG){  /* FIRST fragment */
3629                     if( (!pinfo->fd->flags.visited) && value->rep_frame ){
3630                         fragment_add(tvb, offset, pinfo, value->rep_frame,
3631                              dcerpc_co_reassemble_table,
3632                              0,
3633                              stub_length,
3634                              TRUE);
3635                         fragment_set_tot_len(pinfo, value->rep_frame,
3636                              dcerpc_co_reassemble_table, alloc_hint);
3637                     }
3638                     if (check_col(pinfo->cinfo, COL_INFO)) {
3639                         col_append_fstr(pinfo->cinfo, COL_INFO,
3640                                         " [DCE/RPC fragment]");
3641                     }
3642                 } else if(hdr->flags&PFC_LAST_FRAG){  /* LAST fragment */
3643                     if( value->rep_frame ){
3644                         fragment_data *fd_head;
3645                         guint32 tot_len;
3646
3647                         tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
3648                                        dcerpc_co_reassemble_table);
3649                         fd_head = fragment_add(tvb, offset, pinfo,
3650                              value->rep_frame,
3651                              dcerpc_co_reassemble_table,
3652                              tot_len-alloc_hint,
3653                              stub_length,
3654                              TRUE);
3655
3656                         if(fd_head){
3657                             /* We completed reassembly */
3658                             tvbuff_t *next_tvb;
3659
3660                             next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
3661                             tvb_set_child_real_data_tvbuff(tvb, next_tvb);
3662                             add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3663                             show_fragment_tree(fd_head, &dcerpc_frag_items,
3664                                 dcerpc_tree, pinfo, next_tvb);
3665
3666                             /*
3667                              * XXX - should there be a third routine for each
3668                              * function in an RPC subdissector, to handle
3669                              * fault responses?  The DCE RPC 1.1 spec says
3670                              * three's "stub data" here, which I infer means
3671                              * that it's protocol-specific and call-specific.
3672                              *
3673                              * It should probably get passed the status code
3674                              * as well, as that might be protocol-specific.
3675                              */
3676                             if (dcerpc_tree) {
3677                                 if (length > 0) {
3678                                      proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3679                                                           "Fault stub data (%d byte%s)",
3680                                                           stub_length,
3681                                                           plurality(stub_length, "", "s"));
3682                                 }
3683                             }
3684                         } else {
3685                             /* Reassembly not complete - some fragments
3686                                are missing */
3687                             if (check_col(pinfo->cinfo, COL_INFO)) {
3688                                 col_append_fstr(pinfo->cinfo, COL_INFO,
3689                                                 " [DCE/RPC fragment]");
3690                             }
3691                         }
3692                     }
3693                 } else {  /* MIDDLE fragment(s) */
3694                     if( (!pinfo->fd->flags.visited) && value->rep_frame ){
3695                         guint32 tot_len;
3696                         tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
3697                                        dcerpc_co_reassemble_table);
3698                         fragment_add(tvb, offset, pinfo, value->rep_frame,
3699                              dcerpc_co_reassemble_table,
3700                              tot_len-alloc_hint,
3701                              stub_length,
3702                              TRUE);
3703                     }
3704                     if (check_col(pinfo->cinfo, COL_INFO)) {
3705                         col_append_fstr(pinfo->cinfo, COL_INFO,
3706                                         " [DCE/RPC fragment]");
3707                     }
3708                 }
3709             }
3710         }
3711     }
3712 }
3713
3714 /*
3715  * DCERPC dissector for connection oriented calls.
3716  * We use transport type to later multiplex between what kind of
3717  * pinfo->private_data structure to expect.
3718  */
3719 static gboolean
3720 dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
3721                    proto_tree *tree, gboolean can_desegment, int *pkt_len)
3722 {
3723     static const guint8 nulls[4] = { 0 };
3724     int start_offset;
3725     int padding = 0;
3726     proto_item *ti = NULL;
3727     proto_item *tf = NULL;
3728     proto_tree *dcerpc_tree = NULL;
3729     proto_tree *cn_flags_tree = NULL;
3730     proto_tree *drep_tree = NULL;
3731     e_dce_cn_common_hdr_t hdr;
3732     dcerpc_auth_info auth_info;
3733
3734     /*
3735      * when done over nbt, dcerpc requests are padded with 4 bytes of null
3736      * data for some reason.
3737      *
3738      * XXX - if that's always the case, the right way to do this would
3739      * be to have a "dissect_dcerpc_cn_nb" routine which strips off
3740      * the 4 bytes of null padding, and make that the dissector
3741      * used for "netbios".
3742      */
3743     if (tvb_memeql (tvb, offset, nulls, 4) == 0) {
3744
3745         /*
3746          * Skip the padding.
3747          */
3748         offset += 4;
3749         padding += 4;
3750     }
3751
3752     /*
3753      * Check if this looks like a C/O DCERPC call
3754      */
3755     if (!tvb_bytes_exist (tvb, offset, sizeof (hdr))) {
3756         return FALSE;   /* not enough information to check */
3757     }
3758     start_offset = offset;
3759     hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
3760     if (hdr.rpc_ver != 5)
3761         return FALSE;
3762     hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
3763     if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
3764         return FALSE;
3765     hdr.ptype = tvb_get_guint8 (tvb, offset++);
3766     if (hdr.ptype > 19)
3767         return FALSE;
3768
3769     hdr.flags = tvb_get_guint8 (tvb, offset++);
3770     tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
3771     offset += sizeof (hdr.drep);
3772
3773     hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3774     offset += 2;
3775     hdr.auth_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3776     offset += 2;
3777     hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3778     offset += 4;
3779
3780     if (can_desegment && pinfo->can_desegment
3781         && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
3782         pinfo->desegment_offset = start_offset;
3783         pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, start_offset);
3784         *pkt_len = 0;   /* desegmentation required */
3785         return TRUE;
3786     }
3787
3788     if (check_col (pinfo->cinfo, COL_PROTOCOL))
3789         col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
3790
3791     if (check_col (pinfo->cinfo, COL_INFO)) {
3792         if(pinfo->dcectxid != 0) {
3793             /* this is not the first DCE-RPC request/response in this (TCP?-)PDU, 
3794              * append a delimiter and set a column fence */
3795             col_append_str (pinfo->cinfo, COL_INFO, " # ");
3796             col_set_fence(pinfo->cinfo,COL_INFO);
3797         }
3798         col_add_fstr (pinfo->cinfo, COL_INFO, "%s: call_id: %u",
3799                 pckt_vals[hdr.ptype].strptr, hdr.call_id);
3800     }
3801
3802     if (tree) {
3803         offset = start_offset;
3804         ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE);
3805         if (ti) {
3806             dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
3807         }
3808         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver);
3809         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset++, 1, hdr.rpc_ver_minor);
3810         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype);
3811         tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
3812         cn_flags_tree = proto_item_add_subtree (tf, ett_dcerpc_cn_flags);
3813         if (cn_flags_tree) {
3814             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
3815             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
3816             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
3817             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
3818             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
3819             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
3820             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
3821             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
3822         }
3823         offset++;
3824
3825         tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
3826         drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
3827         if (drep_tree) {
3828             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
3829             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
3830             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
3831         }
3832         offset += sizeof (hdr.drep);
3833
3834         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
3835         offset += 2;
3836
3837         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
3838         offset += 2;
3839
3840         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
3841         offset += 4;
3842     }
3843
3844     /*
3845      * None of the stuff done above should throw an exception, because
3846      * we would have rejected this as "not DCE RPC" if we didn't have all
3847      * of it.  (XXX - perhaps we should request reassembly if we have
3848      * enough of the header to consider it DCE RPC but not enough to
3849      * get the fragment length; in that case the stuff still wouldn't
3850      * throw an exception.)
3851      *
3852      * The rest of the stuff might, so return the PDU length to our caller.
3853      * XXX - should we construct a tvbuff containing only the PDU and
3854      * use that?  Or should we have separate "is this a DCE RPC PDU",
3855      * "how long is it", and "dissect it" routines - which might let us
3856      * do most of the work in "tcp_dissect_pdus()"?
3857      */
3858     if (pkt_len != NULL)
3859         *pkt_len = hdr.frag_len + padding;
3860
3861     /*
3862      * Packet type specific stuff is next.
3863      */
3864     switch (hdr.ptype) {
3865     case PDU_BIND:
3866     case PDU_ALTER:
3867         dissect_dcerpc_cn_bind (tvb, offset, pinfo, dcerpc_tree, &hdr);
3868         break;
3869
3870     case PDU_BIND_ACK:
3871     case PDU_ALTER_ACK:
3872         dissect_dcerpc_cn_bind_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3873         break;
3874
3875     case PDU_AUTH3:
3876         /*
3877          * Nothing after the common header other than credentials.
3878          */
3879         dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, TRUE, 
3880                                 &auth_info);
3881         break;
3882
3883     case PDU_REQ:
3884         dissect_dcerpc_cn_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
3885         break;
3886
3887     case PDU_RESP:
3888         dissect_dcerpc_cn_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
3889         break;
3890
3891     case PDU_FAULT:
3892         dissect_dcerpc_cn_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
3893         break;
3894
3895     case PDU_BIND_NAK:
3896         dissect_dcerpc_cn_bind_nak (tvb, offset, pinfo, dcerpc_tree, &hdr);
3897         break;
3898
3899     case PDU_CO_CANCEL:
3900     case PDU_ORPHANED:
3901         /*
3902          * Nothing after the common header other than an authentication
3903          * verifier.
3904          */
3905         dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE, 
3906                                 &auth_info);
3907         break;
3908
3909     case PDU_SHUTDOWN:
3910         /*
3911          * Nothing after the common header, not even an authentication
3912          * verifier.
3913          */
3914         break;
3915
3916     default:
3917         /* might as well dissect the auth info */
3918         dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE, 
3919                                 &auth_info);
3920         break;
3921     }
3922     return TRUE;
3923 }
3924
3925 /*
3926  * DCERPC dissector for connection oriented calls over packet-oriented
3927  * transports
3928  */
3929 static gboolean
3930 dissect_dcerpc_cn_pk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3931 {
3932     /*
3933      * Only one PDU per transport packet, and only one transport
3934      * packet per PDU.
3935      */
3936     pinfo->dcetransporttype=DCE_TRANSPORT_UNKNOWN;
3937     if (!dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE, NULL)) {
3938         /*
3939          * It wasn't a DCERPC PDU.
3940          */
3941         return FALSE;
3942     } else {
3943         /*
3944          * It was.
3945          */
3946         return TRUE;
3947     }
3948 }
3949
3950 /*
3951  * DCERPC dissector for connection oriented calls over byte-stream
3952  * transports.
3953  * we need to distinguish here between SMB and non-TCP (more in the future?)
3954  * to be able to know what kind of private_data structure to expect.
3955  */
3956 static gboolean
3957 dissect_dcerpc_cn_bs_body (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3958 {
3959     volatile int offset = 0;
3960     int pdu_len;
3961     volatile gboolean is_dcerpc_pdu;
3962     volatile gboolean ret = FALSE;
3963
3964     /*
3965      * There may be multiple PDUs per transport packet; keep
3966      * processing them.
3967      */
3968     while (tvb_reported_length_remaining(tvb, offset) != 0) {
3969         /*
3970          * Catch ReportedBoundsError, so that even if the stub data is bad,
3971          * we don't abort the full DCE RPC dissection - there might be more
3972          * than one DCE RPC PDU in the data being dissected.
3973          *
3974          * If we get BoundsError, it means the frame was cut short by a
3975          * snapshot length, so there's nothing more to dissect; just
3976          * re-throw that exception.
3977          */
3978         is_dcerpc_pdu = FALSE;
3979         TRY {
3980             is_dcerpc_pdu = dissect_dcerpc_cn (tvb, offset, pinfo, tree,
3981                                                dcerpc_cn_desegment, &pdu_len);
3982         } CATCH(BoundsError) {
3983             RETHROW;
3984         } CATCH(ReportedBoundsError) {
3985             show_reported_bounds_error(tvb, pinfo, tree);
3986         } ENDTRY;
3987
3988         if (!is_dcerpc_pdu) {
3989             /*
3990              * Not a DCERPC PDU.
3991              */
3992             break;
3993         }
3994
3995         /*
3996          * Well, we've seen at least one DCERPC PDU.
3997          */
3998         ret = TRUE;
3999
4000         if (pdu_len == 0) {
4001             /*
4002              * Desegmentation required - bail now.
4003              */
4004             break;
4005         }
4006
4007         /*
4008          * Step to the next PDU.
4009          */
4010         offset += pdu_len;
4011     }
4012     return ret;
4013 }
4014
4015 static gboolean
4016 dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4017 {
4018         pinfo->dcetransporttype=DCE_TRANSPORT_UNKNOWN;
4019         return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
4020 }
4021
4022 static gboolean
4023 dissect_dcerpc_cn_smbpipe (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4024 {
4025         pinfo->dcetransporttype=DCE_CN_TRANSPORT_SMBPIPE;
4026         return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
4027 }
4028
4029
4030
4031 static void
4032 dissect_dcerpc_dg_auth (tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
4033                         e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
4034 {
4035     proto_item *ti = NULL;
4036     proto_tree *auth_tree = NULL;
4037     guint8 protection_level;
4038
4039     /*
4040      * Initially set "*auth_level_p" to -1 to indicate that we haven't
4041      * yet seen any authentication level information.
4042      */
4043     if (auth_level_p != NULL)
4044         *auth_level_p = -1;
4045
4046     /*
4047      * The authentication information is at the *end* of the PDU; in
4048      * request and response PDUs, the request and response stub data
4049      * come before it.
4050      *
4051      * If the full packet is here, and there's data past the end of the
4052      * packet body, then dissect the auth info.
4053      */
4054     offset += hdr->frag_len;
4055     if (tvb_length_remaining(tvb, offset) > 0) {
4056         switch (hdr->auth_proto) {
4057
4058         case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
4059             ti = proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Kerberos authentication verifier");
4060             auth_tree = proto_item_add_subtree (ti, ett_dcerpc_krb5_auth_verf);
4061             protection_level = tvb_get_guint8 (tvb, offset);
4062             if (auth_level_p != NULL)
4063                 *auth_level_p = protection_level;
4064             proto_tree_add_uint (auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
4065             offset++;
4066             proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, FALSE);
4067             offset++;
4068             if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
4069                 offset += 6;    /* 6 bytes of padding */
4070             else
4071                 offset += 2;    /* 6 bytes of padding */
4072             proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, FALSE);
4073             offset += 16;
4074             break;
4075
4076         default:
4077             proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Authentication verifier");
4078             break;
4079         }
4080     }
4081 }
4082
4083 static void
4084 dissect_dcerpc_dg_cancel_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
4085                               proto_tree *dcerpc_tree,
4086                               e_dce_dg_common_hdr_t *hdr)
4087 {
4088     guint32 version;
4089
4090     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4091                                     hdr->drep, hf_dcerpc_dg_cancel_vers,
4092                                     &version);
4093
4094     switch (version) {
4095
4096     case 0:
4097         /* The only version we know about */
4098         offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4099                                         hdr->drep, hf_dcerpc_dg_cancel_id,
4100                                         NULL);
4101         offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
4102                                        hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
4103                                        NULL);
4104         break;
4105     }
4106 }
4107
4108 static void
4109 dissect_dcerpc_dg_cancel (tvbuff_t *tvb, int offset, packet_info *pinfo,
4110                           proto_tree *dcerpc_tree,
4111                           e_dce_dg_common_hdr_t *hdr)
4112 {
4113     guint32 version;
4114
4115     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4116                                     hdr->drep, hf_dcerpc_dg_cancel_vers,
4117                                     &version);
4118
4119     switch (version) {
4120
4121     case 0:
4122         /* The only version we know about */
4123         offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4124                                         hdr->drep, hf_dcerpc_dg_cancel_id,
4125                                         NULL);
4126         /* XXX - are NDR booleans 32 bits? */
4127
4128         /* XXX - the RPC reference in chapter: "the cancel PDU" doesn't mention
4129            the accepting_cancels field (it's only in the cancel_ack PDU)! */
4130         /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4131                                         hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
4132                                         NULL);*/
4133         break;
4134     }
4135 }
4136
4137 static void
4138 dissect_dcerpc_dg_fack (tvbuff_t *tvb, int offset, packet_info *pinfo,
4139                         proto_tree *dcerpc_tree,
4140                         e_dce_dg_common_hdr_t *hdr)
4141 {
4142     guint8 version;
4143     guint16 serial_num;
4144     guint16 selack_len;
4145     guint i;
4146
4147     offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
4148                                   hdr->drep, hf_dcerpc_dg_fack_vers,
4149                                   &version);
4150     /* padding */
4151     offset++;
4152
4153     switch (version) {
4154
4155     case 0:     /* The only version documented in the DCE RPC 1.1 spec */
4156     case 1:     /* This appears to be the same */
4157         offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
4158                                         hdr->drep, hf_dcerpc_dg_fack_window_size,
4159                                         NULL);
4160         offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4161                                         hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
4162                                         NULL);
4163         offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4164                                         hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
4165                                         NULL);
4166         offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
4167                                         hdr->drep, hf_dcerpc_dg_fack_serial_num,
4168                                         &serial_num);
4169         if (check_col (pinfo->cinfo, COL_INFO)) {
4170             col_append_fstr (pinfo->cinfo, COL_INFO, " serial: %u",
4171                              serial_num);
4172         }
4173         offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
4174                                         hdr->drep, hf_dcerpc_dg_fack_selack_len,
4175                                         &selack_len);
4176         for (i = 0; i < selack_len; i++) {
4177             offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4178                                             hdr->drep, hf_dcerpc_dg_fack_selack,
4179                                             NULL);
4180         }
4181
4182         break;
4183     }
4184 }
4185
4186 static void
4187 dissect_dcerpc_dg_reject_fault (tvbuff_t *tvb, int offset, packet_info *pinfo,
4188                         proto_tree *dcerpc_tree,
4189                         e_dce_dg_common_hdr_t *hdr)
4190 {
4191     guint32 status;
4192
4193     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4194                                     hdr->drep, hf_dcerpc_dg_status,
4195                                     &status);
4196
4197     if (check_col (pinfo->cinfo, COL_INFO)) {
4198         col_append_fstr (pinfo->cinfo, COL_INFO,
4199                       ": status: %s",
4200                       val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
4201     }
4202 }
4203
4204 static void
4205 dissect_dcerpc_dg_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
4206                         proto_tree *dcerpc_tree, proto_tree *tree,
4207                         e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
4208 {
4209     int length, reported_length, stub_length;
4210     gboolean save_fragmented;
4211     fragment_data *fd_head;
4212     tvbuff_t *next_tvb;
4213     proto_item *pi;
4214
4215     if (check_col (pinfo->cinfo, COL_INFO))
4216         col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u len: %u", 
4217             di->call_data->opnum, hdr->frag_len );
4218
4219     length = tvb_length_remaining (tvb, offset);
4220     reported_length = tvb_reported_length_remaining (tvb, offset);
4221     stub_length = hdr->frag_len;
4222     if (length > stub_length)
4223         length = stub_length;
4224     if (reported_length > stub_length)
4225         reported_length = stub_length;
4226
4227     save_fragmented = pinfo->fragmented;
4228
4229     /* If we don't have reassembly enabled, or this packet contains
4230        the entire PDU, or if this is a short frame (or a frame
4231        not reassembled at a lower layer) that doesn't include all
4232        the data in the fragment, just call the handoff directly if
4233        this is the first fragment or the PDU isn't fragmented. */
4234     if( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
4235                 !tvb_bytes_exist(tvb, offset, stub_length) ){
4236         if(hdr->frag_num == 0) {
4237
4238
4239             /* First fragment, possibly the only fragment */
4240
4241             /*
4242              * XXX - authentication info?
4243              */
4244             pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
4245             next_tvb = tvb_new_subset (tvb, offset, length,
4246                                        reported_length);
4247             dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
4248                                 next_tvb, hdr->drep, di, NULL);
4249         } else {
4250             /* PDU is fragmented and this isn't the first fragment */
4251             if (check_col(pinfo->cinfo, COL_INFO)) {
4252                 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
4253             }
4254             if (dcerpc_tree) {
4255                 if (length > 0) {
4256                     proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
4257                                          "Fragment data (%d byte%s)",
4258                                          stub_length,
4259                                          plurality(stub_length, "", "s"));
4260                 }
4261             }
4262         }
4263     } else {
4264         /* Reassembly is enabled, the PDU is fragmented, and
4265            we have all the data in the fragment; the first two
4266            of those mean we should attempt reassembly, and the
4267            third means we can attempt reassembly. */
4268         if (dcerpc_tree) {
4269             if (length > 0) {
4270                 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
4271                                      "Fragment data (%d byte%s)", stub_length,
4272                                      plurality(stub_length, "", "s"));
4273             }
4274         }
4275
4276         fd_head = fragment_add_dcerpc(tvb, offset, pinfo,
4277                         hdr->seqnum, &hdr->act_id, dcerpc_cl_reassemble_table,
4278                         hdr->frag_num, stub_length,
4279                         !(hdr->flags1 & PFCL1_LASTFRAG));
4280     if (fd_head != NULL) {
4281             /* We completed reassembly... */
4282         if(pinfo->fd->num==fd_head->reassembled_in) {
4283             /* ...and this is the reassembled RPC PDU */
4284                 next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
4285                 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
4286                 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
4287                 show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
4288                                            dcerpc_tree, pinfo, next_tvb);
4289
4290                 /*
4291                  * XXX - authentication info?
4292                  */
4293                 pinfo->fragmented = FALSE;
4294                 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
4295                                         next_tvb, hdr->drep, di, NULL);
4296                 } else {
4297             /* ...and this isn't the reassembled RPC PDU */
4298                 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
4299                                     tvb, 0, 0, fd_head->reassembled_in);
4300             PROTO_ITEM_SET_GENERATED(pi);
4301                 if (check_col(pinfo->cinfo, COL_INFO)) {
4302                     col_append_fstr(pinfo->cinfo, COL_INFO,
4303                             " [DCE/RPC fragment, reas: #%u]", fd_head->reassembled_in);
4304                 }
4305         }
4306         } else {
4307             /* Reassembly isn't completed yet */
4308             if (check_col(pinfo->cinfo, COL_INFO)) {
4309                 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
4310             }
4311         }
4312     }
4313     pinfo->fragmented = save_fragmented;
4314 }
4315
4316 static void
4317 dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo,
4318                         proto_tree *dcerpc_tree, proto_tree *tree,
4319                         e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4320 {
4321     dcerpc_info *di;
4322     dcerpc_call_value *value, v;
4323     dcerpc_matched_key matched_key, *new_matched_key;
4324     proto_item *pi;
4325
4326     di=get_next_di();
4327     if(!(pinfo->fd->flags.visited)){
4328         dcerpc_call_value *call_value;
4329         dcerpc_dg_call_key *call_key;
4330
4331         call_key=g_mem_chunk_alloc (dcerpc_dg_call_key_chunk);
4332         call_key->conv=conv;
4333         call_key->seqnum=hdr->seqnum;
4334         call_key->act_id=hdr->act_id;
4335
4336         call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
4337         call_value->uuid = hdr->if_id;
4338         call_value->ver = hdr->if_ver;
4339         call_value->opnum = hdr->opnum;
4340         call_value->req_frame=pinfo->fd->num;
4341         call_value->req_time.secs=pinfo->fd->abs_secs;
4342         call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000;
4343         call_value->rep_frame=0;
4344         call_value->max_ptr=0;
4345         call_value->private_data = NULL;
4346         g_hash_table_insert (dcerpc_dg_calls, call_key, call_value);
4347
4348         new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
4349         new_matched_key->frame = pinfo->fd->num;
4350         new_matched_key->call_id = hdr->seqnum;
4351         g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
4352     }
4353
4354     matched_key.frame = pinfo->fd->num;
4355     matched_key.call_id = hdr->seqnum;
4356     value=g_hash_table_lookup(dcerpc_matched, &matched_key);
4357     if (!value) {
4358         v.uuid = hdr->if_id;
4359         v.ver = hdr->if_ver;
4360         v.opnum = hdr->opnum;
4361         v.req_frame = pinfo->fd->num;
4362         v.rep_frame = 0;
4363         v.max_ptr = 0;
4364         v.private_data=NULL;
4365         value = &v;
4366     }
4367
4368     di->conv = conv;
4369     di->call_id = hdr->seqnum;
4370     di->smb_fid = -1;
4371     di->ptype = PDU_REQ;
4372     di->call_data = value;
4373
4374     if(value->rep_frame!=0){
4375         pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
4376                             tvb, 0, 0, value->rep_frame);
4377     PROTO_ITEM_SET_GENERATED(pi);
4378     }
4379     dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
4380 }
4381
4382 static void
4383 dissect_dcerpc_dg_resp (tvbuff_t *tvb, int offset, packet_info *pinfo,
4384                         proto_tree *dcerpc_tree, proto_tree *tree,
4385                         e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4386 {
4387     dcerpc_info *di;
4388     dcerpc_call_value *value, v;
4389     dcerpc_matched_key matched_key, *new_matched_key;
4390     proto_item *pi;
4391
4392     di=get_next_di();
4393     if(!(pinfo->fd->flags.visited)){
4394         dcerpc_call_value *call_value;
4395         dcerpc_dg_call_key call_key;
4396
4397         call_key.conv=conv;
4398         call_key.seqnum=hdr->seqnum;
4399         call_key.act_id=hdr->act_id;
4400
4401         if((call_value=g_hash_table_lookup(dcerpc_dg_calls, &call_key))){
4402             new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
4403             new_matched_key->frame = pinfo->fd->num;
4404             new_matched_key->call_id = hdr->seqnum;
4405             g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
4406             if(call_value->rep_frame==0){
4407                 call_value->rep_frame=pinfo->fd->num;
4408             }
4409         }
4410     }
4411
4412     matched_key.frame = pinfo->fd->num;
4413     matched_key.call_id = hdr->seqnum;
4414     value=g_hash_table_lookup(dcerpc_matched, &matched_key);
4415     if (!value) {
4416         v.uuid = hdr->if_id;
4417         v.ver = hdr->if_ver;
4418         v.opnum = hdr->opnum;
4419         v.req_frame=0;
4420         v.rep_frame=pinfo->fd->num;
4421         v.private_data=NULL;
4422         value = &v;
4423     }
4424
4425     di->conv = conv;
4426     di->call_id = 0;
4427     di->smb_fid = -1;
4428     di->ptype = PDU_RESP;
4429     di->call_data = value;
4430
4431     if(value->req_frame!=0){
4432         nstime_t ns;
4433         pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4434                             tvb, 0, 0, value->req_frame);
4435     PROTO_ITEM_SET_GENERATED(pi);
4436         ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
4437         ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
4438         if(ns.nsecs<0){
4439                 ns.nsecs+=1000000000;
4440                 ns.secs--;
4441         }
4442         pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
4443     PROTO_ITEM_SET_GENERATED(pi);
4444     }
4445     dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
4446 }
4447
4448 /*
4449  * DCERPC dissector for connectionless calls
4450  */
4451 static gboolean
4452 dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4453 {
4454     proto_item *ti = NULL;
4455     proto_item *tf = NULL;
4456     proto_tree *dcerpc_tree = NULL;
4457     proto_tree *dg_flags1_tree = NULL;
4458     proto_tree *dg_flags2_tree = NULL;
4459     proto_tree *drep_tree = NULL;
4460     e_dce_dg_common_hdr_t hdr;
4461     int offset = 0;
4462     conversation_t *conv;
4463     int auth_level;
4464     char uuid_str[DCERPC_UUID_STR_LEN]; 
4465     int uuid_str_len;
4466
4467     /*
4468      * Check if this looks like a CL DCERPC call.  All dg packets
4469      * have an 80 byte header on them.  Which starts with
4470      * version (4), pkt_type.
4471      */
4472     if (!tvb_bytes_exist (tvb, 0, sizeof (hdr))) {
4473         return FALSE;
4474     }
4475     hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
4476     if (hdr.rpc_ver != 4)
4477         return FALSE;
4478     hdr.ptype = tvb_get_guint8 (tvb, offset++);
4479     if (hdr.ptype > 19)
4480         return FALSE;
4481
4482     if (check_col (pinfo->cinfo, COL_PROTOCOL))
4483         col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
4484     if (check_col (pinfo->cinfo, COL_INFO))
4485         col_add_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
4486
4487     hdr.flags1 = tvb_get_guint8 (tvb, offset++);
4488     hdr.flags2 = tvb_get_guint8 (tvb, offset++);
4489     tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
4490     offset += sizeof (hdr.drep);
4491     hdr.serial_hi = tvb_get_guint8 (tvb, offset++);
4492     dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.obj_id);
4493     offset += 16;
4494     dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.if_id);
4495     offset += 16;
4496     dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.act_id);
4497     offset += 16;
4498     hdr.server_boot = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4499     offset += 4;
4500     hdr.if_ver = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4501     offset += 4;
4502     hdr.seqnum = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4503     offset += 4;
4504     hdr.opnum = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4505     offset += 2;
4506     hdr.ihint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4507     offset += 2;
4508     hdr.ahint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4509     offset += 2;
4510     hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4511     offset += 2;
4512     hdr.frag_num = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4513     offset += 2;
4514     hdr.auth_proto = tvb_get_guint8 (tvb, offset++);
4515     hdr.serial_lo = tvb_get_guint8 (tvb, offset++);
4516
4517     if (tree) {
4518         ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, -1, FALSE);
4519         if (ti) {
4520             dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
4521         }
4522     }
4523     offset = 0;
4524
4525     if (tree)
4526         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
4527     offset++;
4528
4529     if (tree)
4530         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
4531     offset++;
4532
4533     if (tree) {
4534         tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
4535         dg_flags1_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags1);
4536         if (dg_flags1_tree) {
4537             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
4538             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
4539             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
4540             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
4541             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
4542             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
4543             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
4544             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
4545         }
4546     }
4547     offset++;
4548
4549     if (tree) {
4550         tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
4551         dg_flags2_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags2);
4552         if (dg_flags2_tree) {
4553             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
4554             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
4555             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
4556             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
4557             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
4558             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
4559             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
4560             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
4561         }
4562     }
4563     offset++;
4564
4565     if (tree) {
4566         tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
4567         drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
4568         if (drep_tree) {
4569             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
4570             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
4571             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
4572         }
4573     }
4574     offset += sizeof (hdr.drep);
4575
4576     if (tree)
4577         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
4578     offset++;
4579
4580     if (tree) {
4581         /* XXX - use "dissect_ndr_uuid_t()"? */
4582         uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, 
4583                                 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
4584                                 hdr.obj_id.Data1, hdr.obj_id.Data2, hdr.obj_id.Data3,
4585                                 hdr.obj_id.Data4[0],
4586                                 hdr.obj_id.Data4[1],
4587                                 hdr.obj_id.Data4[2],
4588                                 hdr.obj_id.Data4[3],
4589                                 hdr.obj_id.Data4[4],
4590                                 hdr.obj_id.Data4[5],
4591                                 hdr.obj_id.Data4[6],
4592                                 hdr.obj_id.Data4[7]);
4593         if (uuid_str_len >= DCERPC_UUID_STR_LEN)
4594                 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
4595         proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
4596                                       offset, 16, uuid_str, "Object UUID: %s", uuid_str);
4597     }
4598     offset += 16;
4599
4600     if (tree) {
4601         /* XXX - use "dissect_ndr_uuid_t()"? */
4602         uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, 
4603                                 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
4604                                 hdr.if_id.Data1, hdr.if_id.Data2, hdr.if_id.Data3,
4605                                 hdr.if_id.Data4[0],
4606                                 hdr.if_id.Data4[1],
4607                                 hdr.if_id.Data4[2],
4608                                 hdr.if_id.Data4[3],
4609                                 hdr.if_id.Data4[4],
4610                                 hdr.if_id.Data4[5],
4611                                 hdr.if_id.Data4[6],
4612                                 hdr.if_id.Data4[7]);
4613         if (uuid_str_len >= DCERPC_UUID_STR_LEN)
4614                 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
4615         proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
4616                                       offset, 16, uuid_str, "Interface: %s", uuid_str);
4617     }
4618     offset += 16;
4619
4620     if (tree) {
4621         /* XXX - use "dissect_ndr_uuid_t()"? */
4622         uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, 
4623                                 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
4624                                 hdr.act_id.Data1, hdr.act_id.Data2, hdr.act_id.Data3,
4625                                 hdr.act_id.Data4[0],
4626                                 hdr.act_id.Data4[1],
4627                                 hdr.act_id.Data4[2],
4628                                 hdr.act_id.Data4[3],
4629                                 hdr.act_id.Data4[4],
4630                                 hdr.act_id.Data4[5],
4631                                 hdr.act_id.Data4[6],
4632                                 hdr.act_id.Data4[7]);
4633         if (uuid_str_len >= DCERPC_UUID_STR_LEN)
4634                 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
4635         proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
4636                                       offset, 16, uuid_str, "Activity: %s", uuid_str);
4637     }
4638     offset += 16;
4639
4640     if (tree) {
4641         nstime_t server_boot;
4642
4643         server_boot.secs  = hdr.server_boot;
4644         server_boot.nsecs = 0;
4645
4646         if (hdr.server_boot == 0)
4647             proto_tree_add_time_format (dcerpc_tree, hf_dcerpc_dg_server_boot,
4648                                         tvb, offset, 4, &server_boot,
4649                                         "Server boot time: Unknown (0)");
4650         else
4651             proto_tree_add_time (dcerpc_tree, hf_dcerpc_dg_server_boot,
4652                                  tvb, offset, 4, &server_boot);
4653     }
4654     offset += 4;
4655
4656     if (tree)
4657         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
4658     offset += 4;
4659
4660     if (tree)
4661         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
4662     if (check_col (pinfo->cinfo, COL_INFO)) {
4663         col_append_fstr (pinfo->cinfo, COL_INFO, ": seq: %u", hdr.seqnum);
4664     }
4665     offset += 4;
4666
4667     if (tree)
4668         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
4669     offset += 2;
4670
4671     if (tree)
4672         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
4673     offset += 2;
4674
4675     if (tree)
4676         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
4677     offset += 2;
4678
4679     if (tree)
4680         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
4681     offset += 2;
4682
4683     if (tree)
4684         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
4685     if (check_col (pinfo->cinfo, COL_INFO)) {
4686         if (hdr.flags1 & PFCL1_FRAG) {
4687             /* Fragmented - put the fragment number into the Info column */
4688             col_append_fstr (pinfo->cinfo, COL_INFO, " frag: %u",
4689                              hdr.frag_num);
4690         }
4691     }
4692     offset += 2;
4693
4694     if (tree)
4695         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
4696     offset++;
4697
4698     if (tree)
4699         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
4700     if (check_col (pinfo->cinfo, COL_INFO)) {
4701         if (hdr.flags1 & PFCL1_FRAG) {
4702             /* Fragmented - put the serial number into the Info column */
4703             col_append_fstr (pinfo->cinfo, COL_INFO, " serial: %u",
4704                              (hdr.serial_hi << 8) | hdr.serial_lo);
4705         }
4706     }
4707     offset++;
4708
4709     if (tree) {
4710         /*
4711          * XXX - for Kerberos, we get a protection level; if it's
4712          * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
4713          * stub data.
4714          */
4715         dissect_dcerpc_dg_auth (tvb, offset, dcerpc_tree, &hdr,
4716                                 &auth_level);
4717     }
4718
4719     /*
4720      * keeping track of the conversation shouldn't really be necessary
4721      * for connectionless packets, because everything we need to know
4722      * to dissect is in the header for each packet.  Unfortunately,
4723      * Microsoft's implementation is buggy and often puts the
4724      * completely wrong if_id in the header.  go figure.  So, keep
4725      * track of the seqnum and use that if possible.  Note: that's not
4726      * completely correct.  It should really be done based on both the
4727      * activity_id and seqnum.  I haven't seen anywhere that it would
4728      * make a difference, but for future reference...
4729      */
4730     conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
4731                               pinfo->srcport, pinfo->destport, 0);
4732     if (!conv) {
4733         conv = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
4734                                  pinfo->srcport, pinfo->destport, 0);
4735     }
4736
4737     /*
4738      * Packet type specific stuff is next.
4739      */
4740
4741     switch (hdr.ptype) {
4742
4743     case PDU_CANCEL_ACK:
4744         /* Body is optional */
4745         /* XXX - we assume "frag_len" is the length of the body */
4746         if (hdr.frag_len != 0)
4747             dissect_dcerpc_dg_cancel_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
4748         break;
4749
4750     case PDU_CL_CANCEL:
4751         /*
4752          * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
4753          * but in at least one capture none of the Cl_cancel PDUs had a
4754          * body.
4755          */
4756         /* XXX - we assume "frag_len" is the length of the body */
4757         if (hdr.frag_len != 0)
4758             dissect_dcerpc_dg_cancel (tvb, offset, pinfo, dcerpc_tree, &hdr);
4759         break;
4760
4761     case PDU_NOCALL:
4762         /* Body is optional; if present, it's the same as PDU_FACK */
4763         /* XXX - we assume "frag_len" is the length of the body */
4764         if (hdr.frag_len != 0)
4765             dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
4766         break;
4767
4768     case PDU_FACK:
4769         dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
4770         break;
4771
4772     case PDU_REJECT:
4773     case PDU_FAULT:
4774         dissect_dcerpc_dg_reject_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
4775         break;
4776
4777     case PDU_REQ:
4778         dissect_dcerpc_dg_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
4779         break;
4780
4781     case PDU_RESP:
4782         dissect_dcerpc_dg_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
4783         break;
4784
4785     /* these requests have no body */
4786     case PDU_ACK:
4787     case PDU_PING:
4788     case PDU_WORKING:
4789     default:
4790         break;
4791     }
4792
4793     return TRUE;
4794 }
4795
4796 static void
4797 dcerpc_init_protocol (void)
4798 {
4799         /* structures and data for BIND */
4800         if (dcerpc_binds){
4801                 g_hash_table_destroy (dcerpc_binds);
4802                 dcerpc_binds=NULL;
4803         } 
4804         if(!dcerpc_binds){
4805                 dcerpc_binds = g_hash_table_new (dcerpc_bind_hash, dcerpc_bind_equal);
4806         }
4807
4808         if (dcerpc_bind_key_chunk){
4809                 g_mem_chunk_destroy (dcerpc_bind_key_chunk);
4810         }
4811         dcerpc_bind_key_chunk = g_mem_chunk_new ("dcerpc_bind_key_chunk",
4812                                              sizeof (dcerpc_bind_key),
4813                                              200 * sizeof (dcerpc_bind_key),
4814                                              G_ALLOC_ONLY);
4815         if (dcerpc_bind_value_chunk){
4816                 g_mem_chunk_destroy (dcerpc_bind_value_chunk);
4817         }
4818         dcerpc_bind_value_chunk = g_mem_chunk_new ("dcerpc_bind_value_chunk",
4819                                              sizeof (dcerpc_bind_value),
4820                                              200 * sizeof (dcerpc_bind_value),
4821                                              G_ALLOC_ONLY);
4822         /* structures and data for CALL */
4823         if (dcerpc_cn_calls){
4824                 g_hash_table_destroy (dcerpc_cn_calls);
4825         }
4826         dcerpc_cn_calls = g_hash_table_new (dcerpc_cn_call_hash, dcerpc_cn_call_equal);
4827         if (dcerpc_dg_calls){
4828                 g_hash_table_destroy (dcerpc_dg_calls);
4829         }
4830         dcerpc_dg_calls = g_hash_table_new (dcerpc_dg_call_hash, dcerpc_dg_call_equal);
4831         if (dcerpc_cn_call_key_chunk){
4832                 g_mem_chunk_destroy (dcerpc_cn_call_key_chunk);
4833         }
4834         dcerpc_cn_call_key_chunk = g_mem_chunk_new ("dcerpc_cn_call_key_chunk",
4835                 sizeof (dcerpc_cn_call_key),
4836                 200 * sizeof (dcerpc_cn_call_key),
4837                 G_ALLOC_ONLY);
4838         if (dcerpc_dg_call_key_chunk){
4839                 g_mem_chunk_destroy (dcerpc_dg_call_key_chunk);
4840         }
4841         dcerpc_dg_call_key_chunk = g_mem_chunk_new ("dcerpc_dg_call_key_chunk",
4842                 sizeof (dcerpc_dg_call_key),
4843                 200 * sizeof (dcerpc_dg_call_key),
4844                 G_ALLOC_ONLY);
4845
4846         if (dcerpc_call_value_chunk){
4847                 g_mem_chunk_destroy (dcerpc_call_value_chunk);
4848         }
4849         dcerpc_call_value_chunk = g_mem_chunk_new ("dcerpc_call_value_chunk",
4850                                              sizeof (dcerpc_call_value),
4851                                              200 * sizeof (dcerpc_call_value),
4852                                              G_ALLOC_ONLY);
4853
4854         /* structure and data for MATCHED */
4855         if (dcerpc_matched){
4856                 g_hash_table_destroy (dcerpc_matched);
4857         }
4858         dcerpc_matched = g_hash_table_new (dcerpc_matched_hash, dcerpc_matched_equal);
4859         if (dcerpc_matched_key_chunk){
4860                 g_mem_chunk_destroy (dcerpc_matched_key_chunk);
4861         }
4862         dcerpc_matched_key_chunk = g_mem_chunk_new ("dcerpc_matched_key_chunk",
4863                                              sizeof (dcerpc_matched_key),
4864                                              200 * sizeof (dcerpc_matched_key),
4865                                              G_ALLOC_ONLY);
4866
4867     /* call the registered hooks */
4868     g_hook_list_invoke(&dcerpc_hooks_init_protos, FALSE /* not may_recurse */);
4869 }
4870
4871 void
4872 proto_register_dcerpc (void)
4873 {
4874     static hf_register_info hf[] = {
4875         { &hf_dcerpc_request_in,
4876                 { "Request in frame", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE,
4877                 NULL, 0, "This packet is a response to the packet with this number", HFILL }},
4878         { &hf_dcerpc_response_in,
4879                 { "Response in frame", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
4880                 NULL, 0, "This packet will be responded in the packet with this number", HFILL }},
4881         { &hf_dcerpc_referent_id,
4882                 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
4883                 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
4884         { &hf_dcerpc_ver,
4885           { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4886         { &hf_dcerpc_ver_minor,
4887           { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4888         { &hf_dcerpc_packet_type,
4889           { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS (pckt_vals), 0x0, "", HFILL }},
4890         { &hf_dcerpc_cn_flags,
4891           { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4892         { &hf_dcerpc_cn_flags_first_frag,
4893           { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_FIRST_FRAG, "", HFILL }},
4894         { &hf_dcerpc_cn_flags_last_frag,
4895           { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_LAST_FRAG, "", HFILL }},
4896         { &hf_dcerpc_cn_flags_cancel_pending,
4897           { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_PENDING_CANCEL, "", HFILL }},
4898         { &hf_dcerpc_cn_flags_reserved,
4899           { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_RESERVED_1, "", HFILL }},
4900         { &hf_dcerpc_cn_flags_mpx,
4901           { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_CONC_MPX, "", HFILL }},
4902         { &hf_dcerpc_cn_flags_dne,
4903           { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_DID_NOT_EXECUTE, "", HFILL }},
4904         { &hf_dcerpc_cn_flags_maybe,
4905           { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_MAYBE, "", HFILL }},
4906         { &hf_dcerpc_cn_flags_object,
4907           { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_OBJECT_UUID, "", HFILL }},
4908         { &hf_dcerpc_drep,
4909           { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
4910         { &hf_dcerpc_drep_byteorder,
4911           { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS (drep_byteorder_vals), 0x0, "", HFILL }},
4912         { &hf_dcerpc_drep_character,
4913           { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS (drep_character_vals), 0x0, "", HFILL }},
4914         { &hf_dcerpc_drep_fp,
4915           { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS (drep_fp_vals), 0x0, "", HFILL }},
4916         { &hf_dcerpc_cn_frag_len,
4917           { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4918         { &hf_dcerpc_cn_auth_len,
4919           { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4920         { &hf_dcerpc_cn_call_id,
4921           { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4922         { &hf_dcerpc_cn_max_xmit,
4923           { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4924         { &hf_dcerpc_cn_max_recv,
4925           { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4926         { &hf_dcerpc_cn_assoc_group,
4927           { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
4928         { &hf_dcerpc_cn_num_ctx_items,
4929           { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4930         { &hf_dcerpc_cn_ctx_id,
4931           { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4932         { &hf_dcerpc_cn_num_trans_items,
4933           { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4934         { &hf_dcerpc_cn_bind_if_id,
4935           { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4936         { &hf_dcerpc_cn_bind_if_ver,
4937           { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4938         { &hf_dcerpc_cn_bind_if_ver_minor,
4939           { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4940         { &hf_dcerpc_cn_bind_trans_id,
4941           { "Transfer Syntax", "dcerpc.cn_bind_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4942         { &hf_dcerpc_cn_bind_trans_ver,
4943           { "Syntax ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4944         { &hf_dcerpc_cn_alloc_hint,
4945           { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4946         { &hf_dcerpc_cn_sec_addr_len,
4947           { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4948         { &hf_dcerpc_cn_sec_addr,
4949           { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, "", HFILL }},
4950         { &hf_dcerpc_cn_num_results,
4951           { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4952         { &hf_dcerpc_cn_ack_result,
4953           { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, "", HFILL }},
4954         { &hf_dcerpc_cn_ack_reason,
4955           { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, "", HFILL }},
4956         { &hf_dcerpc_cn_ack_trans_id,
4957           { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4958         { &hf_dcerpc_cn_ack_trans_ver,
4959           { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4960         { &hf_dcerpc_cn_reject_reason,
4961           { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, "", HFILL }},
4962         { &hf_dcerpc_cn_num_protocols,
4963           { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4964         { &hf_dcerpc_cn_protocol_ver_major,
4965           { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4966         { &hf_dcerpc_cn_protocol_ver_minor,
4967           { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4968         { &hf_dcerpc_cn_cancel_count,
4969           { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4970         { &hf_dcerpc_cn_status,
4971           { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
4972         { &hf_dcerpc_auth_type,
4973           { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
4974         { &hf_dcerpc_auth_level,
4975           { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS (authn_level_vals), 0x0, "", HFILL }},
4976         { &hf_dcerpc_auth_pad_len,
4977           { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4978         { &hf_dcerpc_auth_rsrvd,
4979           { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4980         { &hf_dcerpc_auth_ctx_id,
4981           { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4982         { &hf_dcerpc_dg_flags1,
4983           { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4984         { &hf_dcerpc_dg_flags1_rsrvd_01,
4985           { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_01, "", HFILL }},
4986         { &hf_dcerpc_dg_flags1_last_frag,
4987           { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_LASTFRAG, "", HFILL }},
4988         { &hf_dcerpc_dg_flags1_frag,
4989           { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_FRAG, "", HFILL }},
4990         { &hf_dcerpc_dg_flags1_nofack,
4991           { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_NOFACK, "", HFILL }},
4992         { &hf_dcerpc_dg_flags1_maybe,
4993           { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_MAYBE, "", HFILL }},
4994         { &hf_dcerpc_dg_flags1_idempotent,
4995           { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_IDEMPOTENT, "", HFILL }},
4996         { &hf_dcerpc_dg_flags1_broadcast,
4997           { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_BROADCAST, "", HFILL }},
4998         { &hf_dcerpc_dg_flags1_rsrvd_80,
4999           { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_80, "", HFILL }},
5000         { &hf_dcerpc_dg_flags2,
5001           { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
5002         { &hf_dcerpc_dg_flags2_rsrvd_01,
5003           { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_01, "", HFILL }},
5004         { &hf_dcerpc_dg_flags2_cancel_pending,
5005           { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_CANCEL_PENDING, "", HFILL }},
5006         { &hf_dcerpc_dg_flags2_rsrvd_04,
5007           { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_04, "", HFILL }},
5008         { &hf_dcerpc_dg_flags2_rsrvd_08,
5009           { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_08, "", HFILL }},
5010         { &hf_dcerpc_dg_flags2_rsrvd_10,
5011           { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_10, "", HFILL }},
5012         { &hf_dcerpc_dg_flags2_rsrvd_20,
5013           { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_20, "", HFILL }},
5014         { &hf_dcerpc_dg_flags2_rsrvd_40,
5015           { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_40, "", HFILL }},
5016         { &hf_dcerpc_dg_flags2_rsrvd_80,
5017           { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_80, "", HFILL }},
5018         { &hf_dcerpc_dg_serial_lo,
5019           { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
5020         { &hf_dcerpc_dg_serial_hi,
5021           { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
5022         { &hf_dcerpc_dg_ahint,
5023           { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
5024         { &hf_dcerpc_dg_ihint,
5025           { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
5026         { &hf_dcerpc_dg_frag_len,
5027           { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5028         { &hf_dcerpc_dg_frag_num,
5029           { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5030         { &hf_dcerpc_dg_auth_proto,
5031           { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
5032         { &hf_dcerpc_dg_seqnum,
5033           { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5034         { &hf_dcerpc_dg_server_boot,
5035           { "Server boot time", "dcerpc.dg_server_boot", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0, "", HFILL }},
5036         { &hf_dcerpc_dg_if_ver,
5037           { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5038         { &hf_dcerpc_krb5_av_prot_level,
5039           { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, "", HFILL }},
5040         { &hf_dcerpc_krb5_av_key_vers_num,
5041           { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5042         { &hf_dcerpc_krb5_av_key_auth_verifier,
5043           { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
5044         { &hf_dcerpc_obj_id,
5045           { "Object", "dcerpc.obj_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
5046         { &hf_dcerpc_dg_if_id,
5047           { "Interface", "dcerpc.dg_if_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
5048         { &hf_dcerpc_dg_act_id,
5049           { "Activity", "dcerpc.dg_act_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
5050         { &hf_dcerpc_opnum,
5051           { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5052
5053         { &hf_dcerpc_dg_cancel_vers,
5054           { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5055
5056         { &hf_dcerpc_dg_cancel_id,
5057           { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5058
5059         { &hf_dcerpc_dg_server_accepting_cancels,
5060           { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
5061
5062         { &hf_dcerpc_dg_fack_vers,
5063           { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5064
5065         { &hf_dcerpc_dg_fack_window_size,
5066           { "Window Size", "dcerpc.fack_window_size", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5067
5068         { &hf_dcerpc_dg_fack_max_tsdu,
5069           { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5070
5071         { &hf_dcerpc_dg_fack_max_frag_size,
5072           { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5073
5074         { &hf_dcerpc_dg_fack_serial_num,
5075           { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5076
5077         { &hf_dcerpc_dg_fack_selack_len,
5078           { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5079
5080         { &hf_dcerpc_dg_fack_selack,
5081           { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
5082
5083         { &hf_dcerpc_dg_status,
5084           { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
5085
5086         { &hf_dcerpc_array_max_count,
5087           { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
5088
5089         { &hf_dcerpc_array_offset,
5090           { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
5091
5092         { &hf_dcerpc_array_actual_count,
5093           { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
5094
5095         { &hf_dcerpc_array_buffer,
5096           { "Buffer", "dcerpc.array.buffer", FT_BYTES, BASE_NONE, NULL, 0x0, "Buffer: Buffer containing elements of the array", HFILL }},
5097                 
5098         { &hf_dcerpc_op,
5099           { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5100
5101         { &hf_dcerpc_fragments,
5102           { "DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
5103           NULL, 0x0, "DCE/RPC Fragments", HFILL }},
5104
5105         { &hf_dcerpc_fragment,
5106           { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM, BASE_NONE,
5107           NULL, 0x0, "DCE/RPC Fragment", HFILL }},
5108
5109         { &hf_dcerpc_fragment_overlap,
5110           { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE, 
5111       NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
5112
5113         { &hf_dcerpc_fragment_overlap_conflict,
5114           { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE, 
5115       NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
5116
5117         { &hf_dcerpc_fragment_multiple_tails,
5118           { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE, 
5119       NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
5120
5121         { &hf_dcerpc_fragment_too_long_fragment,
5122           { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE, 
5123       NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
5124
5125         { &hf_dcerpc_fragment_error,
5126           { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE, 
5127       NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
5128
5129         { &hf_dcerpc_time, 
5130           { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE, 
5131       NULL, 0, "Time between Request and Response for DCE-RPC calls", HFILL }},
5132
5133         { &hf_dcerpc_reassembled_in,
5134       { "Reassembled PDU in frame", "dcerpc.reassembled_in", FT_FRAMENUM, BASE_NONE, 
5135       NULL, 0x0, "The DCE/RPC PDU is completely reassembled in the packet with this number", HFILL }},
5136
5137         { &hf_dcerpc_unknown_if_id, 
5138           { "Unknown DCERPC interface id", "dcerpc.unknown_if_id", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
5139    };
5140     static gint *ett[] = {
5141         &ett_dcerpc,
5142         &ett_dcerpc_cn_flags,
5143         &ett_dcerpc_cn_ctx,
5144         &ett_dcerpc_cn_iface,
5145         &ett_dcerpc_drep,
5146         &ett_dcerpc_dg_flags1,
5147         &ett_dcerpc_dg_flags2,
5148         &ett_dcerpc_pointer_data,
5149         &ett_dcerpc_string,
5150         &ett_dcerpc_fragments,
5151         &ett_dcerpc_fragment,
5152         &ett_dcerpc_krb5_auth_verf,
5153     };
5154     module_t *dcerpc_module;
5155
5156     proto_dcerpc = proto_register_protocol ("DCE RPC", "DCERPC", "dcerpc");
5157     proto_register_field_array (proto_dcerpc, hf, array_length (hf));
5158     proto_register_subtree_array (ett, array_length (ett));
5159     register_init_routine (dcerpc_init_protocol);
5160     dcerpc_module = prefs_register_protocol (proto_dcerpc, NULL);
5161     prefs_register_bool_preference (dcerpc_module,
5162                                     "desegment_dcerpc",
5163                                     "Reassemble DCE/RPC messages spanning multiple TCP segments",
5164                                     "Whether the DCE/RPC dissector should reassemble messages spanning multiple TCP segments."
5165                                     " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
5166                                     &dcerpc_cn_desegment);
5167     prefs_register_bool_preference (dcerpc_module,
5168                                     "reassemble_dcerpc",
5169                                     "Reassemble DCE/RPC fragments",
5170                                     "Whether the DCE/RPC dissector should reassemble fragmented DCE/RPC PDUs",
5171                                     &dcerpc_reassemble);
5172     register_init_routine(dcerpc_reassemble_init);
5173     dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
5174     dcerpc_tap=register_tap("dcerpc");
5175     
5176     g_hook_list_init(&dcerpc_hooks_init_protos, sizeof(GHook));
5177 }
5178
5179 void
5180 proto_reg_handoff_dcerpc (void)
5181 {
5182     heur_dissector_add ("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
5183     heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
5184     heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
5185     heur_dissector_add ("smb_transact", dissect_dcerpc_cn_smbpipe, proto_dcerpc);
5186     heur_dissector_add ("http", dissect_dcerpc_cn_bs, proto_dcerpc);
5187     dcerpc_smb_init(proto_dcerpc);
5188 }