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