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