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