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