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