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