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