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