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