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