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