6e7d21d3aa91eadcb5a29f712a7d6fdfc6939b9e
[metze/wireshark/wip.git] / packet-dcerpc.c
1 /* packet-dcerpc.c
2  * Routines for DCERPC packet disassembly
3  * Copyright 2001, Todd Sabin <tas@webspan.net>
4  *
5  * $Id: packet-dcerpc.c,v 1.53 2002/06/04 07:03:44 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #ifdef HAVE_SYS_TYPES_H
31 #include <sys/types.h>
32 #endif
33
34 #include <string.h>
35 #include <ctype.h>
36
37 #include <glib.h>
38 #include <epan/packet.h>
39 #include "packet-dcerpc.h"
40 #include <epan/conversation.h>
41 #include "prefs.h"
42 #include "reassemble.h"
43
44 static const value_string pckt_vals[] = {
45     { 0, "Request"},
46     { 1, "Ping"},
47     { 2, "Response"},
48     { 3, "Fault"},
49     { 4, "Working"},
50     { 5, "Nocall"},
51     { 6, "Reject"},
52     { 7, "Ack"},
53     { 8, "Cl_cancel"},
54     { 9, "Fack"},
55     { 10, "Cancel_ack"},
56     { 11, "Bind"},
57     { 12, "Bind_ack"},
58     { 13, "Bind_nak"},
59     { 14, "Alter_context"},
60     { 15, "Alter_context_resp"},
61     { 16, "AUTH3?"},
62     { 17, "Shutdown"},
63     { 18, "Co_cancel"},
64     { 19, "Orphaned"},
65     { 0,  NULL }
66 };
67
68 static const value_string drep_byteorder_vals[] = {
69     { 0, "Big-endian" },
70     { 1, "Little-endian" },
71     { 0,  NULL }
72 };
73
74 static const value_string drep_character_vals[] = {
75     { 0, "ASCII" },
76     { 1, "EBCDIC" },
77     { 0,  NULL }
78 };
79
80 static const value_string drep_fp_vals[] = {
81     { 0, "IEEE" },
82     { 1, "VAX" },
83     { 2, "Cray" },
84     { 3, "IBM" },
85     { 0,  NULL }
86 };
87
88 static const true_false_string flags_set_truth = {
89   "Set",
90   "Not set"
91 };
92
93 /*
94  * Authentication services.
95  */
96 static const value_string authn_protocol_vals[] = {
97         { 0, "None" },
98         { 1, "Kerberos 5" },
99         { 0, NULL }
100 };
101
102 /*
103  * Protection levels.
104  */
105 #define DCE_C_AUTHN_LEVEL_NONE          1
106 #define DCE_C_AUTHN_LEVEL_CONNECT       2
107 #define DCE_C_AUTHN_LEVEL_CALL          3
108 #define DCE_C_AUTHN_LEVEL_PKT           4
109 #define DCE_C_AUTHN_LEVEL_PKT_INTEGRITY 5
110 #define DCE_C_AUTHN_LEVEL_PKT_PRIVACY   6
111
112 static const value_string authn_level_vals[] = {
113         { DCE_C_AUTHN_LEVEL_NONE,          "None" },
114         { DCE_C_AUTHN_LEVEL_CONNECT,       "Connect" },
115         { DCE_C_AUTHN_LEVEL_CALL,          "Call" },
116         { DCE_C_AUTHN_LEVEL_PKT,           "Packet" },
117         { DCE_C_AUTHN_LEVEL_PKT_INTEGRITY, "Packet integrity" },
118         { DCE_C_AUTHN_LEVEL_PKT_PRIVACY,   "Packet privacy" },
119         { 0,                               NULL }
120 };
121
122 static int proto_dcerpc = -1;
123
124 /* field defines */
125 static int hf_dcerpc_request_in = -1;
126 static int hf_dcerpc_response_in = -1;
127 static int hf_dcerpc_ver = -1;
128 static int hf_dcerpc_ver_minor = -1;
129 static int hf_dcerpc_packet_type = -1;
130 static int hf_dcerpc_cn_flags = -1;
131 static int hf_dcerpc_cn_flags_first_frag = -1;
132 static int hf_dcerpc_cn_flags_last_frag = -1;
133 static int hf_dcerpc_cn_flags_cancel_pending = -1;
134 static int hf_dcerpc_cn_flags_reserved = -1;
135 static int hf_dcerpc_cn_flags_mpx = -1;
136 static int hf_dcerpc_cn_flags_dne = -1;
137 static int hf_dcerpc_cn_flags_maybe = -1;
138 static int hf_dcerpc_cn_flags_object = -1;
139 static int hf_dcerpc_drep = -1;
140 static int hf_dcerpc_drep_byteorder = -1;
141 static int hf_dcerpc_drep_character = -1;
142 static int hf_dcerpc_drep_fp = -1;
143 static int hf_dcerpc_cn_frag_len = -1;
144 static int hf_dcerpc_cn_auth_len = -1;
145 static int hf_dcerpc_cn_call_id = -1;
146 static int hf_dcerpc_cn_max_xmit = -1;
147 static int hf_dcerpc_cn_max_recv = -1;
148 static int hf_dcerpc_cn_assoc_group = -1;
149 static int hf_dcerpc_cn_num_ctx_items = -1;
150 static int hf_dcerpc_cn_ctx_id = -1;
151 static int hf_dcerpc_cn_num_trans_items = -1;
152 static int hf_dcerpc_cn_bind_if_id = -1;
153 static int hf_dcerpc_cn_bind_if_ver = -1;
154 static int hf_dcerpc_cn_bind_if_ver_minor = -1;
155 static int hf_dcerpc_cn_bind_trans_id = -1;
156 static int hf_dcerpc_cn_bind_trans_ver = -1;
157 static int hf_dcerpc_cn_alloc_hint = -1;
158 static int hf_dcerpc_cn_sec_addr_len = -1;
159 static int hf_dcerpc_cn_sec_addr = -1;
160 static int hf_dcerpc_cn_num_results = -1;
161 static int hf_dcerpc_cn_ack_result = -1;
162 static int hf_dcerpc_cn_ack_reason = -1;
163 static int hf_dcerpc_cn_ack_trans_id = -1;
164 static int hf_dcerpc_cn_ack_trans_ver = -1;
165 static int hf_dcerpc_cn_cancel_count = -1;
166 static int hf_dcerpc_auth_type = -1;
167 static int hf_dcerpc_auth_level = -1;
168 static int hf_dcerpc_auth_pad_len = -1;
169 static int hf_dcerpc_auth_rsrvd = -1;
170 static int hf_dcerpc_auth_ctx_id = -1;
171 static int hf_dcerpc_dg_flags1 = -1;
172 static int hf_dcerpc_dg_flags1_rsrvd_01 = -1;
173 static int hf_dcerpc_dg_flags1_last_frag = -1;
174 static int hf_dcerpc_dg_flags1_frag = -1;
175 static int hf_dcerpc_dg_flags1_nofack = -1;
176 static int hf_dcerpc_dg_flags1_maybe = -1;
177 static int hf_dcerpc_dg_flags1_idempotent = -1;
178 static int hf_dcerpc_dg_flags1_broadcast = -1;
179 static int hf_dcerpc_dg_flags1_rsrvd_80 = -1;
180 static int hf_dcerpc_dg_flags2 = -1;
181 static int hf_dcerpc_dg_flags2_rsrvd_01 = -1;
182 static int hf_dcerpc_dg_flags2_cancel_pending = -1;
183 static int hf_dcerpc_dg_flags2_rsrvd_04 = -1;
184 static int hf_dcerpc_dg_flags2_rsrvd_08 = -1;
185 static int hf_dcerpc_dg_flags2_rsrvd_10 = -1;
186 static int hf_dcerpc_dg_flags2_rsrvd_20 = -1;
187 static int hf_dcerpc_dg_flags2_rsrvd_40 = -1;
188 static int hf_dcerpc_dg_flags2_rsrvd_80 = -1;
189 static int hf_dcerpc_dg_serial_hi = -1;
190 static int hf_dcerpc_obj_id = -1;
191 static int hf_dcerpc_dg_if_id = -1;
192 static int hf_dcerpc_dg_act_id = -1;
193 static int hf_dcerpc_dg_serial_lo = -1;
194 static int hf_dcerpc_dg_ahint = -1;
195 static int hf_dcerpc_dg_ihint = -1;
196 static int hf_dcerpc_dg_frag_len = -1;
197 static int hf_dcerpc_dg_frag_num = -1;
198 static int hf_dcerpc_dg_auth_proto = -1;
199 static int hf_dcerpc_opnum = -1;
200 static int hf_dcerpc_dg_seqnum = -1;
201 static int hf_dcerpc_dg_server_boot = -1;
202 static int hf_dcerpc_dg_if_ver = -1;
203 static int hf_dcerpc_array_max_count = -1;
204 static int hf_dcerpc_array_offset = -1;
205 static int hf_dcerpc_array_actual_count = -1;
206 static int hf_dcerpc_op = -1;
207 static int hf_dcerpc_referent_id = -1;
208 static int hf_dcerpc_fragments = -1;
209 static int hf_dcerpc_fragment = -1;
210 static int hf_dcerpc_fragment_overlap = -1;
211 static int hf_dcerpc_fragment_overlap_conflict = -1;
212 static int hf_dcerpc_fragment_multiple_tails = -1;
213 static int hf_dcerpc_fragment_too_long_fragment = -1;
214 static int hf_dcerpc_fragment_error = -1;
215
216 static gint ett_dcerpc = -1;
217 static gint ett_dcerpc_cn_flags = -1;
218 static gint ett_dcerpc_drep = -1;
219 static gint ett_dcerpc_dg_flags1 = -1;
220 static gint ett_dcerpc_dg_flags2 = -1;
221 static gint ett_dcerpc_pointer_data = -1;
222 static gint ett_dcerpc_fragments = -1;
223 static gint ett_dcerpc_fragment = -1;
224
225 /* try to desegment big DCE/RPC packets over TCP? */
226 static gboolean dcerpc_cn_desegment = TRUE;
227
228 /* reassemble DCE/RPC fragments */
229 /* reassembly of dcerpc fragments will not work for the case where ONE frame 
230    might contain multiple dcerpc fragments for different PDUs.
231    this case would be so unusual/weird so if you got captures like that:
232         too bad
233 */
234 static gboolean dcerpc_reassemble = FALSE;
235 static GHashTable *dcerpc_reassemble_table = NULL;
236
237 static void
238 dcerpc_reassemble_init(void)
239 {
240   fragment_table_init(&dcerpc_reassemble_table);
241 }
242
243 /*
244  * Subdissectors
245  */
246
247 /* the registered subdissectors */
248 static GHashTable *dcerpc_uuids;
249
250 typedef struct _dcerpc_uuid_key {
251     e_uuid_t uuid;
252     guint16 ver;
253 } dcerpc_uuid_key;
254
255 typedef struct _dcerpc_uuid_value {
256     int proto;
257     int ett;
258     gchar *name;
259     dcerpc_sub_dissector *procs;
260 } dcerpc_uuid_value;
261
262 static gint
263 dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2)
264 {
265     dcerpc_uuid_key *key1 = (dcerpc_uuid_key *)k1;
266     dcerpc_uuid_key *key2 = (dcerpc_uuid_key *)k2;
267     return ((memcmp (&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
268             && (key1->ver == key2->ver));
269 }
270
271 static guint
272 dcerpc_uuid_hash (gconstpointer k)
273 {
274     dcerpc_uuid_key *key = (dcerpc_uuid_key *)k;
275     /* This isn't perfect, but the Data1 part of these is almost always
276        unique. */
277     return key->uuid.Data1;
278 }
279
280 void
281 dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver,
282                   dcerpc_sub_dissector *procs)
283 {
284     dcerpc_uuid_key *key = g_malloc (sizeof (*key));
285     dcerpc_uuid_value *value = g_malloc (sizeof (*value));
286
287     key->uuid = *uuid;
288     key->ver = ver;
289
290     value->proto = proto;
291     value->ett = ett;
292     value->name = proto_get_protocol_short_name (proto);
293     value->procs = procs;
294
295     g_hash_table_insert (dcerpc_uuids, key, value);
296 }
297
298
299 /*
300  * To keep track of ctx_id mappings.
301  *
302  * Everytime we see a bind call we update this table.
303  * Note that we always specify a SMB FID. For non-SMB transports this
304  * value is 0.
305  */
306 static GHashTable *dcerpc_binds=NULL;
307
308 typedef struct _dcerpc_bind_key {
309     conversation_t *conv;
310     guint16 ctx_id;
311     guint16 smb_fid;
312 } dcerpc_bind_key;
313
314 typedef struct _dcerpc_bind_value {
315         e_uuid_t uuid;
316         guint16 ver;
317 } dcerpc_bind_value;
318
319 static GMemChunk *dcerpc_bind_key_chunk=NULL;
320 static GMemChunk *dcerpc_bind_value_chunk=NULL;
321
322 static gint
323 dcerpc_bind_equal (gconstpointer k1, gconstpointer k2)
324 {
325     dcerpc_bind_key *key1 = (dcerpc_bind_key *)k1;
326     dcerpc_bind_key *key2 = (dcerpc_bind_key *)k2;
327     return (key1->conv == key2->conv
328             && key1->ctx_id == key2->ctx_id
329             && key1->smb_fid == key2->smb_fid);
330 }
331
332 static guint
333 dcerpc_bind_hash (gconstpointer k)
334 {
335     dcerpc_bind_key *key = (dcerpc_bind_key *)k;
336     return ((guint)key->conv) + key->ctx_id + key->smb_fid;
337 }
338
339 /*
340  * To keep track of callid mappings.  Should really use some generic
341  * conversation support instead.
342  */
343 static GHashTable *dcerpc_calls=NULL;
344
345 typedef struct _dcerpc_call_key {
346     conversation_t *conv;
347     guint32 call_id;
348     guint16 smb_fid;
349 } dcerpc_call_key;
350
351 static GMemChunk *dcerpc_call_key_chunk=NULL;
352
353 static GMemChunk *dcerpc_call_value_chunk=NULL;
354
355 static gint
356 dcerpc_call_equal (gconstpointer k1, gconstpointer k2)
357 {
358     dcerpc_call_key *key1 = (dcerpc_call_key *)k1;
359     dcerpc_call_key *key2 = (dcerpc_call_key *)k2;
360     return (key1->conv == key2->conv
361             && key1->call_id == key2->call_id
362             && key1->smb_fid == key2->smb_fid);
363 }
364
365 static guint
366 dcerpc_call_hash (gconstpointer k)
367 {
368     dcerpc_call_key *key = (dcerpc_call_key *)k;
369     return ((guint32)key->conv) + key->call_id + key->smb_fid;
370 }
371
372
373 /* to keep track of matched calls/responses
374    this one uses the same value struct as calls, but the key is the frame id
375 */
376 static GHashTable *dcerpc_matched=NULL;
377 static gint
378 dcerpc_matched_equal (gconstpointer k1, gconstpointer k2)
379 {
380         return (guint32)k1 == (guint32)k2;
381 }
382
383 static guint
384 dcerpc_matched_hash (gconstpointer k)
385 {
386         return (guint32)k;
387 }
388
389
390
391 /*
392  * Utility functions.  Modeled after packet-rpc.c
393  */
394
395 int
396 dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
397                       proto_tree *tree, char *drep, 
398                       int hfindex, guint8 *pdata)
399 {
400     guint8 data;
401
402     data = tvb_get_guint8 (tvb, offset);
403     if (tree) {
404         proto_tree_add_item (tree, hfindex, tvb, offset, 1, (drep[0] & 0x10));
405     }
406     if (pdata)
407         *pdata = data;
408     return offset + 1;
409 }
410
411 int
412 dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
413                        proto_tree *tree, char *drep, 
414                        int hfindex, guint16 *pdata)
415 {
416     guint16 data;
417
418     data = ((drep[0] & 0x10)
419             ? tvb_get_letohs (tvb, offset)
420             : tvb_get_ntohs (tvb, offset));
421     
422     if (tree) {
423         proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10));
424     }
425     if (pdata)
426         *pdata = data;
427     return offset + 2;
428 }
429
430 int
431 dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
432                        proto_tree *tree, char *drep, 
433                        int hfindex, guint32 *pdata)
434 {
435     guint32 data;
436
437     data = ((drep[0] & 0x10)
438             ? tvb_get_letohl (tvb, offset)
439             : tvb_get_ntohl (tvb, offset));
440     
441     if (tree) {
442         proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10));
443     }
444     if (pdata)
445         *pdata = data;
446     return offset+4;
447 }
448
449 int
450 dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
451                        proto_tree *tree, char *drep, 
452                        int hfindex, unsigned char *pdata)
453 {
454     if(pdata){
455       tvb_memcpy(tvb, pdata, offset, 8);
456       if(drep[0] & 0x10){/* XXX this might be the wrong way around */
457         unsigned char data;
458         data=pdata[0];pdata[0]=pdata[7];pdata[7]=data;
459         data=pdata[1];pdata[1]=pdata[6];pdata[6]=data;
460         data=pdata[2];pdata[2]=pdata[5];pdata[5]=data;
461         data=pdata[3];pdata[3]=pdata[4];pdata[4]=data;
462       }
463     }
464
465     if (tree) {
466         proto_tree_add_item(tree, hfindex, tvb, offset, 8, (drep[0] & 0x10));
467     }
468
469     return offset+8;
470 }
471
472 /*
473  * a couple simpler things
474  */
475 guint16
476 dcerpc_tvb_get_ntohs (tvbuff_t *tvb, gint offset, char *drep)
477 {
478     if (drep[0] & 0x10) {
479         return tvb_get_letohs (tvb, offset);
480     } else {
481         return tvb_get_ntohs (tvb, offset);
482     }
483 }
484
485 guint32
486 dcerpc_tvb_get_ntohl (tvbuff_t *tvb, gint offset, char *drep)
487 {
488     if (drep[0] & 0x10) {
489         return tvb_get_letohl (tvb, offset);
490     } else {
491         return tvb_get_ntohl (tvb, offset);
492     }
493 }
494
495 void
496 dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, char *drep, e_uuid_t *uuid)
497 {
498     unsigned int i;
499     uuid->Data1 = dcerpc_tvb_get_ntohl (tvb, offset, drep);
500     uuid->Data2 = dcerpc_tvb_get_ntohs (tvb, offset+4, drep);
501     uuid->Data3 = dcerpc_tvb_get_ntohs (tvb, offset+6, drep);
502
503     for (i=0; i<sizeof (uuid->Data4); i++) {
504         uuid->Data4[i] = tvb_get_guint8 (tvb, offset+8+i);
505     }
506 }
507
508
509
510 /* NDR arrays */
511 /* function to dissect a unidimensional conformant array */
512 int 
513 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
514                 proto_tree *tree, char *drep, 
515                 dcerpc_dissect_fnct_t *fnct)
516 {
517         guint32 i;
518         dcerpc_info *di;
519         int old_offset;
520
521         di=pinfo->private_data;
522         if(di->conformant_run){
523                 /* conformant run, just dissect the max_count header */
524                 old_offset=offset;
525                 di->conformant_run=0;
526                 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
527                                 hf_dcerpc_array_max_count, &di->array_max_count);
528                 di->array_max_count_offset=offset-4;
529                 di->conformant_run=1;
530                 di->conformant_eaten=offset-old_offset;
531         } else {
532                 /* we dont dont remember where  in the bytestream this fields was */
533                 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
534
535                 /* real run, dissect the elements */
536                 for(i=0;i<di->array_max_count;i++){
537                         offset = (*fnct)(tvb, offset, pinfo, tree, drep);
538                 }
539         }
540
541         return offset;
542 }
543 /* function to dissect a unidimensional conformant and varying array */
544 int 
545 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
546                 proto_tree *tree, char *drep, 
547                 dcerpc_dissect_fnct_t *fnct)
548 {
549         guint32 i;
550         dcerpc_info *di;
551         int old_offset;
552
553         di=pinfo->private_data;
554         if(di->conformant_run){
555                 /* conformant run, just dissect the max_count header */
556                 old_offset=offset;
557                 di->conformant_run=0;
558                 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
559                                 hf_dcerpc_array_max_count, &di->array_max_count);
560                 di->array_max_count_offset=offset-4;
561                 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
562                                 hf_dcerpc_array_offset, &di->array_offset);
563                 di->array_offset_offset=offset-4;
564                 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
565                                 hf_dcerpc_array_actual_count, &di->array_actual_count);
566                 di->array_actual_count_offset=offset-4;
567                 di->conformant_run=1;
568                 di->conformant_eaten=offset-old_offset;
569         } else {
570                 /* we dont dont remember where  in the bytestream these fields were */
571                 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
572                 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
573                 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
574
575                 /* real run, dissect the elements */
576                 for(i=0;i<di->array_actual_count;i++){
577                         offset = (*fnct)(tvb, offset, pinfo, tree, drep);
578                 }
579         }
580
581         return offset;
582 }
583
584
585 /* ndr pointer handling */
586 /* list of pointers encountered so far */
587 static GSList *ndr_pointer_list = NULL;
588
589 /* position where in the list to insert newly encountered pointers */
590 static int ndr_pointer_list_pos=0;
591
592 /* boolean controlling whether pointers are top-level or embedded */
593 static gboolean pointers_are_top_level = TRUE;
594
595 /* as a kludge, we represent all embedded reference pointers as id==-1
596    hoping that his will not collide with any non-ref pointers */
597 typedef struct ndr_pointer_data {
598         guint32 id;
599         proto_tree *tree;
600         dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
601         int hf_index;
602         int levels;
603 } ndr_pointer_data_t;
604
605 static void
606 init_ndr_pointer_list(packet_info *pinfo)
607 {
608         dcerpc_info *di;
609
610         di=pinfo->private_data;
611         di->conformant_run=0;
612
613         while(ndr_pointer_list){
614                 ndr_pointer_data_t *npd;
615         
616                 npd=g_slist_nth_data(ndr_pointer_list, 0);
617                 ndr_pointer_list=g_slist_remove(ndr_pointer_list, npd);
618                 if(npd){
619                         g_free(npd);
620                 }
621         }
622
623         ndr_pointer_list=NULL;
624         ndr_pointer_list_pos=0;
625         pointers_are_top_level=TRUE;
626 }
627
628 static int
629 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, char *drep)
630 {
631         int found_new_pointer;
632         dcerpc_info *di;
633         int old_offset;
634
635         di=pinfo->private_data;
636         do{
637                 int i, len;
638
639                 found_new_pointer=0;
640                 len=g_slist_length(ndr_pointer_list);
641                 for(i=0;i<len;i++){
642                         ndr_pointer_data_t *tnpd;
643                         tnpd=g_slist_nth_data(ndr_pointer_list, i);
644                         if(tnpd->fnct){
645                                 dcerpc_dissect_fnct_t *fnct;
646
647                                 found_new_pointer=1;
648                                 fnct=tnpd->fnct;
649                                 tnpd->fnct=NULL;
650                                 ndr_pointer_list_pos=i+1;
651                                 di->hf_index=tnpd->hf_index;
652                                 di->levels=tnpd->levels;
653                                 /* first a run to handle any conformant
654                                    array headers */
655                                 di->conformant_run=1;
656                                 di->conformant_eaten=0;
657                                 old_offset = offset;
658                                 offset = (*(fnct))(tvb, offset, pinfo, NULL, drep);
659
660                                 g_assert((offset-old_offset)==di->conformant_eaten);
661                                 /* This is to check for any bugs in the dissectors.
662                                  *
663                                  * Basically, the NDR representation will store all
664                                  * arrays in two blocks, one block with the dimension 
665                                  * discreption, like size, number of elements and such,
666                                  * and another block that contains the actual data stored
667                                  * in the array.
668                                  * If the array is embedded directly inside another, 
669                                  * encapsulating aggregate type, like a union or struct,
670                                  * then these two blocks will be stored at different places
671                                  * in the bytestream, with other data between the blocks.
672                                  *
673                                  * For this reason, all pointers to types (both aggregate
674                                  * and scalar, for simplicity no distinction is made)
675                                  * will have its dissector called twice.
676                                  * The dissector will first be called with conformant_run==1
677                                  * in which mode the dissector MUST NOT consume any data from
678                                  * the tvbuff (i.e. may not dissect anything) except the
679                                  * initial control block for arrays.
680                                  * The second time the dissector is called, with 
681                                  * conformant_run==0, all other data for the type will be 
682                                  * dissected.
683                                  *
684                                  * All dissect_ndr_<type> dissectors are already prepared
685                                  * for this and knows when it should eat data from the tvb
686                                  * and when not to, so implementors of dissectors will
687                                  * normally not need to worry about this or even know about
688                                  * it. However, if a dissector for an aggregate type calls
689                                  * a subdissector from outside packet-dcerpc.c, such as
690                                  * the dissector in packet-smb.c for NT Security Descriptors
691                                  * as an example, then it is VERY important to encapsulate
692                                  * this call to an external subdissector with the appropriate
693                                  * test for conformant_run, i.e. it will need something like
694                                  *
695                                  *      dcerpc_info *di;
696                                  *
697                                  *      di=pinfo->private_data;
698                                  *      if(di->conformant_run){
699                                  *              return offset;
700                                  *      }
701                                  * 
702                                  * to make sure it makes the right thing.
703                                  * This assert will signal when someone has forgotten to
704                                  * make the dissector aware of this requirement.
705                                  */
706
707                                 /* now we dissect the actual pointer */
708                                 di->conformant_run=0;
709                                 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, drep);
710                                 break;
711                         }
712                 }
713         } while(found_new_pointer);
714
715         return offset;
716 }
717                                                 
718
719 static void
720 add_pointer_to_list(packet_info *pinfo, proto_tree *tree, 
721                 dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index, int levels)
722 {
723         ndr_pointer_data_t *npd;
724
725         /* check if this pointer is valid */
726         if(id!=0xffffffff){
727                 dcerpc_info *di;
728                 dcerpc_call_value *value;
729
730                 di=pinfo->private_data;
731                 value=di->call_data;
732
733                 if(di->request){
734                         if(!(pinfo->fd->flags.visited)){
735                                 if(id>value->max_ptr){
736                                         value->max_ptr=id;
737                                 }
738                         }
739                 } else {
740                         /* if we havent seen the request bail out since we cant
741                            know whether this is the first non-NULL instance 
742                            or not */
743                         if(value->req_frame==0){
744                                 /* XXX THROW EXCEPTION */
745                         }
746
747                         /* We saw this one in the request frame, nothing to
748                            dissect later */
749                         if(id<=value->max_ptr){
750                                 return;
751                         }
752                 }
753         }
754
755         npd=g_malloc(sizeof(ndr_pointer_data_t));
756         npd->id=id;
757         npd->tree=tree;
758         npd->fnct=fnct;
759         npd->hf_index=hf_index;
760         npd->levels=levels;
761         ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd, 
762                                         ndr_pointer_list_pos);
763         ndr_pointer_list_pos++;
764 }
765
766
767 static int
768 find_pointer_index(guint32 id)
769 {
770         ndr_pointer_data_t *npd;
771         int i,len;
772         
773         len=g_slist_length(ndr_pointer_list);
774         for(i=0;i<len;i++){
775                 npd=g_slist_nth_data(ndr_pointer_list, i);
776                 if(npd){
777                         if(npd->id==id){
778                                 return i;
779                         }
780                 }
781         }
782         
783         return -1;
784 }
785
786 /* This function dissects an NDR pointer and stores the callback for later
787  * deferred dissection.  
788  *
789  *   fnct is the callback function for when we have reached this object in
790  *   the bytestream.  
791  * 
792  *   type is what type of pointer.
793  *
794  *   this is text is what text we should put in any created tree node.
795  *
796  *   hf_index is what hf value we want to pass to the callback function when
797  *   it is called, the callback can later pich this one up from di->hf_index.
798  * 
799  *   levels is a generic int we want to pass to teh callback function.  the
800  *   callback can later pick it up from di->levels
801  *
802  * See packet-dcerpc-samr.c for examples
803  */
804 int 
805 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
806                     proto_tree *tree, char *drep, dcerpc_dissect_fnct_t *fnct,
807                     int type, char *text, int hf_index, int levels)
808 {
809         dcerpc_info *di;
810         
811         di=pinfo->private_data;
812         if(di->conformant_run){
813                 /* this call was only for dissecting the header for any
814                    embedded conformant array. we will not parse any
815                    pointers in this mode.
816                 */
817                 return offset;
818         }
819
820         /*TOP LEVEL REFERENCE POINTER*/
821         if( pointers_are_top_level
822         &&(type==NDR_POINTER_REF) ){
823                 proto_item *item;
824                 proto_tree *tr;
825
826                 /* we must find out a nice way to do the length here */
827                 item=proto_tree_add_text(tree, tvb, offset, 0, 
828                         "%s", text);
829                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
830
831                 add_pointer_to_list(pinfo, tr, fnct, 0xffffffff, hf_index, levels);
832                 goto after_ref_id;
833         }
834
835         /*TOP LEVEL FULL POINTER*/
836         if( pointers_are_top_level
837         && (type==NDR_POINTER_PTR) ){
838                 int idx;
839                 guint32 id;
840                 proto_item *item;
841                 proto_tree *tr;
842
843                 /* get the referent id */
844                 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
845         
846                 /* we got a NULL pointer */
847                 if(id==0){
848                         proto_tree_add_text(tree, tvb, offset-4, 4,
849                                 "(NULL pointer) %s",text);
850                         goto after_ref_id;
851                 }
852
853                 /* see if we have seen this pointer before */
854                 idx=find_pointer_index(id);
855
856                 /* we have seen this pointer before */
857                 if(idx>=0){
858                         proto_tree_add_text(tree, tvb, offset-4, 4,
859                                 "(duplicate PTR) %s",text);
860                         goto after_ref_id;
861                 }
862
863                 /* new pointer */
864                 item=proto_tree_add_text(tree, tvb, offset-4, 4, 
865                         "%s", text);
866                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
867                 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
868                 add_pointer_to_list(pinfo, tr, fnct, id, hf_index, levels);
869                 goto after_ref_id;
870         }
871         /*TOP LEVEL UNIQUE POINTER*/
872         if( pointers_are_top_level
873         && (type==NDR_POINTER_UNIQUE) ){
874                 guint32 id;
875                 proto_item *item;
876                 proto_tree *tr;
877
878                 /* get the referent id */
879                 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
880         
881                 /* we got a NULL pointer */
882                 if(id==0){
883                         proto_tree_add_text(tree, tvb, offset-4, 4,
884                                 "(NULL pointer) %s",text);
885                         goto after_ref_id;
886                 }
887
888                 /* new pointer */
889                 item=proto_tree_add_text(tree, tvb, offset-4, 4, 
890                         "%s", text);
891                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
892                 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
893                 add_pointer_to_list(pinfo, tr, fnct, 0xffffffff, hf_index, levels);
894                 goto after_ref_id;
895         }
896
897         /*EMBEDDED REFERENCE POINTER*/
898         if( (!pointers_are_top_level)
899         && (type==NDR_POINTER_REF) ){
900                 guint32 id;
901                 proto_item *item;
902                 proto_tree *tr;
903
904                 /* get the referent id */
905                 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
906         
907                 /* new pointer */
908                 item=proto_tree_add_text(tree, tvb, offset-4, 4, 
909                         "%s",text);
910                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
911                 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
912                 add_pointer_to_list(pinfo, tr, fnct, 0xffffffff, hf_index, levels);
913                 goto after_ref_id;
914         }
915
916         /*EMBEDDED UNIQUE POINTER*/
917         if( (!pointers_are_top_level)
918         && (type==NDR_POINTER_UNIQUE) ){
919                 guint32 id;
920                 proto_item *item;
921                 proto_tree *tr;
922
923                 /* get the referent id */
924                 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
925         
926                 /* we got a NULL pointer */
927                 if(id==0){
928                         proto_tree_add_text(tree, tvb, offset-4, 4,
929                                 "(NULL pointer) %s", text);
930                         goto after_ref_id;
931                 }
932
933                 /* new pointer */
934                 item=proto_tree_add_text(tree, tvb, offset-4, 4, 
935                         "%s",text);
936                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
937                 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
938                 add_pointer_to_list(pinfo, tr, fnct, 0xffffffff, hf_index, levels);
939                 goto after_ref_id;
940         }
941
942         /*EMBEDDED FULL POINTER*/
943         if( (!pointers_are_top_level)
944         && (type==NDR_POINTER_PTR) ){
945                 int idx;
946                 guint32 id;
947                 proto_item *item;
948                 proto_tree *tr;
949
950                 /* get the referent id */
951                 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
952         
953                 /* we got a NULL pointer */
954                 if(id==0){
955                         proto_tree_add_text(tree, tvb, offset-4, 4,
956                                 "(NULL pointer) %s",text);
957                         goto after_ref_id;
958                 }
959
960                 /* see if we have seen this pointer before */
961                 idx=find_pointer_index(id);
962
963                 /* we have seen this pointer before */
964                 if(idx>=0){
965                         proto_tree_add_text(tree, tvb, offset-4, 4,
966                                 "(duplicate PTR) %s",text);
967                         goto after_ref_id;
968                 }
969
970                 /* new pointer */
971                 item=proto_tree_add_text(tree, tvb, offset-4, 4, 
972                         "%s", text);
973                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
974                 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
975                 add_pointer_to_list(pinfo, tr, fnct, id, hf_index, levels);
976                 goto after_ref_id;
977         }
978
979
980 after_ref_id:
981         /* After each top level pointer we have dissected we have to
982            dissect all deferrals before we move on to the next top level
983            argument */
984         if(pointers_are_top_level==TRUE){
985                 pointers_are_top_level=FALSE;
986                 offset = dissect_deferred_pointers(pinfo, tvb, offset, drep);
987                 pointers_are_top_level=TRUE;
988         }
989
990         return offset;
991 }
992
993
994
995 static int
996 dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
997                     proto_tree *dcerpc_tree,
998                     tvbuff_t *tvb, gint offset,
999                     guint16 opnum, gboolean is_rqst,
1000                     char *drep, dcerpc_info *info,
1001                     int auth_level)
1002 {
1003     dcerpc_uuid_key key;
1004     dcerpc_uuid_value *sub_proto;
1005     int length;
1006     proto_tree *sub_tree = NULL;
1007     dcerpc_sub_dissector *proc;
1008     gchar *name = NULL;
1009     dcerpc_dissect_fnct_t *sub_dissect;
1010     const char *saved_proto;
1011     void *saved_private_data;
1012
1013     key.uuid = info->call_data->uuid;
1014     key.ver = info->call_data->ver;
1015
1016     
1017     if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == NULL
1018          || !proto_is_protocol_enabled(sub_proto->proto)) {
1019         /*
1020          * We don't have a dissector for this UUID, or the protocol
1021          * for that UUID is disabled.
1022          */
1023         length = tvb_length_remaining (tvb, offset);
1024         if (length > 0) {
1025             proto_tree_add_text (dcerpc_tree, tvb, offset, length,
1026                                  "Stub data (%d byte%s)", length,
1027                                  plurality(length, "", "s"));
1028         }
1029         return -1;
1030     }
1031
1032     for (proc = sub_proto->procs; proc->name; proc++) {
1033         if (proc->num == opnum) {
1034             name = proc->name;
1035             break;
1036         }
1037     }
1038
1039     if (!name)
1040         name = "Unknown?!";
1041
1042     if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
1043         col_set_str (pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
1044     }
1045
1046     if (check_col (pinfo->cinfo, COL_INFO)) {
1047         col_add_fstr (pinfo->cinfo, COL_INFO, "%s %s",
1048                       name, is_rqst ? "request" : "reply");
1049     }
1050
1051     if (tree) {
1052         proto_item *sub_item;
1053         sub_item = proto_tree_add_item (tree, sub_proto->proto, tvb, offset, 
1054                                         -1, FALSE);
1055
1056         if (sub_item) {
1057             sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
1058         }
1059         
1060         /*
1061          * Put the operation number into the tree along with
1062          * the operation's name.
1063          *
1064          * XXX - the subdissectors should all have their own fields
1065          * for the opnum, so that you can filter on a particular
1066          * protocol and opnum value; the opnum value isn't, by itself,
1067          * very interesting, as its interpretation depends on the
1068          * subprotocol.
1069          *
1070          * That would also allow the field to have a value_string
1071          * table, giving names for operations, and letting you filter
1072          * by name.
1073          *
1074          * ONC RPC should do the same thing with the version and
1075          * procedure fields it puts into the subprotocol's tree.
1076          */
1077         proto_tree_add_uint_format (sub_tree, hf_dcerpc_op, tvb,
1078                                     0, 0, opnum,
1079                                     "Operation: %s (%u)",
1080                                     name, opnum);
1081     }
1082
1083     /* 
1084      * If the authentication level is DCE_C_AUTHN_LEVEL_PKT_PRIVACY,
1085      * the stub data is encrypted, and we can't dissect it.
1086      */
1087     if (auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
1088         length = tvb_length_remaining (tvb, offset);
1089         if (length > 0) {
1090             proto_tree_add_text(sub_tree, tvb, offset, length,
1091                                 "Encrypted stub data (%d byte%s)",
1092                                 length, plurality(length, "", "s"));
1093         }
1094     } else {
1095         sub_dissect = is_rqst ? proc->dissect_rqst : proc->dissect_resp;
1096         if (sub_dissect) {
1097             saved_proto = pinfo->current_proto;
1098             saved_private_data = pinfo->private_data;
1099             pinfo->current_proto = sub_proto->name;
1100             pinfo->private_data = (void *)info;
1101
1102             init_ndr_pointer_list(pinfo);
1103             offset = sub_dissect (tvb, offset, pinfo, sub_tree, drep);
1104
1105             pinfo->current_proto = saved_proto;
1106             pinfo->private_data = saved_private_data;
1107         } else {
1108             length = tvb_length_remaining (tvb, offset);
1109             if (length > 0) {
1110                 proto_tree_add_text (sub_tree, tvb, offset, length,
1111                                      "Stub data (%d byte%s)", length,
1112                                      plurality(length, "", "s"));
1113             }
1114         }
1115     }
1116     return 0;
1117 }
1118
1119 static int
1120 dissect_dcerpc_cn_auth (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1121                         e_dce_cn_common_hdr_t *hdr, int *auth_level_p)
1122 {
1123     int offset;
1124     guint8 auth_pad_len;
1125     guint8 auth_level;
1126
1127     /*
1128      * Initially set "*auth_level_p" to -1 to indicate that we haven't
1129      * yet seen any authentication level information.
1130      */
1131     if (auth_level_p != NULL)
1132         *auth_level_p = -1;
1133
1134     /*
1135      * The authentication information is at the *end* of the PDU; in
1136      * request and response PDUs, the request and response stub data
1137      * come before it.
1138      *
1139      * If the full packet is here, and we've got an auth len, and it's
1140      * valid, then dissect the auth info.
1141      */
1142     if (tvb_length (tvb) >= hdr->frag_len
1143         && hdr->auth_len
1144         && (hdr->auth_len + 8 <= hdr->frag_len)) {
1145
1146         offset = hdr->frag_len - (hdr->auth_len + 8);
1147         
1148         offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1149                                        hf_dcerpc_auth_type, NULL);
1150         offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1151                                        hf_dcerpc_auth_level, &auth_level);
1152         if (auth_level_p != NULL)
1153             *auth_level_p = auth_level;
1154         offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1155                                        hf_dcerpc_auth_pad_len, &auth_pad_len);
1156         offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1157                                        hf_dcerpc_auth_rsrvd, NULL);
1158         offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1159                                         hf_dcerpc_auth_ctx_id, NULL);
1160
1161         proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len, "Auth Data");
1162
1163         /* figure out where the auth padding starts */
1164         offset = hdr->frag_len - (hdr->auth_len + 8 + auth_pad_len);
1165         if (offset > 0 && auth_pad_len) {
1166             proto_tree_add_text (dcerpc_tree, tvb, offset, 
1167                                  auth_pad_len, "Auth padding");
1168             return hdr->auth_len + 8 + auth_pad_len;
1169         } else {
1170             return hdr->auth_len + 8;
1171         }
1172     } else {
1173         return 0;
1174     }
1175 }
1176
1177
1178 /* We need to hash in the SMB fid number to generate a unique hash table
1179    key as DCERPC over SMB allows several pipes over the same TCP/IP
1180    socket. */
1181
1182 static guint16 get_smb_fid (void *private_data)
1183 {
1184     dcerpc_private_info *priv = (dcerpc_private_info *)private_data;
1185         
1186     if (!priv)
1187         return 0;       /* Nothing to see here */
1188
1189     /* DCERPC over smb */
1190
1191     if (priv->transport_type == DCERPC_TRANSPORT_SMB)
1192         return priv->data.smb.fid;
1193
1194     /* Some other transport... */
1195
1196     return 0;
1197 }
1198
1199 /*
1200  * Connection oriented packet types
1201  */
1202
1203 static void
1204 dissect_dcerpc_cn_bind (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1205                         e_dce_cn_common_hdr_t *hdr)
1206 {
1207     conversation_t *conv = NULL;
1208     guint8 num_ctx_items;
1209     guint i;
1210     gboolean saw_ctx_item = FALSE;
1211     guint16 ctx_id;
1212     guint16 num_trans_items;
1213     guint j;
1214     e_uuid_t if_id;
1215     e_uuid_t trans_id;
1216     guint32 trans_ver;
1217     guint16 if_ver, if_ver_minor;
1218     int offset = 16;
1219
1220     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1221                                     hf_dcerpc_cn_max_xmit, NULL);
1222
1223     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1224                                     hf_dcerpc_cn_max_recv, NULL);
1225
1226     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1227                                     hf_dcerpc_cn_assoc_group, NULL);
1228
1229     offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1230                                     hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
1231
1232     /* padding */
1233     offset += 3;
1234
1235     for (i = 0; i < num_ctx_items; i++) {
1236       offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1237                                       hf_dcerpc_cn_ctx_id, &ctx_id);
1238
1239       offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1240                                       hf_dcerpc_cn_num_trans_items, &num_trans_items);
1241
1242       dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
1243       if (dcerpc_tree) {
1244           proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_if_id, tvb,
1245                                         offset, 16, "HMMM",
1246                                         "Interface UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1247                                         if_id.Data1, if_id.Data2, if_id.Data3,
1248                                         if_id.Data4[0], if_id.Data4[1],
1249                                         if_id.Data4[2], if_id.Data4[3],
1250                                         if_id.Data4[4], if_id.Data4[5],
1251                                         if_id.Data4[6], if_id.Data4[7]);
1252       }
1253       offset += 16;
1254
1255       if (hdr->drep[0] & 0x10) {
1256           offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1257                                           hf_dcerpc_cn_bind_if_ver, &if_ver);
1258           offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1259                                           hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
1260       } else {
1261           offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1262                                           hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
1263           offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1264                                           hf_dcerpc_cn_bind_if_ver, &if_ver);
1265       }
1266
1267       if (!saw_ctx_item) {
1268         conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
1269                                   pinfo->srcport, pinfo->destport, 0);
1270         if (conv == NULL) {
1271             conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
1272                                      pinfo->srcport, pinfo->destport, 0);
1273         }
1274
1275         /* if this is the first time we see this packet, we need to
1276            update the dcerpc_binds table so that any later calls can
1277            match to the interface.
1278            XXX We assume that BINDs will NEVER be fragmented.
1279         */
1280         if(!(pinfo->fd->flags.visited)){
1281                 dcerpc_bind_key *key;
1282                 dcerpc_bind_value *value;
1283
1284                 key = g_mem_chunk_alloc (dcerpc_bind_key_chunk);
1285                 key->conv = conv;
1286                 key->ctx_id = ctx_id;
1287                 key->smb_fid = get_smb_fid(pinfo->private_data);
1288
1289                 value = g_mem_chunk_alloc (dcerpc_bind_value_chunk);
1290                 value->uuid = if_id;
1291                 value->ver = if_ver;
1292
1293                 /* add this entry to the bind table, first removing any
1294                    previous ones that are identical
1295                  */
1296                 if(g_hash_table_lookup(dcerpc_binds, key)){
1297                         g_hash_table_remove(dcerpc_binds, key);
1298                 }
1299                 g_hash_table_insert (dcerpc_binds, key, value);
1300         }
1301
1302         if (check_col (pinfo->cinfo, COL_INFO)) {
1303           col_add_fstr (pinfo->cinfo, COL_INFO, "%s: UUID %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %d.%d",
1304                         hdr->ptype == PDU_BIND ? "Bind" : "Alter Ctx",
1305                         if_id.Data1, if_id.Data2, if_id.Data3,
1306                         if_id.Data4[0], if_id.Data4[1],
1307                         if_id.Data4[2], if_id.Data4[3],
1308                         if_id.Data4[4], if_id.Data4[5],
1309                         if_id.Data4[6], if_id.Data4[7],
1310                         if_ver, if_ver_minor);
1311         }
1312         saw_ctx_item = TRUE;
1313       }
1314
1315       for (j = 0; j < num_trans_items; j++) {
1316         dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
1317         if (dcerpc_tree) {
1318             proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_trans_id, tvb,
1319                                           offset, 16, "HMMM",
1320                                           "Transfer Syntax: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1321                                           trans_id.Data1, trans_id.Data2, trans_id.Data3,
1322                                           trans_id.Data4[0], trans_id.Data4[1],
1323                                           trans_id.Data4[2], trans_id.Data4[3],
1324                                           trans_id.Data4[4], trans_id.Data4[5],
1325                                           trans_id.Data4[6], trans_id.Data4[7]);
1326         }
1327         offset += 16;
1328
1329         offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1330                                         hf_dcerpc_cn_bind_trans_ver, &trans_ver);
1331       }
1332     }
1333
1334     /*
1335      * XXX - we should save the authentication type *if* we have
1336      * an authentication header, and associate it with an authentication
1337      * context, so subsequent PDUs can use that context.
1338      */
1339     dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, NULL);
1340 }
1341
1342 static void
1343 dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1344                             e_dce_cn_common_hdr_t *hdr)
1345 {
1346     guint16 max_xmit, max_recv;
1347     guint16 sec_addr_len;
1348     guint8 num_results;
1349     guint i;
1350     guint16 result;
1351     guint16 reason;
1352     e_uuid_t trans_id;
1353     guint32 trans_ver;
1354
1355     int offset = 16;
1356
1357     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1358                                     hf_dcerpc_cn_max_xmit, &max_xmit);
1359
1360     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1361                                     hf_dcerpc_cn_max_recv, &max_recv);
1362
1363     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1364                                     hf_dcerpc_cn_assoc_group, NULL);
1365
1366     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1367                                     hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
1368     if (sec_addr_len != 0) {
1369         proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
1370                              sec_addr_len, FALSE);
1371         offset += sec_addr_len;
1372     }
1373
1374     if (offset % 4) {
1375         offset += 4 - offset % 4;
1376     }
1377
1378     offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1379                                    hf_dcerpc_cn_num_results, &num_results);
1380
1381     /* padding */
1382     offset += 3;
1383
1384     for (i = 0; i < num_results; i++) {
1385         offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, 
1386                                         hdr->drep, hf_dcerpc_cn_ack_result,
1387                                         &result);
1388         offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, 
1389                                         hdr->drep, hf_dcerpc_cn_ack_reason,
1390                                         &reason);
1391
1392         dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
1393         if (dcerpc_tree) {
1394             proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_ack_trans_id, tvb,
1395                                           offset, 16, "HMMM",
1396                                           "Transfer Syntax: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1397                                           trans_id.Data1, trans_id.Data2, trans_id.Data3,
1398                                           trans_id.Data4[0], trans_id.Data4[1],
1399                                           trans_id.Data4[2], trans_id.Data4[3],
1400                                           trans_id.Data4[4], trans_id.Data4[5],
1401                                           trans_id.Data4[6], trans_id.Data4[7]);
1402         }
1403         offset += 16;
1404
1405         offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1406                                         hf_dcerpc_cn_ack_trans_ver, &trans_ver);
1407     }
1408     
1409     /*
1410      * XXX - do we need to do anything with the authentication level
1411      * we get back from this?
1412      */
1413     dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, NULL);
1414
1415     if (check_col (pinfo->cinfo, COL_INFO)) {
1416         if (num_results != 0 && result == 0) {
1417             col_add_fstr (pinfo->cinfo, COL_INFO, "%s ack: accept  max_xmit: %d  max_recv: %d",
1418                           hdr->ptype == PDU_BIND_ACK ? "Bind" : "Alter ctx",
1419                           max_xmit, max_recv);
1420         } else {
1421             /* FIXME: should put in reason */
1422             col_add_fstr (pinfo->cinfo, COL_INFO, "%s ack: %s",
1423                           hdr->ptype == PDU_BIND_ACK ? "Bind" : "Alter ctx",
1424                           result == 1 ? "User reject" :
1425                           result == 2 ? "Provider reject" :
1426                           "Unknown");
1427         }
1428     }
1429 }
1430
1431 static void
1432 dissect_dcerpc_cn_rqst (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1433                         proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
1434 {
1435     conversation_t *conv;
1436     guint16 ctx_id;
1437     guint16 opnum;
1438     e_uuid_t obj_id;
1439     int auth_sz = 0;
1440     int auth_level;
1441     int offset = 16;
1442     guint32 alloc_hint;
1443
1444     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1445                                     hf_dcerpc_cn_alloc_hint, &alloc_hint);
1446
1447     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1448                                     hf_dcerpc_cn_ctx_id, &ctx_id);
1449
1450     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1451                                     hf_dcerpc_opnum, &opnum);
1452
1453     if (check_col (pinfo->cinfo, COL_INFO)) {
1454         col_add_fstr (pinfo->cinfo, COL_INFO, "Request: opnum: %d  ctx_id:%d",
1455                          opnum, ctx_id);
1456     }
1457
1458     if (hdr->flags & 0x80) {
1459         dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id);
1460         if (dcerpc_tree) {
1461             proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
1462                                           offset, 16, "HMMM",
1463                                           "Object UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1464                                           obj_id.Data1, obj_id.Data2, obj_id.Data3,
1465                                           obj_id.Data4[0],
1466                                           obj_id.Data4[1],
1467                                           obj_id.Data4[2],
1468                                           obj_id.Data4[3],
1469                                           obj_id.Data4[4],
1470                                           obj_id.Data4[5],
1471                                           obj_id.Data4[6],
1472                                           obj_id.Data4[7]);
1473         }
1474         offset += 16;
1475     }
1476
1477     /*
1478      * XXX - what if this was set when the connection was set up,
1479      * and we just have a security context?
1480      */
1481     auth_sz = dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr,
1482                                       &auth_level);
1483
1484     conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
1485                               pinfo->srcport, pinfo->destport, 0);
1486     if (!conv) {
1487
1488     } else {
1489         dcerpc_call_value *value;
1490         int length, reported_length, stub_length;
1491         dcerpc_info di;
1492
1493         /* !!! we can NOT check flags.visited here since this will interact
1494            badly with when SMB handles (i.e. calls the subdissector)
1495            and desegmented pdu's .
1496            Instead we check if this pdu is already in the matched table or not
1497         */
1498         if(!g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num)){
1499                 dcerpc_bind_key bind_key;
1500                 dcerpc_bind_value *bind_value;
1501
1502                 bind_key.conv=conv;
1503                 bind_key.ctx_id=ctx_id;
1504                 bind_key.smb_fid=get_smb_fid(pinfo->private_data);
1505
1506                 if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key))){
1507                         dcerpc_call_key *call_key;
1508                         dcerpc_call_value *call_value;
1509
1510                         /* We found the binding so just add the call
1511                            to both the call table and the matched table
1512                         */
1513                         call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
1514                         call_key->conv=conv;
1515                         call_key->call_id=hdr->call_id;
1516                         call_key->smb_fid=get_smb_fid(pinfo->private_data);
1517
1518                         /* if there is already a matching call in the table
1519                            remove it so it is replaced with the new one */
1520                         if(g_hash_table_lookup(dcerpc_calls, call_key)){
1521                                 g_hash_table_remove(dcerpc_calls, call_key);
1522                         }
1523
1524                         call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
1525                         call_value->uuid = bind_value->uuid;
1526                         call_value->ver = bind_value->ver;
1527                         call_value->opnum = opnum;
1528                         call_value->req_frame=pinfo->fd->num;
1529                         call_value->rep_frame=0;
1530                         call_value->max_ptr=0;
1531                         call_value->private_data = NULL;
1532                         g_hash_table_insert (dcerpc_calls, call_key, call_value);
1533
1534                         g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);       
1535                 }
1536         }
1537
1538         value=g_hash_table_lookup (dcerpc_matched, (void *)pinfo->fd->num);
1539
1540
1541         if (value) {
1542
1543             /* handoff this call */
1544             length = tvb_length_remaining(tvb, offset);
1545             reported_length = tvb_reported_length_remaining(tvb, offset);
1546             stub_length = hdr->frag_len - offset - auth_sz;
1547             if (length > stub_length)
1548               length = stub_length;
1549             if (reported_length > stub_length)
1550               reported_length = stub_length;
1551             di.conv = conv;
1552             di.call_id = hdr->call_id;
1553             di.smb_fid = get_smb_fid(pinfo->private_data);
1554             di.request = TRUE;
1555             di.call_data = value;
1556
1557             if(value->rep_frame!=0){
1558                 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in, 
1559                                     tvb, 0, 0, value->rep_frame);
1560             }
1561
1562             /* If we dont have reassembly enabled, or this packet contains the
1563                entire PDU, just call the handoff directly */
1564             if( (!dcerpc_reassemble)
1565               || ((hdr->flags&0x03)==0x03) ){
1566                 if(hdr->flags&0x01){
1567                     dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
1568                                 tvb_new_subset (tvb, offset, length,
1569                                                 reported_length),
1570                                 0, opnum, TRUE, hdr->drep, &di, auth_level);
1571                 } else {
1572                     if (check_col(pinfo->cinfo, COL_INFO)) {
1573                         col_add_fstr(pinfo->cinfo, COL_INFO, "[DCE/RPC fragment]");
1574                     }
1575                 }
1576             } else if(dcerpc_reassemble){
1577                 /*OK we need to do reassembly */
1578                 /* handle first fragment */
1579                 if((hdr->flags&0x03)==0x01){  /* FIRST fragment */
1580                     if( (!pinfo->fd->flags.visited) && value->req_frame ){
1581                         fragment_add(tvb, offset, pinfo, value->req_frame,
1582                              dcerpc_reassemble_table,
1583                              0,
1584                              length,
1585                              TRUE);
1586                         fragment_set_tot_len(pinfo, value->req_frame,
1587                              dcerpc_reassemble_table, alloc_hint);
1588                     }
1589                     if (check_col(pinfo->cinfo, COL_INFO)) {
1590                         col_add_fstr(pinfo->cinfo, COL_INFO, "[DCE/RPC fragment]");
1591                     }
1592                 }
1593                 if((hdr->flags&0x03)==0x00){  /* MIDDLE fragment(s) */
1594                     if( (!pinfo->fd->flags.visited) && value->req_frame ){
1595                         guint32 tot_len;
1596                         tot_len = fragment_get_tot_len(pinfo, value->req_frame,
1597                                        dcerpc_reassemble_table);
1598                         fragment_add(tvb, offset, pinfo, value->req_frame,
1599                              dcerpc_reassemble_table,
1600                              tot_len-alloc_hint,
1601                              length,
1602                              TRUE);
1603                     }
1604                     if (check_col(pinfo->cinfo, COL_INFO)) {
1605                         col_add_fstr(pinfo->cinfo, COL_INFO, "[DCE/RPC fragment]");
1606                     }
1607                 }
1608                 if((hdr->flags&0x03)==0x02){  /* LAST fragment */
1609                     if( value->req_frame ){
1610                         fragment_data *ipfd_head;
1611                         guint32 tot_len;
1612                         tot_len = fragment_get_tot_len(pinfo, value->req_frame,
1613                                        dcerpc_reassemble_table);
1614                         ipfd_head = fragment_add(tvb, offset, pinfo, 
1615                              value->req_frame,
1616                              dcerpc_reassemble_table,
1617                              tot_len-alloc_hint,
1618                              length,
1619                              TRUE);
1620
1621                         if(ipfd_head){
1622                             fragment_data *ipfd;
1623                             proto_tree *ft=NULL;
1624                             proto_item *fi=NULL;
1625                             tvbuff_t *next_tvb;
1626
1627                             next_tvb = tvb_new_real_data(ipfd_head->data, ipfd_head->datalen, ipfd_head->datalen);
1628                             tvb_set_child_real_data_tvbuff(tvb, next_tvb);
1629                             add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
1630                             pinfo->fragmented=FALSE;
1631                             fi = proto_tree_add_item(dcerpc_tree, hf_dcerpc_fragments, next_tvb, 0, -1, FALSE);
1632                             ft = proto_item_add_subtree(fi, ett_dcerpc_fragments);
1633                             for (ipfd=ipfd_head->next; ipfd; ipfd=ipfd->next){
1634                                 if (ipfd->flags & (FD_OVERLAP|FD_OVERLAPCONFLICT|FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
1635                                     proto_tree *fet=NULL;
1636                                     proto_item *fei=NULL;
1637                                     int hf;
1638
1639                                     if (ipfd->flags & (FD_OVERLAPCONFLICT|FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
1640                                         hf = hf_dcerpc_fragment_error;
1641                                     } else {
1642                                         hf = hf_dcerpc_fragment;
1643                                     }
1644                                     fei = proto_tree_add_none_format(ft, hf, 
1645                                         next_tvb, ipfd->offset, ipfd->len,
1646                                         "Frame:%u payload:%u-%u",
1647                                         ipfd->frame,
1648                                         ipfd->offset,
1649                                         ipfd->offset+ipfd->len-1);
1650                                     fet = proto_item_add_subtree(fei, ett_dcerpc_fragment);
1651                                     if (ipfd->flags&FD_OVERLAP) {
1652                                         proto_tree_add_boolean(fet, hf_dcerpc_fragment_overlap, next_tvb, 0, 0, TRUE);
1653                                     }
1654                                     if (ipfd->flags&FD_OVERLAPCONFLICT) {
1655                                         proto_tree_add_boolean(fet, hf_dcerpc_fragment_overlap_conflict, next_tvb, 0, 0, TRUE);
1656                                     }
1657                                     if (ipfd->flags&FD_MULTIPLETAILS) {
1658                                         proto_tree_add_boolean(fet, hf_dcerpc_fragment_multiple_tails, next_tvb, 0, 0, TRUE);
1659                                     }
1660                                     if (ipfd->flags&FD_TOOLONGFRAGMENT) {
1661                                         proto_tree_add_boolean(fet, hf_dcerpc_fragment_too_long_fragment, next_tvb, 0, 0, TRUE);
1662                                     }
1663                                 } else {
1664                                     proto_tree_add_none_format(ft, hf_dcerpc_fragment, 
1665                                            next_tvb, ipfd->offset, ipfd->len,
1666                                            "Frame:%u payload:%u-%u",
1667                                            ipfd->frame,
1668                                            ipfd->offset,
1669                                            ipfd->offset+ipfd->len-1
1670                                     );
1671                                 }
1672                             }
1673                             if (ipfd_head->flags & (FD_OVERLAPCONFLICT|FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
1674                                 if (check_col(pinfo->cinfo, COL_INFO)) {
1675                                         col_set_str(pinfo->cinfo, COL_INFO, "[Illegal fragments]");
1676                                 }
1677                             }
1678                             dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
1679                                 next_tvb,
1680                                 0, opnum, TRUE, hdr->drep, &di,
1681                                 auth_level);
1682                         } else {
1683                             if (check_col(pinfo->cinfo, COL_INFO)) {
1684                                 col_add_fstr(pinfo->cinfo, COL_INFO, "[DCE/RPC fragment]");
1685                             }
1686                         }
1687
1688                     }
1689                 }
1690             }
1691         }
1692     }
1693 }
1694
1695 static void
1696 dissect_dcerpc_cn_resp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1697                         proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
1698 {
1699     dcerpc_call_value *value = NULL;
1700     conversation_t *conv;
1701     guint16 ctx_id;
1702     int auth_sz = 0;
1703     int offset = 16;
1704     int auth_level;
1705     guint32 alloc_hint;
1706
1707     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1708                                     hf_dcerpc_cn_alloc_hint, &alloc_hint);
1709
1710     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1711                                     hf_dcerpc_cn_ctx_id, &ctx_id);
1712
1713     if (check_col (pinfo->cinfo, COL_INFO)) {
1714         col_add_fstr (pinfo->cinfo, COL_INFO, "Response: call_id: %d  ctx_id:%d",
1715                       hdr->call_id, ctx_id);
1716     }
1717
1718     offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1719                                    hf_dcerpc_cn_cancel_count, NULL);
1720     /* padding */
1721     offset++;
1722
1723     /*
1724      * XXX - what if this was set when the connection was set up,
1725      * and we just have a security context?
1726      */
1727     auth_sz = dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr,
1728                                       &auth_level);
1729
1730     conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
1731                               pinfo->srcport, pinfo->destport, 0);
1732     if (!conv) {
1733         /* no point in creating one here, really */
1734     } else {
1735
1736         /* !!! we can NOT check flags.visited here since this will interact
1737            badly with when SMB handles (i.e. calls the subdissector)
1738            and desegmented pdu's .
1739            Instead we check if this pdu is already in the matched table or not
1740         */
1741         if(!g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num)){
1742                 dcerpc_call_key call_key;
1743                 dcerpc_call_value *call_value;
1744
1745                 call_key.conv=conv;
1746                 call_key.call_id=hdr->call_id;
1747                 call_key.smb_fid=get_smb_fid(pinfo->private_data);
1748
1749                 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
1750                         g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
1751                         if(call_value->rep_frame==0){
1752                                 call_value->rep_frame=pinfo->fd->num;
1753                         }
1754
1755                 }
1756         }
1757
1758         value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
1759
1760         if (value) {
1761             int length, reported_length, stub_length;
1762             dcerpc_info di;
1763
1764             /* handoff this call */
1765             length = tvb_length_remaining(tvb, offset);
1766             reported_length = tvb_reported_length_remaining(tvb, offset);
1767             stub_length = hdr->frag_len - offset - auth_sz;
1768             if (length > stub_length)
1769               length = stub_length;
1770             if (reported_length > stub_length)
1771               reported_length = stub_length;
1772             di.conv = conv;
1773             di.call_id = hdr->call_id;
1774             di.smb_fid = get_smb_fid(pinfo->private_data);
1775             di.request = FALSE;
1776             di.call_data = value;
1777
1778             proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
1779             if(value->req_frame!=0){
1780                 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in, 
1781                                     tvb, 0, 0, value->req_frame);
1782             }
1783
1784             /* If we dont have reassembly enabled, or this packet contains the
1785                entire PDU, just call the handoff directly */
1786             if( (!dcerpc_reassemble)
1787               || ((hdr->flags&0x03)==0x03) ){
1788                 if(hdr->flags&0x01){
1789                     dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
1790                                 tvb_new_subset (tvb, offset, length,
1791                                                 reported_length),
1792                                 0, value->opnum, FALSE, hdr->drep, &di,
1793                                 auth_level);
1794                 } else {
1795                     if (check_col(pinfo->cinfo, COL_INFO)) {
1796                         col_add_fstr(pinfo->cinfo, COL_INFO, "[DCE/RPC fragment]");
1797                     }
1798                 }
1799             } else if(dcerpc_reassemble){
1800                 /*OK we need to do reassembly */
1801                 /* handle first fragment */
1802                 if((hdr->flags&0x03)==0x01){  /* FIRST fragment */
1803                     if( (!pinfo->fd->flags.visited) && value->rep_frame ){
1804                         fragment_add(tvb, offset, pinfo, value->rep_frame,
1805                              dcerpc_reassemble_table,
1806                              0,
1807                              length,
1808                              TRUE);
1809                         fragment_set_tot_len(pinfo, value->rep_frame,
1810                              dcerpc_reassemble_table, alloc_hint);
1811                     }
1812                     if (check_col(pinfo->cinfo, COL_INFO)) {
1813                         col_add_fstr(pinfo->cinfo, COL_INFO, "[DCE/RPC fragment]");
1814                     }
1815                 }
1816                 if((hdr->flags&0x03)==0x00){  /* MIDDLE fragment(s) */
1817                     if( (!pinfo->fd->flags.visited) && value->rep_frame ){
1818                         guint32 tot_len;
1819                         tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
1820                                        dcerpc_reassemble_table);
1821                         fragment_add(tvb, offset, pinfo, value->rep_frame,
1822                              dcerpc_reassemble_table,
1823                              tot_len-alloc_hint,
1824                              length,
1825                              TRUE);
1826                     }
1827                     if (check_col(pinfo->cinfo, COL_INFO)) {
1828                         col_add_fstr(pinfo->cinfo, COL_INFO, "[DCE/RPC fragment]");
1829                     }
1830                 }
1831                 if((hdr->flags&0x03)==0x02){  /* LAST fragment */
1832                     if( value->rep_frame ){
1833                         fragment_data *ipfd_head;
1834                         guint32 tot_len;
1835                         tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
1836                                        dcerpc_reassemble_table);
1837                         ipfd_head = fragment_add(tvb, offset, pinfo, 
1838                              value->rep_frame,
1839                              dcerpc_reassemble_table,
1840                              tot_len-alloc_hint,
1841                              length,
1842                              TRUE);
1843
1844                         if(ipfd_head){
1845                             fragment_data *ipfd;
1846                             proto_tree *ft=NULL;
1847                             proto_item *fi=NULL;
1848                             tvbuff_t *next_tvb;
1849
1850                             next_tvb = tvb_new_real_data(ipfd_head->data, ipfd_head->datalen, ipfd_head->datalen);
1851                             tvb_set_child_real_data_tvbuff(tvb, next_tvb);
1852                             add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
1853                             pinfo->fragmented=FALSE;
1854                             fi = proto_tree_add_item(dcerpc_tree, hf_dcerpc_fragments, next_tvb, 0, -1, FALSE);
1855                             ft = proto_item_add_subtree(fi, ett_dcerpc_fragments);
1856                             for (ipfd=ipfd_head->next; ipfd; ipfd=ipfd->next){
1857                                 if (ipfd->flags & (FD_OVERLAP|FD_OVERLAPCONFLICT|FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
1858                                     proto_tree *fet=NULL;
1859                                     proto_item *fei=NULL;
1860                                     int hf;
1861
1862                                     if (ipfd->flags & (FD_OVERLAPCONFLICT|FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
1863                                         hf = hf_dcerpc_fragment_error;
1864                                     } else {
1865                                         hf = hf_dcerpc_fragment;
1866                                     }
1867                                     fei = proto_tree_add_none_format(ft, hf, 
1868                                         next_tvb, ipfd->offset, ipfd->len,
1869                                         "Frame:%u payload:%u-%u",
1870                                         ipfd->frame,
1871                                         ipfd->offset,
1872                                         ipfd->offset+ipfd->len-1);
1873                                     fet = proto_item_add_subtree(fei, ett_dcerpc_fragment);
1874                                     if (ipfd->flags&FD_OVERLAP) {
1875                                         proto_tree_add_boolean(fet, hf_dcerpc_fragment_overlap, next_tvb, 0, 0, TRUE);
1876                                     }
1877                                     if (ipfd->flags&FD_OVERLAPCONFLICT) {
1878                                         proto_tree_add_boolean(fet, hf_dcerpc_fragment_overlap_conflict, next_tvb, 0, 0, TRUE);
1879                                     }
1880                                     if (ipfd->flags&FD_MULTIPLETAILS) {
1881                                         proto_tree_add_boolean(fet, hf_dcerpc_fragment_multiple_tails, next_tvb, 0, 0, TRUE);
1882                                     }
1883                                     if (ipfd->flags&FD_TOOLONGFRAGMENT) {
1884                                         proto_tree_add_boolean(fet, hf_dcerpc_fragment_too_long_fragment, next_tvb, 0, 0, TRUE);
1885                                     }
1886                                 } else {
1887                                     proto_tree_add_none_format(ft, hf_dcerpc_fragment, 
1888                                            next_tvb, ipfd->offset, ipfd->len,
1889                                            "Frame:%u payload:%u-%u",
1890                                            ipfd->frame,
1891                                            ipfd->offset,
1892                                            ipfd->offset+ipfd->len-1
1893                                     );
1894                                 }
1895                             }
1896                             if (ipfd_head->flags & (FD_OVERLAPCONFLICT|FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
1897                                 if (check_col(pinfo->cinfo, COL_INFO)) {
1898                                         col_set_str(pinfo->cinfo, COL_INFO, "[Illegal fragments]");
1899                                 }
1900                             }
1901                             dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
1902                                 next_tvb,
1903                                 0, value->opnum, FALSE, hdr->drep, &di,
1904                                 auth_level);
1905                         } else {
1906                             if (check_col(pinfo->cinfo, COL_INFO)) {
1907                                 col_add_fstr(pinfo->cinfo, COL_INFO, "[DCE/RPC fragment]");
1908                             }
1909                         }
1910                     }
1911                 }
1912             }
1913
1914         }
1915     }
1916 }
1917
1918 /*
1919  * DCERPC dissector for connection oriented calls
1920  */
1921 static int
1922 dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
1923                    proto_tree *tree, gboolean can_desegment)
1924 {
1925     static char nulls[4] = { 0 };
1926     int start_offset;
1927     int padding = 0;
1928     proto_item *ti = NULL;
1929     proto_item *tf = NULL;
1930     proto_tree *dcerpc_tree = NULL;
1931     proto_tree *cn_flags_tree = NULL;
1932     proto_tree *drep_tree = NULL;
1933     e_dce_cn_common_hdr_t hdr;
1934
1935     /*
1936      * when done over nbt, dcerpc requests are padded with 4 bytes of null
1937      * data for some reason.
1938      *
1939      * XXX - if that's always the case, the right way to do this would
1940      * be to have a "dissect_dcerpc_cn_nb" routine which strips off
1941      * the 4 bytes of null padding, and make that the dissector
1942      * used for "netbios".
1943      */
1944     if (tvb_bytes_exist (tvb, offset, 4) &&
1945         tvb_memeql (tvb, offset, nulls, 4) == 0) {
1946
1947         /*
1948          * Skip the padding.
1949          */
1950         offset += 4;
1951         padding += 4;
1952     }
1953
1954     /*
1955      * Check if this looks like a C/O DCERPC call
1956      */
1957     if (!tvb_bytes_exist (tvb, offset, sizeof (hdr))) {
1958         return -1;
1959     }
1960     start_offset = offset;
1961     hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
1962     if (hdr.rpc_ver != 5)
1963         return -1;
1964     hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
1965     if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
1966         return -1;
1967     hdr.ptype = tvb_get_guint8 (tvb, offset++);
1968     if (hdr.ptype > 19)
1969         return -1;
1970
1971     if (check_col (pinfo->cinfo, COL_PROTOCOL))
1972         col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
1973     if (check_col (pinfo->cinfo, COL_INFO))
1974         col_set_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
1975
1976     hdr.flags = tvb_get_guint8 (tvb, offset++);
1977     tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
1978     offset += sizeof (hdr.drep);
1979
1980     hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1981     offset += 2;
1982     hdr.auth_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1983     offset += 2;
1984     hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
1985     offset += 4;
1986
1987     offset = start_offset;
1988     if (can_desegment && pinfo->can_desegment
1989         && hdr.frag_len > tvb_length_remaining (tvb, offset)) {
1990         pinfo->desegment_offset = offset;
1991         pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, offset);
1992         return 0;       /* desegmentation required */
1993     }
1994
1995     if (tree) {
1996         ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE);
1997         if (ti) {
1998             dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
1999         }
2000         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver);
2001         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset++, 1, hdr.rpc_ver_minor);
2002         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype);
2003         tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
2004         cn_flags_tree = proto_item_add_subtree (tf, ett_dcerpc_cn_flags);
2005         if (cn_flags_tree) {
2006             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
2007             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
2008             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
2009             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
2010             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
2011             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
2012             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
2013             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
2014         }
2015         offset++;
2016
2017         tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
2018         drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
2019         if (drep_tree) {
2020             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
2021             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
2022             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
2023         }
2024         offset += sizeof (hdr.drep);
2025
2026         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
2027         offset += 2;
2028
2029         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
2030         offset += 2;
2031
2032         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
2033         offset += 4;
2034     }
2035
2036
2037     /*
2038      * Packet type specific stuff is next.
2039      */
2040     switch (hdr.ptype) {
2041     case PDU_BIND:
2042     case PDU_ALTER:
2043         dissect_dcerpc_cn_bind (tvb, pinfo, dcerpc_tree, &hdr);
2044         break;
2045
2046     case PDU_BIND_ACK:
2047     case PDU_ALTER_ACK:
2048         dissect_dcerpc_cn_bind_ack (tvb, pinfo, dcerpc_tree, &hdr);
2049         break;
2050
2051     case PDU_REQ:
2052         dissect_dcerpc_cn_rqst (tvb, pinfo, dcerpc_tree, tree, &hdr);
2053         break;
2054
2055     case PDU_RESP:
2056         dissect_dcerpc_cn_resp (tvb, pinfo, dcerpc_tree, tree, &hdr);
2057         break;
2058
2059     default:
2060         /* might as well dissect the auth info */
2061         dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, NULL);
2062         break;
2063     }
2064     return hdr.frag_len + padding;
2065 }
2066
2067 /*
2068  * DCERPC dissector for connection oriented calls over packet-oriented
2069  * transports
2070  */
2071 static gboolean
2072 dissect_dcerpc_cn_pk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2073 {
2074     /*
2075      * Only one PDU per transport packet, and only one transport
2076      * packet per PDU.
2077      */
2078     if (dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE) == -1) {
2079         /*
2080          * It wasn't a DCERPC PDU.
2081          */
2082         return FALSE;
2083     } else {
2084         /*
2085          * It was.
2086          */
2087         return TRUE;
2088     }
2089 }
2090
2091 /*
2092  * DCERPC dissector for connection oriented calls over byte-stream
2093  * transports
2094  */
2095 static gboolean
2096 dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2097 {
2098     int offset = 0;
2099     int pdu_len;
2100     gboolean ret = FALSE;
2101
2102     /*
2103      * There may be multiple PDUs per transport packet; keep
2104      * processing them.
2105      */
2106     while (tvb_reported_length_remaining(tvb, offset) != 0) {
2107         pdu_len = dissect_dcerpc_cn (tvb, offset, pinfo, tree,
2108                                      dcerpc_cn_desegment);
2109         if (pdu_len == -1) {
2110             /*
2111              * Not a DCERPC PDU.
2112              */
2113             break;
2114         }
2115
2116         /*
2117          * Well, we've seen at least one DCERPC PDU.
2118          */
2119         ret = TRUE;
2120
2121         if (pdu_len == 0) {
2122             /*
2123              * Desegmentation required - bail now.
2124              */
2125             break;
2126         }
2127
2128         /*
2129          * Step to the next PDU.
2130          */
2131         offset += pdu_len;
2132     }
2133     return ret;
2134 }
2135
2136 static void
2137 dissect_dcerpc_dg_auth (tvbuff_t *tvb, proto_tree *dcerpc_tree,
2138                         e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
2139 {
2140     int offset;
2141
2142     /*
2143      * Initially set "*auth_level_p" to -1 to indicate that we haven't
2144      * yet seen any authentication level information.
2145      */
2146     if (auth_level_p != NULL)
2147         *auth_level_p = -1;
2148
2149     /*
2150      * The authentication information is at the *end* of the PDU; in
2151      * request and response PDUs, the request and response stub data
2152      * come before it.
2153      *
2154      * If the full packet is here, and there's data past the end of the
2155      * packet body, then dissect the auth info.
2156      */
2157     if (tvb_length (tvb) >= hdr->frag_len) {
2158         offset = hdr->frag_len;
2159         
2160         proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Auth data");
2161     }
2162 }
2163
2164 /*
2165  * DCERPC dissector for connectionless calls
2166  */
2167 static gboolean
2168 dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2169 {
2170     proto_item *ti = NULL;
2171     proto_item *tf = NULL;
2172     proto_tree *dcerpc_tree = NULL;
2173     proto_tree *dg_flags1_tree = NULL;
2174     proto_tree *dg_flags2_tree = NULL;
2175     proto_tree *drep_tree = NULL;
2176     e_dce_dg_common_hdr_t hdr;
2177     int offset = 0;
2178     conversation_t *conv;
2179
2180     /*
2181      * Check if this looks like a CL DCERPC call.  All dg packets
2182      * have an 80 byte header on them.  Which starts with
2183      * version (4), pkt_type.
2184      */
2185     if (!tvb_bytes_exist (tvb, 0, sizeof (hdr))) {
2186         return FALSE;
2187     }
2188     hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
2189     if (hdr.rpc_ver != 4)
2190         return FALSE;
2191     hdr.ptype = tvb_get_guint8 (tvb, offset++);
2192     if (hdr.ptype > 19)
2193         return FALSE;
2194
2195     if (check_col (pinfo->cinfo, COL_PROTOCOL))
2196         col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
2197     if (check_col (pinfo->cinfo, COL_INFO))
2198         col_set_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
2199
2200     hdr.flags1 = tvb_get_guint8 (tvb, offset++);
2201     hdr.flags2 = tvb_get_guint8 (tvb, offset++);
2202     tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
2203     offset += sizeof (hdr.drep);
2204     hdr.serial_hi = tvb_get_guint8 (tvb, offset++);
2205     dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.obj_id);
2206     offset += 16;
2207     dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.if_id);
2208     offset += 16;
2209     dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.act_id);
2210     offset += 16;
2211     hdr.server_boot = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
2212     offset += 4;
2213     hdr.if_ver = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
2214     offset += 4;
2215     hdr.seqnum = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
2216     offset += 4;
2217     hdr.opnum = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
2218     offset += 2;
2219     hdr.ihint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
2220     offset += 2;
2221     hdr.ahint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
2222     offset += 2;
2223     hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
2224     offset += 2;
2225     hdr.frag_num = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
2226     offset += 2;
2227     hdr.auth_proto = tvb_get_guint8 (tvb, offset++);
2228     hdr.serial_lo = tvb_get_guint8 (tvb, offset++);
2229
2230     if (tree) {
2231         ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, -1, FALSE);
2232         if (ti) {
2233             dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
2234         }
2235         offset = 0;
2236         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver);
2237
2238         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype);
2239
2240         tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
2241         dg_flags1_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags1);
2242         if (dg_flags1_tree) {
2243             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
2244             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
2245             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
2246             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
2247             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
2248             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
2249             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
2250             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
2251         }
2252         offset++;
2253
2254         tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
2255         dg_flags2_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags2);
2256         if (dg_flags2_tree) {
2257             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
2258             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
2259             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
2260             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
2261             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
2262             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
2263             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
2264             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
2265         }
2266         offset++;
2267
2268         tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
2269         drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
2270         if (drep_tree) {
2271             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
2272             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
2273             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
2274         }
2275         offset += sizeof (hdr.drep);
2276
2277         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset++, 1, hdr.serial_hi);
2278
2279         proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
2280                                       offset, 16, "HMMM",
2281                                       "Object: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2282                                       hdr.obj_id.Data1, hdr.obj_id.Data2, hdr.obj_id.Data3,
2283                                       hdr.obj_id.Data4[0],
2284                                       hdr.obj_id.Data4[1],
2285                                       hdr.obj_id.Data4[2],
2286                                       hdr.obj_id.Data4[3],
2287                                       hdr.obj_id.Data4[4],
2288                                       hdr.obj_id.Data4[5],
2289                                       hdr.obj_id.Data4[6],
2290                                       hdr.obj_id.Data4[7]);
2291         offset += 16;
2292
2293         proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
2294                                       offset, 16, "HMMM",
2295                                       "Interface: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2296                                       hdr.if_id.Data1, hdr.if_id.Data2, hdr.if_id.Data3,
2297                                       hdr.if_id.Data4[0],
2298                                       hdr.if_id.Data4[1],
2299                                       hdr.if_id.Data4[2],
2300                                       hdr.if_id.Data4[3],
2301                                       hdr.if_id.Data4[4],
2302                                       hdr.if_id.Data4[5],
2303                                       hdr.if_id.Data4[6],
2304                                       hdr.if_id.Data4[7]);
2305         offset += 16;
2306
2307         proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
2308                                       offset, 16, "HMMM",
2309                                       "Activity: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2310                                       hdr.act_id.Data1, hdr.act_id.Data2, hdr.act_id.Data3,
2311                                       hdr.act_id.Data4[0],
2312                                       hdr.act_id.Data4[1],
2313                                       hdr.act_id.Data4[2],
2314                                       hdr.act_id.Data4[3],
2315                                       hdr.act_id.Data4[4],
2316                                       hdr.act_id.Data4[5],
2317                                       hdr.act_id.Data4[6],
2318                                       hdr.act_id.Data4[7]);
2319         offset += 16;
2320
2321         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_server_boot, tvb, offset, 4, hdr.server_boot);
2322         offset += 4;
2323
2324         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
2325         offset += 4;
2326
2327         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
2328         offset += 4;
2329
2330         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
2331         offset += 2;
2332
2333         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
2334         offset += 2;
2335
2336         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
2337         offset += 2;
2338
2339         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
2340         offset += 2;
2341
2342         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
2343         offset += 2;
2344
2345         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
2346         offset++;
2347
2348         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
2349         offset++;
2350
2351         /*
2352          * XXX - for Kerberos, we can get a protection level; if it's
2353          * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
2354          * stub data.
2355          */
2356         dissect_dcerpc_dg_auth (tvb, dcerpc_tree, &hdr, NULL);
2357     }
2358     /* 
2359      * keeping track of the conversation shouldn't really be necessary
2360      * for connectionless packets, because everything we need to know
2361      * to dissect is in the header for each packet.  Unfortunately,
2362      * Microsoft's implementation is buggy and often puts the
2363      * completely wrong if_id in the header.  go figure.  So, keep
2364      * track of the seqnum and use that if possible.  Note: that's not
2365      * completely correct.  It should really be done based on both the
2366      * activity_id and seqnum.  I haven't seen anywhere that it would
2367      * make a difference, but for future reference...
2368      */
2369     conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2370                               pinfo->srcport, pinfo->destport, 0);
2371     if (!conv) {
2372         conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
2373                                  pinfo->srcport, pinfo->destport, 0);
2374     }
2375
2376     /*
2377      * Packet type specific stuff is next.
2378      */
2379
2380     switch (hdr.ptype) {
2381         int length, reported_length, stub_length;
2382         dcerpc_info di;
2383         dcerpc_call_value *value, v;
2384
2385     case PDU_REQ:
2386
2387         if(!(pinfo->fd->flags.visited)){
2388                 dcerpc_call_value *call_value;
2389                 dcerpc_call_key *call_key;
2390
2391                 call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
2392                 call_key->conv=conv;
2393                 call_key->call_id=hdr.seqnum;
2394                 call_key->smb_fid=get_smb_fid(pinfo->private_data);
2395
2396                 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
2397                 call_value->uuid = hdr.if_id;
2398                 call_value->ver = hdr.if_ver;
2399                 call_value->opnum = hdr.opnum;
2400                 call_value->req_frame=pinfo->fd->num;
2401                 call_value->rep_frame=0;
2402                 call_value->max_ptr=0;
2403                 call_value->private_data = NULL;
2404                 g_hash_table_insert (dcerpc_calls, call_key, call_value);
2405
2406                 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);       
2407         }
2408
2409         value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
2410         if (!value) {
2411             v.uuid = hdr.if_id;
2412             v.ver = hdr.if_ver;
2413             v.opnum = hdr.opnum;
2414             v.req_frame = pinfo->fd->num;
2415             v.rep_frame = 0;
2416             v.max_ptr = 0;
2417             v.private_data=NULL;
2418             value = &v;
2419         }
2420
2421         length = tvb_length_remaining (tvb, offset);
2422         reported_length = tvb_reported_length_remaining (tvb, offset);
2423         stub_length = hdr.frag_len;
2424         if (length > stub_length)
2425             length = stub_length;
2426         if (reported_length > stub_length)
2427             reported_length = stub_length;
2428
2429         di.conv = conv;
2430         di.call_id = hdr.seqnum;
2431         di.smb_fid = -1;
2432         di.request = TRUE;
2433         di.call_data = value;
2434
2435         /*
2436          * XXX - authentication level?
2437          */
2438         dcerpc_try_handoff (pinfo, tree, dcerpc_tree, 
2439                             tvb_new_subset (tvb, offset, length, 
2440                                             reported_length),
2441                             0, hdr.opnum, TRUE, hdr.drep, &di, 0);
2442         break;
2443     case PDU_RESP:
2444         if(!(pinfo->fd->flags.visited)){
2445                 dcerpc_call_value *call_value;
2446                 dcerpc_call_key call_key;
2447
2448                 call_key.conv=conv;
2449                 call_key.call_id=hdr.seqnum;
2450                 call_key.smb_fid=get_smb_fid(pinfo->private_data);
2451
2452                 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
2453                         g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
2454                         if(call_value->rep_frame==0){
2455                                 call_value->rep_frame=pinfo->fd->num;
2456                         }
2457                 }
2458         }
2459
2460         value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
2461         if (!value) {
2462             v.uuid = hdr.if_id;
2463             v.ver = hdr.if_ver;
2464             v.opnum = hdr.opnum;
2465             v.req_frame=0;
2466             v.rep_frame=pinfo->fd->num;
2467             v.private_data=NULL;
2468             value = &v;
2469         }
2470
2471         length = tvb_length_remaining (tvb, offset);
2472         reported_length = tvb_reported_length_remaining (tvb, offset);
2473         stub_length = hdr.frag_len;
2474         if (length > stub_length)
2475             length = stub_length;
2476         if (reported_length > stub_length)
2477             reported_length = stub_length;
2478
2479         di.conv = conv;
2480         di.call_id = 0; 
2481         di.smb_fid = -1;
2482         di.request = FALSE;
2483         di.call_data = value;
2484
2485         /*
2486          * XXX - authentication level?
2487          */
2488         dcerpc_try_handoff (pinfo, tree, dcerpc_tree, 
2489                             tvb_new_subset (tvb, offset, length,
2490                                             reported_length),
2491                             0, value->opnum, FALSE, hdr.drep, &di, 0);
2492         break;
2493     }
2494
2495     return TRUE;
2496 }
2497
2498 static void
2499 dcerpc_init_protocol (void)
2500 {
2501         /* structures and data for BIND */
2502         if (dcerpc_binds){
2503                 g_hash_table_destroy (dcerpc_binds);
2504         }
2505         dcerpc_binds = g_hash_table_new (dcerpc_bind_hash, dcerpc_bind_equal);
2506
2507         if (dcerpc_bind_key_chunk){
2508                 g_mem_chunk_destroy (dcerpc_bind_key_chunk);
2509         }
2510         dcerpc_bind_key_chunk = g_mem_chunk_new ("dcerpc_bind_key_chunk",
2511                                              sizeof (dcerpc_bind_key),
2512                                              200 * sizeof (dcerpc_bind_key),
2513                                              G_ALLOC_ONLY);
2514         if (dcerpc_bind_value_chunk){
2515                 g_mem_chunk_destroy (dcerpc_bind_value_chunk);
2516         }
2517         dcerpc_bind_value_chunk = g_mem_chunk_new ("dcerpc_bind_value_chunk",
2518                                              sizeof (dcerpc_bind_value),
2519                                              200 * sizeof (dcerpc_bind_value),
2520                                              G_ALLOC_ONLY);
2521         /* structures and data for CALL */
2522         if (dcerpc_calls){
2523                 g_hash_table_destroy (dcerpc_calls);
2524         }
2525         dcerpc_calls = g_hash_table_new (dcerpc_call_hash, dcerpc_call_equal);
2526         if (dcerpc_call_key_chunk){
2527                 g_mem_chunk_destroy (dcerpc_call_key_chunk);
2528         }
2529         dcerpc_call_key_chunk = g_mem_chunk_new ("dcerpc_call_key_chunk",
2530                                              sizeof (dcerpc_call_key),
2531                                              200 * sizeof (dcerpc_call_key),
2532                                              G_ALLOC_ONLY);
2533         if (dcerpc_call_value_chunk){
2534                 g_mem_chunk_destroy (dcerpc_call_value_chunk);
2535         }
2536         dcerpc_call_value_chunk = g_mem_chunk_new ("dcerpc_call_value_chunk",
2537                                              sizeof (dcerpc_call_value),
2538                                              200 * sizeof (dcerpc_call_value),
2539                                              G_ALLOC_ONLY);
2540
2541         /* structure and data for MATCHED */
2542         if (dcerpc_matched){
2543                 g_hash_table_destroy (dcerpc_matched);
2544         }
2545         dcerpc_matched = g_hash_table_new (dcerpc_matched_hash, dcerpc_matched_equal);
2546
2547 }
2548
2549 void
2550 proto_register_dcerpc (void)
2551 {
2552     static hf_register_info hf[] = {
2553         { &hf_dcerpc_request_in,
2554                 { "Request in", "dcerpc.request_in", FT_UINT32, BASE_DEC,
2555                 NULL, 0, "This packet is a response to the packet in this frame", HFILL }},
2556         { &hf_dcerpc_response_in, 
2557                 { "Response in", "dcerpc.response_in", FT_UINT32, BASE_DEC,
2558                 NULL, 0, "The response to this packet is in this packet", HFILL }},
2559         { &hf_dcerpc_referent_id, 
2560                 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
2561                 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
2562         { &hf_dcerpc_ver,
2563           { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2564         { &hf_dcerpc_ver_minor,
2565           { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2566         { &hf_dcerpc_packet_type,
2567           { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_HEX, VALS (pckt_vals), 0x0, "", HFILL }},
2568         { &hf_dcerpc_cn_flags,
2569           { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
2570         { &hf_dcerpc_cn_flags_first_frag,
2571           { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x1, "", HFILL }},
2572         { &hf_dcerpc_cn_flags_last_frag,
2573           { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x2, "", HFILL }},
2574         { &hf_dcerpc_cn_flags_cancel_pending,
2575           { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x4, "", HFILL }},
2576         { &hf_dcerpc_cn_flags_reserved,
2577           { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x8, "", HFILL }},
2578         { &hf_dcerpc_cn_flags_mpx,
2579           { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x10, "", HFILL }},
2580         { &hf_dcerpc_cn_flags_dne,
2581           { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x20, "", HFILL }},
2582         { &hf_dcerpc_cn_flags_maybe,
2583           { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x40, "", HFILL }},
2584         { &hf_dcerpc_cn_flags_object,
2585           { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x80, "", HFILL }},
2586         { &hf_dcerpc_drep,
2587           { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
2588         { &hf_dcerpc_drep_byteorder,
2589           { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS (drep_byteorder_vals), 0x0, "", HFILL }},
2590         { &hf_dcerpc_drep_character,
2591           { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS (drep_character_vals), 0x0, "", HFILL }},
2592         { &hf_dcerpc_drep_fp,
2593           { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS (drep_fp_vals), 0x0, "", HFILL }},
2594         { &hf_dcerpc_cn_frag_len,
2595           { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2596         { &hf_dcerpc_cn_auth_len,
2597           { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2598         { &hf_dcerpc_cn_call_id,
2599           { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2600         { &hf_dcerpc_cn_max_xmit,
2601           { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2602         { &hf_dcerpc_cn_max_recv,
2603           { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2604         { &hf_dcerpc_cn_assoc_group,
2605           { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
2606         { &hf_dcerpc_cn_num_ctx_items,
2607           { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2608         { &hf_dcerpc_cn_ctx_id,
2609           { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2610         { &hf_dcerpc_cn_num_trans_items,
2611           { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2612         { &hf_dcerpc_cn_bind_if_id,
2613           { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2614         { &hf_dcerpc_cn_bind_if_ver,
2615           { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2616         { &hf_dcerpc_cn_bind_if_ver_minor,
2617           { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2618         { &hf_dcerpc_cn_bind_trans_id,
2619           { "Transfer Syntax", "dcerpc.cn_bind_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2620         { &hf_dcerpc_cn_bind_trans_ver,
2621           { "Syntax ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2622         { &hf_dcerpc_cn_alloc_hint,
2623           { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2624         { &hf_dcerpc_cn_sec_addr_len,
2625           { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2626         { &hf_dcerpc_cn_sec_addr,
2627           { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, "", HFILL }},
2628         { &hf_dcerpc_cn_num_results,
2629           { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2630         { &hf_dcerpc_cn_ack_result,
2631           { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2632         { &hf_dcerpc_cn_ack_reason,
2633           { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2634         { &hf_dcerpc_cn_ack_trans_id,
2635           { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2636         { &hf_dcerpc_cn_ack_trans_ver,
2637           { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2638         { &hf_dcerpc_cn_cancel_count,
2639           { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2640         { &hf_dcerpc_auth_type,
2641           { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
2642         { &hf_dcerpc_auth_level,
2643           { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS (authn_level_vals), 0x0, "", HFILL }},
2644         { &hf_dcerpc_auth_pad_len,
2645           { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2646         { &hf_dcerpc_auth_rsrvd,
2647           { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2648         { &hf_dcerpc_auth_ctx_id,
2649           { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2650         { &hf_dcerpc_dg_flags1,
2651           { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
2652         { &hf_dcerpc_dg_flags1_rsrvd_01,
2653           { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x01, "", HFILL }},
2654         { &hf_dcerpc_dg_flags1_last_frag,
2655           { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x02, "", HFILL }},
2656         { &hf_dcerpc_dg_flags1_frag,
2657           { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x04, "", HFILL }},
2658         { &hf_dcerpc_dg_flags1_nofack,
2659           { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x08, "", HFILL }},
2660         { &hf_dcerpc_dg_flags1_maybe,
2661           { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x10, "", HFILL }},
2662         { &hf_dcerpc_dg_flags1_idempotent,
2663           { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x20, "", HFILL }},
2664         { &hf_dcerpc_dg_flags1_broadcast,
2665           { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x40, "", HFILL }},
2666         { &hf_dcerpc_dg_flags1_rsrvd_80,
2667           { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x80, "", HFILL }},
2668         { &hf_dcerpc_dg_flags2,
2669           { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
2670         { &hf_dcerpc_dg_flags2_rsrvd_01,
2671           { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x01, "", HFILL }},
2672         { &hf_dcerpc_dg_flags2_cancel_pending,
2673           { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x02, "", HFILL }},
2674         { &hf_dcerpc_dg_flags2_rsrvd_04,
2675           { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x04, "", HFILL }},
2676         { &hf_dcerpc_dg_flags2_rsrvd_08,
2677           { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x08, "", HFILL }},
2678         { &hf_dcerpc_dg_flags2_rsrvd_10,
2679           { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x10, "", HFILL }},
2680         { &hf_dcerpc_dg_flags2_rsrvd_20,
2681           { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x20, "", HFILL }},
2682         { &hf_dcerpc_dg_flags2_rsrvd_40,
2683           { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x40, "", HFILL }},
2684         { &hf_dcerpc_dg_flags2_rsrvd_80,
2685           { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x80, "", HFILL }},
2686         { &hf_dcerpc_dg_serial_lo,
2687           { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
2688         { &hf_dcerpc_dg_serial_hi,
2689           { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
2690         { &hf_dcerpc_dg_ahint,
2691           { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
2692         { &hf_dcerpc_dg_ihint,
2693           { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
2694         { &hf_dcerpc_dg_frag_len,
2695           { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2696         { &hf_dcerpc_dg_frag_num,
2697           { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2698         { &hf_dcerpc_dg_auth_proto,
2699           { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
2700         { &hf_dcerpc_dg_seqnum,
2701           { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
2702         { &hf_dcerpc_dg_server_boot,
2703           { "Server boot time", "dcerpc.dg_server_boot", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
2704         { &hf_dcerpc_dg_if_ver,
2705           { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2706         { &hf_dcerpc_obj_id,
2707           { "Object", "dcerpc.obj_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2708         { &hf_dcerpc_dg_if_id,
2709           { "Interface", "dcerpc.dg_if_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2710         { &hf_dcerpc_dg_act_id,
2711           { "Activitiy", "dcerpc.dg_act_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2712         { &hf_dcerpc_opnum,
2713           { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2714         { &hf_dcerpc_array_max_count,
2715           { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
2716
2717         { &hf_dcerpc_array_offset,
2718           { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
2719
2720         { &hf_dcerpc_array_actual_count,
2721           { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
2722
2723         { &hf_dcerpc_op,
2724           { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2725
2726         { &hf_dcerpc_fragments,
2727           { "DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE, 
2728           NULL, 0x0, "DCE/RPC Fragments", HFILL }},
2729
2730         { &hf_dcerpc_fragment,
2731           { "DCE/RPC Fragment", "dcerpc.fragment", FT_NONE, BASE_NONE, 
2732           NULL, 0x0, "DCE/RPC Fragment", HFILL }},
2733
2734         { &hf_dcerpc_fragment_overlap,
2735           { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
2736
2737         { &hf_dcerpc_fragment_overlap_conflict,
2738           { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
2739
2740         { &hf_dcerpc_fragment_multiple_tails,
2741           { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
2742
2743         { &hf_dcerpc_fragment_too_long_fragment,
2744           { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
2745
2746         { &hf_dcerpc_fragment_error,
2747           { "Defragmentation error", "dcerpc.fragment.error", FT_NONE, BASE_NONE, NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
2748
2749     };
2750     static gint *ett[] = {
2751         &ett_dcerpc,
2752         &ett_dcerpc_cn_flags,
2753         &ett_dcerpc_drep,
2754         &ett_dcerpc_dg_flags1,
2755         &ett_dcerpc_dg_flags2,
2756         &ett_dcerpc_pointer_data,
2757         &ett_dcerpc_fragments,
2758         &ett_dcerpc_fragment,
2759     };
2760     module_t *dcerpc_module;
2761
2762     proto_dcerpc = proto_register_protocol ("DCE RPC", "DCERPC", "dcerpc");
2763     proto_register_field_array (proto_dcerpc, hf, array_length (hf));
2764     proto_register_subtree_array (ett, array_length (ett));
2765     register_init_routine (dcerpc_init_protocol);
2766     dcerpc_module = prefs_register_protocol (proto_dcerpc, NULL);
2767     prefs_register_bool_preference (dcerpc_module,
2768                                     "desegment_dcerpc",
2769                                     "Desegment all DCE/RPC over TCP",
2770                                     "Whether the DCE/RPC dissector should desegment all DCE/RPC over TCP",
2771                                     &dcerpc_cn_desegment);
2772     prefs_register_bool_preference (dcerpc_module,
2773                                     "reassemble_dcerpc",
2774                                     "Reassemble DCE/RPC fragments",
2775                                     "Whether the DCE/RPC dissector should reassemble all fragmented PDUs",
2776                                     &dcerpc_reassemble);
2777     register_init_routine(dcerpc_reassemble_init);
2778     dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
2779 }
2780
2781 void
2782 proto_reg_handoff_dcerpc (void)
2783 {
2784     heur_dissector_add ("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
2785     heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
2786     heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
2787     heur_dissector_add ("smb_transact", dissect_dcerpc_cn_bs, proto_dcerpc);
2788 }