Added mockups for LSA_SECRET and LSA_SECURITY_DESCRIPTOR inside
[obnox/wireshark/wip.git] / packet-dcerpc.c
1 /* packet-dcerpc.c
2  * Routines for DCERPC packet disassembly
3  * Copyright 2001, Todd Sabin <tas@webspan.net>
4  *
5  * $Id: packet-dcerpc.c,v 1.38 2002/03/10 03:11:10 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
43 static const value_string pckt_vals[] = {
44     { 0, "Request"},
45     { 1, "Ping"},
46     { 2, "Response"},
47     { 3, "Fault"},
48     { 4, "Working"},
49     { 5, "Nocall"},
50     { 6, "Reject"},
51     { 7, "Ack"},
52     { 8, "Cl_cancel"},
53     { 9, "Fack"},
54     { 10, "Cancel_ack"},
55     { 11, "Bind"},
56     { 12, "Bind_ack"},
57     { 13, "Bind_nak"},
58     { 14, "Alter_context"},
59     { 15, "Alter_context_resp"},
60     { 16, "AUTH3?"},
61     { 17, "Shutdown"},
62     { 18, "Co_cancel"},
63     { 19, "Orphaned"},
64     { 0,  NULL }
65 };
66
67 static const value_string drep_byteorder_vals[] = {
68     { 0, "Big-endian" },
69     { 1, "Little-endian" },
70     { 0,  NULL }
71 };
72
73 static const value_string drep_character_vals[] = {
74     { 0, "ASCII" },
75     { 1, "EBCDIC" },
76     { 0,  NULL }
77 };
78
79 static const value_string drep_fp_vals[] = {
80     { 0, "IEEE" },
81     { 1, "VAX" },
82     { 2, "Cray" },
83     { 3, "IBM" },
84     { 0,  NULL }
85 };
86
87 static const true_false_string flags_set_truth = {
88   "Set",
89   "Not set"
90 };
91
92 static int proto_dcerpc = -1;
93
94 /* field defines */
95 static int hf_dcerpc_request_in = -1;
96 static int hf_dcerpc_response_in = -1;
97 static int hf_dcerpc_ver = -1;
98 static int hf_dcerpc_ver_minor = -1;
99 static int hf_dcerpc_packet_type = -1;
100 static int hf_dcerpc_cn_flags = -1;
101 static int hf_dcerpc_cn_flags_first_frag = -1;
102 static int hf_dcerpc_cn_flags_last_frag = -1;
103 static int hf_dcerpc_cn_flags_cancel_pending = -1;
104 static int hf_dcerpc_cn_flags_reserved = -1;
105 static int hf_dcerpc_cn_flags_mpx = -1;
106 static int hf_dcerpc_cn_flags_dne = -1;
107 static int hf_dcerpc_cn_flags_maybe = -1;
108 static int hf_dcerpc_cn_flags_object = -1;
109 static int hf_dcerpc_drep = -1;
110 static int hf_dcerpc_drep_byteorder = -1;
111 static int hf_dcerpc_drep_character = -1;
112 static int hf_dcerpc_drep_fp = -1;
113 static int hf_dcerpc_cn_frag_len = -1;
114 static int hf_dcerpc_cn_auth_len = -1;
115 static int hf_dcerpc_cn_call_id = -1;
116 static int hf_dcerpc_cn_max_xmit = -1;
117 static int hf_dcerpc_cn_max_recv = -1;
118 static int hf_dcerpc_cn_assoc_group = -1;
119 static int hf_dcerpc_cn_num_ctx_items = -1;
120 static int hf_dcerpc_cn_ctx_id = -1;
121 static int hf_dcerpc_cn_num_trans_items = -1;
122 static int hf_dcerpc_cn_bind_if_id = -1;
123 static int hf_dcerpc_cn_bind_if_ver = -1;
124 static int hf_dcerpc_cn_bind_if_ver_minor = -1;
125 static int hf_dcerpc_cn_bind_trans_id = -1;
126 static int hf_dcerpc_cn_bind_trans_ver = -1;
127 static int hf_dcerpc_cn_alloc_hint = -1;
128 static int hf_dcerpc_cn_sec_addr_len = -1;
129 static int hf_dcerpc_cn_num_results = -1;
130 static int hf_dcerpc_cn_ack_result = -1;
131 static int hf_dcerpc_cn_ack_reason = -1;
132 static int hf_dcerpc_cn_ack_trans_id = -1;
133 static int hf_dcerpc_cn_ack_trans_ver = -1;
134 static int hf_dcerpc_cn_cancel_count = -1;
135 static int hf_dcerpc_auth_type = -1;
136 static int hf_dcerpc_auth_level = -1;
137 static int hf_dcerpc_auth_pad_len = -1;
138 static int hf_dcerpc_auth_rsrvd = -1;
139 static int hf_dcerpc_auth_ctx_id = -1;
140 static int hf_dcerpc_dg_flags1 = -1;
141 static int hf_dcerpc_dg_flags1_rsrvd_01 = -1;
142 static int hf_dcerpc_dg_flags1_last_frag = -1;
143 static int hf_dcerpc_dg_flags1_frag = -1;
144 static int hf_dcerpc_dg_flags1_nofack = -1;
145 static int hf_dcerpc_dg_flags1_maybe = -1;
146 static int hf_dcerpc_dg_flags1_idempotent = -1;
147 static int hf_dcerpc_dg_flags1_broadcast = -1;
148 static int hf_dcerpc_dg_flags1_rsrvd_80 = -1;
149 static int hf_dcerpc_dg_flags2 = -1;
150 static int hf_dcerpc_dg_flags2_rsrvd_01 = -1;
151 static int hf_dcerpc_dg_flags2_cancel_pending = -1;
152 static int hf_dcerpc_dg_flags2_rsrvd_04 = -1;
153 static int hf_dcerpc_dg_flags2_rsrvd_08 = -1;
154 static int hf_dcerpc_dg_flags2_rsrvd_10 = -1;
155 static int hf_dcerpc_dg_flags2_rsrvd_20 = -1;
156 static int hf_dcerpc_dg_flags2_rsrvd_40 = -1;
157 static int hf_dcerpc_dg_flags2_rsrvd_80 = -1;
158 static int hf_dcerpc_dg_serial_hi = -1;
159 static int hf_dcerpc_obj_id = -1;
160 static int hf_dcerpc_dg_if_id = -1;
161 static int hf_dcerpc_dg_act_id = -1;
162 static int hf_dcerpc_dg_serial_lo = -1;
163 static int hf_dcerpc_dg_ahint = -1;
164 static int hf_dcerpc_dg_ihint = -1;
165 static int hf_dcerpc_dg_frag_len = -1;
166 static int hf_dcerpc_dg_frag_num = -1;
167 static int hf_dcerpc_dg_auth_proto = -1;
168 static int hf_dcerpc_opnum = -1;
169 static int hf_dcerpc_dg_seqnum = -1;
170 static int hf_dcerpc_dg_server_boot = -1;
171 static int hf_dcerpc_dg_if_ver = -1;
172 static int hf_dcerpc_array_max_count = -1;
173 static int hf_dcerpc_array_offset = -1;
174 static int hf_dcerpc_array_actual_count = -1;
175 static int hf_dcerpc_referent_id = -1;
176
177 static gint ett_dcerpc = -1;
178 static gint ett_dcerpc_cn_flags = -1;
179 static gint ett_dcerpc_drep = -1;
180 static gint ett_dcerpc_dg_flags1 = -1;
181 static gint ett_dcerpc_dg_flags2 = -1;
182 static gint ett_dcerpc_pointer_data = -1;
183
184 /* try to desegment big DCE/RPC packets over TCP? */
185 static gboolean dcerpc_cn_desegment = TRUE;
186
187
188 /*
189  * Subdissectors
190  */
191
192 /* the registered subdissectors */
193 static GHashTable *dcerpc_uuids;
194
195 typedef struct _dcerpc_uuid_key {
196     e_uuid_t uuid;
197     guint16 ver;
198 } dcerpc_uuid_key;
199
200 typedef struct _dcerpc_uuid_value {
201     int proto;
202     int ett;
203     gchar *name;
204     dcerpc_sub_dissector *procs;
205 } dcerpc_uuid_value;
206
207 static gint
208 dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2)
209 {
210     dcerpc_uuid_key *key1 = (dcerpc_uuid_key *)k1;
211     dcerpc_uuid_key *key2 = (dcerpc_uuid_key *)k2;
212     return ((memcmp (&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
213             && (key1->ver == key2->ver));
214 }
215
216 static guint
217 dcerpc_uuid_hash (gconstpointer k)
218 {
219     dcerpc_uuid_key *key = (dcerpc_uuid_key *)k;
220     /* This isn't perfect, but the Data1 part of these is almost always
221        unique. */
222     return key->uuid.Data1;
223 }
224
225 void
226 dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver,
227                   dcerpc_sub_dissector *procs)
228 {
229     dcerpc_uuid_key *key = g_malloc (sizeof (*key));
230     dcerpc_uuid_value *value = g_malloc (sizeof (*value));
231
232     key->uuid = *uuid;
233     key->ver = ver;
234
235     value->proto = proto;
236     value->ett = ett;
237     value->name = proto_get_protocol_short_name (proto);
238     value->procs = procs;
239
240     g_hash_table_insert (dcerpc_uuids, key, value);
241 }
242
243
244 /*
245  * To keep track of ctx_id mappings.
246  *
247  * Everytime we see a bind call we update this table.
248  * Note that we always specify a SMB FID. For non-SMB transports this
249  * value is 0.
250  */
251 static GHashTable *dcerpc_binds=NULL;
252
253 typedef struct _dcerpc_bind_key {
254     conversation_t *conv;
255     guint16 ctx_id;
256     guint16 smb_fid;
257 } dcerpc_bind_key;
258
259 typedef struct _dcerpc_bind_value {
260         e_uuid_t uuid;
261         guint16 ver;
262 } dcerpc_bind_value;
263
264 static GMemChunk *dcerpc_bind_key_chunk=NULL;
265 static GMemChunk *dcerpc_bind_value_chunk=NULL;
266
267 static gint
268 dcerpc_bind_equal (gconstpointer k1, gconstpointer k2)
269 {
270     dcerpc_bind_key *key1 = (dcerpc_bind_key *)k1;
271     dcerpc_bind_key *key2 = (dcerpc_bind_key *)k2;
272     return (key1->conv == key2->conv
273             && key1->ctx_id == key2->ctx_id
274             && key1->smb_fid == key2->smb_fid);
275 }
276
277 static guint
278 dcerpc_bind_hash (gconstpointer k)
279 {
280     dcerpc_bind_key *key = (dcerpc_bind_key *)k;
281     return ((guint)key->conv) + key->ctx_id + key->smb_fid;
282 }
283
284 /*
285  * To keep track of callid mappings.  Should really use some generic
286  * conversation support instead.
287  */
288 static GHashTable *dcerpc_calls=NULL;
289
290 typedef struct _dcerpc_call_key {
291     conversation_t *conv;
292     guint32 call_id;
293     guint16 smb_fid;
294 } dcerpc_call_key;
295
296 static GMemChunk *dcerpc_call_key_chunk=NULL;
297
298 static GMemChunk *dcerpc_call_value_chunk=NULL;
299
300 static gint
301 dcerpc_call_equal (gconstpointer k1, gconstpointer k2)
302 {
303     dcerpc_call_key *key1 = (dcerpc_call_key *)k1;
304     dcerpc_call_key *key2 = (dcerpc_call_key *)k2;
305     return (key1->conv == key2->conv
306             && key1->call_id == key2->call_id
307             && key1->smb_fid == key2->smb_fid);
308 }
309
310 static guint
311 dcerpc_call_hash (gconstpointer k)
312 {
313     dcerpc_call_key *key = (dcerpc_call_key *)k;
314     return ((guint32)key->conv) + key->call_id + key->smb_fid;
315 }
316
317
318 /* to keep track of matched calls/responses
319    this one uses the same value struct as calls, but the key is the frame id
320 */
321 static GHashTable *dcerpc_matched=NULL;
322 static gint
323 dcerpc_matched_equal (gconstpointer k1, gconstpointer k2)
324 {
325         return (guint32)k1 == (guint32)k2;
326 }
327
328 static guint
329 dcerpc_matched_hash (gconstpointer k)
330 {
331         return (guint32)k;
332 }
333
334
335
336 /*
337  * Utility functions.  Modeled after packet-rpc.c
338  */
339
340 int
341 dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo,
342                       proto_tree *tree, char *drep, 
343                       int hfindex, guint8 *pdata)
344 {
345     guint8 data;
346
347     data = tvb_get_guint8 (tvb, offset);
348     if (tree) {
349         proto_tree_add_item (tree, hfindex, tvb, offset, 1, (drep[0] & 0x10));
350     }
351     if (pdata)
352         *pdata = data;
353     return offset + 1;
354 }
355
356 int
357 dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo,
358                        proto_tree *tree, char *drep, 
359                        int hfindex, guint16 *pdata)
360 {
361     guint16 data;
362
363     data = ((drep[0] & 0x10)
364             ? tvb_get_letohs (tvb, offset)
365             : tvb_get_ntohs (tvb, offset));
366     
367     if (tree) {
368         proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10));
369     }
370     if (pdata)
371         *pdata = data;
372     return offset + 2;
373 }
374
375 int
376 dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo,
377                        proto_tree *tree, char *drep, 
378                        int hfindex, guint32 *pdata)
379 {
380     guint32 data;
381
382     data = ((drep[0] & 0x10)
383             ? tvb_get_letohl (tvb, offset)
384             : tvb_get_ntohl (tvb, offset));
385     
386     if (tree) {
387         proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10));
388     }
389     if (pdata)
390         *pdata = data;
391     return offset+4;
392 }
393
394 int
395 dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo,
396                        proto_tree *tree, char *drep, 
397                        int hfindex, unsigned char *pdata)
398 {
399     if(pdata){
400       tvb_memcpy(tvb, pdata, offset, 8);
401       if(drep[0] & 0x10){/* XXX this might be the wrong way around */
402         unsigned char data;
403         data=pdata[0];pdata[0]=pdata[7];pdata[7]=data;
404         data=pdata[1];pdata[1]=pdata[6];pdata[6]=data;
405         data=pdata[2];pdata[2]=pdata[5];pdata[5]=data;
406         data=pdata[3];pdata[3]=pdata[4];pdata[4]=data;
407       }
408     }
409
410     if (tree) {
411         proto_tree_add_item(tree, hfindex, tvb, offset, 8, (drep[0] & 0x10));
412     }
413
414     return offset+8;
415 }
416
417 /*
418  * a couple simpler things
419  */
420 guint16
421 dcerpc_tvb_get_ntohs (tvbuff_t *tvb, gint offset, char *drep)
422 {
423     if (drep[0] & 0x10) {
424         return tvb_get_letohs (tvb, offset);
425     } else {
426         return tvb_get_ntohs (tvb, offset);
427     }
428 }
429
430 guint32
431 dcerpc_tvb_get_ntohl (tvbuff_t *tvb, gint offset, char *drep)
432 {
433     if (drep[0] & 0x10) {
434         return tvb_get_letohl (tvb, offset);
435     } else {
436         return tvb_get_ntohl (tvb, offset);
437     }
438 }
439
440 void
441 dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, char *drep, e_uuid_t *uuid)
442 {
443     unsigned int i;
444     uuid->Data1 = dcerpc_tvb_get_ntohl (tvb, offset, drep);
445     uuid->Data2 = dcerpc_tvb_get_ntohs (tvb, offset+4, drep);
446     uuid->Data3 = dcerpc_tvb_get_ntohs (tvb, offset+6, drep);
447
448     for (i=0; i<sizeof (uuid->Data4); i++) {
449         uuid->Data4[i] = tvb_get_guint8 (tvb, offset+8+i);
450     }
451 }
452
453
454
455 /* NDR arrays */
456 /* function to dissect a unidimensional conformant array */
457 int 
458 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
459                 proto_tree *tree, char *drep, 
460                 dcerpc_dissect_fnct_t *fnct)
461 {
462         guint32 i, count;
463         dcerpc_info *di;
464
465         di=pinfo->private_data;
466         if(di->conformant_run){
467                 /* conformant run, just dissect the max_count header */
468                 di->conformant_run=0;
469                 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
470                                 hf_dcerpc_array_max_count, &di->array_max_count);
471                 di->array_max_count_offset=offset-4;
472                 di->conformant_run=1;
473         } else {
474                 /* we dont dont remember where  in the bytestream this fields was */
475                 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
476
477                 /* real run, dissect the elements */
478                 for(i=0;i<di->array_max_count;i++){
479                         offset = (*fnct)(tvb, offset, pinfo, tree, drep);
480                 }
481         }
482
483         return offset;
484 }
485 /* function to dissect a unidimensional conformant and varying array */
486 int 
487 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
488                 proto_tree *tree, char *drep, 
489                 dcerpc_dissect_fnct_t *fnct)
490 {
491         guint32 i, count;
492         dcerpc_info *di;
493
494         di=pinfo->private_data;
495         if(di->conformant_run){
496                 /* conformant run, just dissect the max_count header */
497                 di->conformant_run=0;
498                 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
499                                 hf_dcerpc_array_max_count, &di->array_max_count);
500                 di->array_max_count_offset=offset-4;
501                 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
502                                 hf_dcerpc_array_offset, &di->array_offset);
503                 di->array_offset_offset=offset-4;
504                 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
505                                 hf_dcerpc_array_actual_count, &di->array_actual_count);
506                 di->array_actual_count_offset=offset-4;
507                 di->conformant_run=1;
508         } else {
509                 /* we dont dont remember where  in the bytestream these fields were */
510                 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
511                 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
512                 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
513
514                 /* real run, dissect the elements */
515                 for(i=0;i<di->array_actual_count;i++){
516                         offset = (*fnct)(tvb, offset, pinfo, tree, drep);
517                 }
518         }
519
520         return offset;
521 }
522
523
524 /* ndr pointer handling */
525 /* list of pointers encountered so far */
526 static GSList *ndr_pointer_list = NULL;
527
528 /* position where in the list to insert newly encountered pointers */
529 static int ndr_pointer_list_pos=0;
530
531 /* boolean controlling whether pointers are top-level or embedded */
532 static gboolean pointers_are_top_level = TRUE;
533
534 /* as a kludge, we represent all embedded reference pointers as id==-1
535    hoping that his will not collide with any non-ref pointers */
536 typedef struct ndr_pointer_data {
537         guint32 id;
538         proto_tree *tree;
539         dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
540         int hf_index;
541         int levels;
542 } ndr_pointer_data_t;
543
544 static void
545 init_ndr_pointer_list(packet_info *pinfo)
546 {
547         dcerpc_info *di;
548
549         di=pinfo->private_data;
550         di->conformant_run=0;
551
552         while(ndr_pointer_list){
553                 ndr_pointer_data_t *npd;
554         
555                 npd=g_slist_nth_data(ndr_pointer_list, 0);
556                 ndr_pointer_list=g_slist_remove(ndr_pointer_list, npd);
557                 if(npd){
558                         g_free(npd);
559                 }
560         }
561
562         ndr_pointer_list=NULL;
563         ndr_pointer_list_pos=0;
564         pointers_are_top_level=TRUE;
565 }
566
567 static int
568 dissect_deferred_pointers(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, char *drep)
569 {
570         int found_new_pointer;
571         dcerpc_info *di;
572
573         di=pinfo->private_data;
574         do{
575                 int i, len;
576
577                 found_new_pointer=0;
578                 len=g_slist_length(ndr_pointer_list);
579                 for(i=0;i<len;i++){
580                         ndr_pointer_data_t *tnpd;
581                         tnpd=g_slist_nth_data(ndr_pointer_list, i);
582                         if(tnpd->fnct){
583                                 dcerpc_dissect_fnct_t *fnct;
584
585                                 found_new_pointer=1;
586                                 fnct=tnpd->fnct;
587                                 tnpd->fnct=NULL;
588                                 ndr_pointer_list_pos=i+1;
589                                 di->hf_index=tnpd->hf_index;
590                                 di->levels=tnpd->levels;
591                                 /* first a run to handle any conformant
592                                    array headers */
593                                 di->conformant_run=1;
594                                 offset = (*(fnct))(tvb, offset, pinfo, NULL, drep);
595                                 /* now we dissect the actual pointer */
596                                 di->conformant_run=0;
597                                 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, drep);
598                                 break;
599                         }
600                 }
601         } while(found_new_pointer);
602
603         return offset;
604 }
605                                                 
606
607 static void
608 add_pointer_to_list(packet_info *pinfo, proto_tree *tree, 
609                 dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index, int levels)
610 {
611         ndr_pointer_data_t *npd;
612
613         /* check if this pointer is valid */
614         if(id!=0xffffffff){
615                 dcerpc_info *di;
616                 dcerpc_call_value *value;
617
618                 di=pinfo->private_data;
619                 value=di->call_data;
620
621                 if(di->request){
622                         if(!(pinfo->fd->flags.visited)){
623                                 if(id>value->max_ptr){
624                                         value->max_ptr=id;
625                                 }
626                         }
627                 } else {
628                         /* if we havent seen the request bail out since we cant
629                            know whether this is the first non-NULL instance 
630                            or not */
631                         if(value->req_frame==-1){
632                                 /* XXX THROW EXCEPTION */
633                         }
634
635                         /* We saw this one in the request frame, nothing to
636                            dissect later */
637                         if(id<=value->max_ptr){
638                                 return;
639                         }
640                 }
641         }
642
643         npd=g_malloc(sizeof(ndr_pointer_data_t));
644         npd->id=id;
645         npd->tree=tree;
646         npd->fnct=fnct;
647         npd->hf_index=hf_index;
648         npd->levels=levels;
649         ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd, 
650                                         ndr_pointer_list_pos);
651         ndr_pointer_list_pos++;
652 }
653
654
655 static int
656 find_pointer_index(guint32 id)
657 {
658         ndr_pointer_data_t *npd;
659         int i,len;
660         
661         len=g_slist_length(ndr_pointer_list);
662         for(i=0;i<len;i++){
663                 npd=g_slist_nth_data(ndr_pointer_list, i);
664                 if(npd){
665                         if(npd->id==id){
666                                 return i;
667                         }
668                 }
669         }
670         
671         return -1;
672 }
673
674 /* this function dissects an NDR pointer and stores the callback for later deferred dissection.
675  * fnct is the callback function for when we have reached this object in the bytestream.
676  * type is what type of pointer this is
677  * text is what text we should put in any created tree node
678  * hf_index is what hf value we want to pass to the callback function when it is called,
679  *    the callback can later pich this one up from di->hf_index.
680  * levels is a generic int we want to pass to teh callback function.
681  *    the callback can later pick it up from di->levels
682  *
683  * See packet-dcerpc-samr.c for examples
684  */
685 int 
686 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
687                         proto_tree *tree, char *drep, 
688                         dcerpc_dissect_fnct_t *fnct, int type, char *text, int hf_index, int levels)
689 {
690         dcerpc_info *di;
691         
692         di=pinfo->private_data;
693         if(di->conformant_run){
694                 /* this call was only for dissecting the header for any
695                    embedded conformant array. we will not parse any
696                    pointers in this mode.
697                 */
698                 return offset;
699         }
700
701         /*TOP LEVEL REFERENCE POINTER*/
702         if( pointers_are_top_level
703         && (type==NDR_POINTER_REF) ){
704                 add_pointer_to_list(pinfo, tree, fnct, 0xffffffff, hf_index, levels);
705                 goto after_ref_id;
706         }
707
708         /*TOP LEVEL FULL POINTER*/
709         if( pointers_are_top_level
710         && (type==NDR_POINTER_PTR) ){
711                 int idx;
712                 guint32 id;
713                 proto_item *item;
714                 proto_tree *tr;
715
716                 /* get the referent id */
717                 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
718         
719                 /* we got a NULL pointer */
720                 if(id==0){
721                         proto_tree_add_text(tree, tvb, offset-4, 4,
722                                 "(NULL pointer) %s",text);
723                         goto after_ref_id;
724                 }
725
726                 /* see if we have seen this pointer before */
727                 idx=find_pointer_index(id);
728
729                 /* we have seen this pointer before */
730                 if(idx>=0){
731                         proto_tree_add_text(tree, tvb, offset-4, 4,
732                                 "(duplicate PTR) %s",text);
733                         goto after_ref_id;
734                 }
735
736                 /* new pointer */
737                 item=proto_tree_add_text(tree, tvb, offset-4, 4, 
738                         "%s", text);
739                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
740                 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
741                 add_pointer_to_list(pinfo, tr, fnct, id, hf_index, levels);
742                 goto after_ref_id;
743         }
744         /*TOP LEVEL UNIQUE POINTER*/
745         if( pointers_are_top_level
746         && (type==NDR_POINTER_UNIQUE) ){
747                 int idx;
748                 guint32 id;
749                 proto_item *item;
750                 proto_tree *tr;
751
752                 /* get the referent id */
753                 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
754         
755                 /* we got a NULL pointer */
756                 if(id==0){
757                         proto_tree_add_text(tree, tvb, offset-4, 4,
758                                 "(NULL pointer) %s",text);
759                         goto after_ref_id;
760                 }
761
762                 /* new pointer */
763                 item=proto_tree_add_text(tree, tvb, offset-4, 4, 
764                         "%s", text);
765                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
766                 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
767                 add_pointer_to_list(pinfo, tr, fnct, 0xffffffff, hf_index, levels);
768                 goto after_ref_id;
769         }
770
771         /*EMBEDDED REFERENCE POINTER*/
772         if( (!pointers_are_top_level)
773         && (type==NDR_POINTER_REF) ){
774                 guint32 id;
775                 proto_item *item;
776                 proto_tree *tr;
777
778                 /* get the referent id */
779                 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
780         
781                 /* new pointer */
782                 item=proto_tree_add_text(tree, tvb, offset-4, 4, 
783                         "%s",text);
784                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
785                 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
786                 add_pointer_to_list(pinfo, tr, fnct, 0xffffffff, hf_index, levels);
787                 goto after_ref_id;
788         }
789
790         /*EMBEDDED UNIQUE POINTER*/
791         if( (!pointers_are_top_level)
792         && (type==NDR_POINTER_UNIQUE) ){
793                 int idx;
794                 guint32 id;
795                 proto_item *item;
796                 proto_tree *tr;
797
798                 /* get the referent id */
799                 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
800         
801                 /* we got a NULL pointer */
802                 if(id==0){
803                         proto_tree_add_text(tree, tvb, offset-4, 4,
804                                 "(NULL pointer) %s", text);
805                         goto after_ref_id;
806                 }
807
808                 /* new pointer */
809                 item=proto_tree_add_text(tree, tvb, offset-4, 4, 
810                         "%s",text);
811                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
812                 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
813                 add_pointer_to_list(pinfo, tr, fnct, 0xffffffff, hf_index, levels);
814                 goto after_ref_id;
815         }
816
817         /*EMBEDDED FULL POINTER*/
818         if( (!pointers_are_top_level)
819         && (type==NDR_POINTER_PTR) ){
820                 int idx;
821                 guint32 id;
822                 proto_item *item;
823                 proto_tree *tr;
824
825                 /* get the referent id */
826                 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
827         
828                 /* we got a NULL pointer */
829                 if(id==0){
830                         proto_tree_add_text(tree, tvb, offset-4, 4,
831                                 "(NULL pointer) %s",text);
832                         goto after_ref_id;
833                 }
834
835                 /* see if we have seen this pointer before */
836                 idx=find_pointer_index(id);
837
838                 /* we have seen this pointer before */
839                 if(idx>=0){
840                         proto_tree_add_text(tree, tvb, offset-4, 4,
841                                 "(duplicate PTR) %s",text);
842                         goto after_ref_id;
843                 }
844
845                 /* new pointer */
846                 item=proto_tree_add_text(tree, tvb, offset-4, 4, 
847                         "%s", text);
848                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
849                 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
850                 add_pointer_to_list(pinfo, tr, fnct, id, hf_index, levels);
851                 goto after_ref_id;
852         }
853
854
855 after_ref_id:
856         /* After each top level pointer we have dissected we have to
857            dissect all deferrals before we move on to the next top level
858            argument */
859         if(pointers_are_top_level==TRUE){
860                 pointers_are_top_level=FALSE;
861                 offset = dissect_deferred_pointers(pinfo, tree, tvb, offset, drep);
862                 pointers_are_top_level=TRUE;
863         }
864
865         return offset;
866 }
867
868
869
870 static int
871 dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
872                     proto_tree *dcerpc_tree,
873                     tvbuff_t *tvb, gint offset,
874                     guint16 opnum, gboolean is_rqst,
875                     char *drep, dcerpc_info *info)
876 {
877     dcerpc_uuid_key key;
878     dcerpc_uuid_value *sub_proto;
879     int length;
880     proto_tree *sub_tree = NULL;
881     dcerpc_sub_dissector *proc;
882     gchar *name = NULL;
883     dcerpc_dissect_fnct_t *sub_dissect;
884     const char *saved_proto;
885     void *saved_private_data;
886
887     key.uuid = info->call_data->uuid;
888     key.ver = info->call_data->ver;
889
890     
891     if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == NULL
892          || !proto_is_protocol_enabled(sub_proto->proto)) {
893         /*
894          * We don't have a dissector for this UUID, or the protocol
895          * for that UUID is disabled.
896          */
897         length = tvb_length_remaining (tvb, offset);
898         if (length > 0) {
899             proto_tree_add_text (dcerpc_tree, tvb, offset, length,
900                                  "Stub data (%d byte%s)", length,
901                                  plurality(length, "", "s"));
902         }
903         return -1;
904     }
905
906     if (tree) {
907         proto_item *sub_item;
908         sub_item = proto_tree_add_item (tree, sub_proto->proto, tvb, offset, 
909                                         -1, FALSE);
910
911         if (sub_item) {
912             sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
913         }
914         
915     }
916     for (proc = sub_proto->procs; proc->name; proc++) {
917         if (proc->num == opnum) {
918             name = proc->name;
919             break;
920         }
921     }
922
923     if (!name)
924         name = "Unknown?!";
925
926     if (check_col (pinfo->cinfo, COL_INFO)) {
927         col_add_fstr (pinfo->cinfo, COL_INFO, "%s %s(...)",
928                       is_rqst ? "rqst" : "rply", name);
929     }
930
931     if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
932         col_set_str (pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
933     }
934
935     sub_dissect = is_rqst ? proc->dissect_rqst : proc->dissect_resp;
936     if (sub_dissect) {
937         saved_proto = pinfo->current_proto;
938         saved_private_data = pinfo->private_data;
939         pinfo->current_proto = sub_proto->name;
940         pinfo->private_data = (void *)info;
941
942         init_ndr_pointer_list(pinfo);
943         offset = sub_dissect (tvb, offset, pinfo, sub_tree, drep);
944
945         pinfo->current_proto = saved_proto;
946         pinfo->private_data = saved_private_data;
947     } else {
948         length = tvb_length_remaining (tvb, offset);
949         if (length > 0) {
950             proto_tree_add_text (sub_tree, tvb, offset, length,
951                                  "Stub data (%d byte%s)", length,
952                                  plurality(length, "", "s"));
953         }
954     }
955     return 0;
956 }
957
958 static int
959 dissect_dcerpc_cn_auth (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
960                         e_dce_cn_common_hdr_t *hdr)
961 {
962     int offset;
963     guint8 auth_pad_len;
964
965     /*
966      * The authentication information is at the *end* of the PDU; in
967      * request and response PDUs, the request and response stub data
968      * come before it.
969      *
970      * If the full packet is here, and we've got an auth len, and it's
971      * valid, then dissect the auth info
972      */
973     if (tvb_length (tvb) >= hdr->frag_len
974         && hdr->auth_len
975         && (hdr->auth_len + 8 <= hdr->frag_len)) {
976
977         offset = hdr->frag_len - (hdr->auth_len + 8);
978         
979         offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
980                                        hf_dcerpc_auth_type, NULL);
981         offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
982                                        hf_dcerpc_auth_level, NULL);
983         offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
984                                        hf_dcerpc_auth_pad_len, &auth_pad_len);
985         offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
986                                        hf_dcerpc_auth_rsrvd, NULL);
987         offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
988                                         hf_dcerpc_auth_ctx_id, NULL);
989
990         proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len, "Auth Data");
991
992         /* figure out where the auth padding starts */
993         offset = hdr->frag_len - (hdr->auth_len + 8 + auth_pad_len);
994         if (offset > 0 && auth_pad_len) {
995             proto_tree_add_text (dcerpc_tree, tvb, offset, 
996                                  auth_pad_len, "Auth padding");
997             return hdr->auth_len + 8 + auth_pad_len;
998         } else {
999             return hdr->auth_len + 8;
1000         }
1001     } else {
1002         return 0;
1003     }
1004 }
1005
1006
1007 /* We need to hash in the SMB fid number to generate a unique hash table
1008    key as DCERPC over SMB allows several pipes over the same TCP/IP
1009    socket. */
1010
1011 static guint16 get_smb_fid (void *private_data)
1012 {
1013     dcerpc_private_info *priv = (dcerpc_private_info *)private_data;
1014         
1015     if (!priv)
1016         return 0;       /* Nothing to see here */
1017
1018     /* DCERPC over smb */
1019
1020     if (priv->transport_type == DCERPC_TRANSPORT_SMB)
1021         return priv->data.smb.fid;
1022
1023     /* Some other transport... */
1024
1025     return 0;
1026 }
1027
1028 /*
1029  * Connection oriented packet types
1030  */
1031
1032 static void
1033 dissect_dcerpc_cn_bind (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1034                         e_dce_cn_common_hdr_t *hdr)
1035 {
1036     conversation_t *conv = NULL;
1037     guint8 num_ctx_items;
1038     guint i;
1039     gboolean saw_ctx_item = FALSE;
1040     guint16 ctx_id;
1041     guint16 num_trans_items;
1042     guint j;
1043     e_uuid_t if_id;
1044     e_uuid_t trans_id;
1045     guint32 trans_ver;
1046     guint16 if_ver, if_ver_minor;
1047     int offset = 16;
1048
1049     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1050                                     hf_dcerpc_cn_max_xmit, NULL);
1051
1052     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1053                                     hf_dcerpc_cn_max_recv, NULL);
1054
1055     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1056                                     hf_dcerpc_cn_assoc_group, NULL);
1057
1058     offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1059                                     hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
1060
1061     /* padding */
1062     offset += 3;
1063
1064     for (i = 0; i < num_ctx_items; i++) {
1065       offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1066                                       hf_dcerpc_cn_ctx_id, &ctx_id);
1067
1068       offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1069                                       hf_dcerpc_cn_num_trans_items, &num_trans_items);
1070
1071       dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
1072       if (dcerpc_tree) {
1073           proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_if_id, tvb,
1074                                         offset, 16, "HMMM",
1075                                         "Interface UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1076                                         if_id.Data1, if_id.Data2, if_id.Data3,
1077                                         if_id.Data4[0], if_id.Data4[1],
1078                                         if_id.Data4[2], if_id.Data4[3],
1079                                         if_id.Data4[4], if_id.Data4[5],
1080                                         if_id.Data4[6], if_id.Data4[7]);
1081       }
1082       offset += 16;
1083
1084       if (hdr->drep[0] & 0x10) {
1085           offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1086                                           hf_dcerpc_cn_bind_if_ver, &if_ver);
1087           offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1088                                           hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
1089       } else {
1090           offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1091                                           hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
1092           offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1093                                           hf_dcerpc_cn_bind_if_ver, &if_ver);
1094       }
1095
1096       if (!saw_ctx_item) {
1097         conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
1098                                   pinfo->srcport, pinfo->destport, 0);
1099         if (conv == NULL) {
1100             conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
1101                                      pinfo->srcport, pinfo->destport, 0);
1102         }
1103
1104         /* if this is the first time we see this packet, we need to
1105            update the dcerpc_binds table so that any later calls can
1106            match to the interface.
1107            XXX We assume that BINDs will NEVER be fragmented.
1108         */
1109         if(!(pinfo->fd->flags.visited)){
1110                 dcerpc_bind_key *key;
1111                 dcerpc_bind_value *value;
1112
1113                 key = g_mem_chunk_alloc (dcerpc_bind_key_chunk);
1114                 key->conv = conv;
1115                 key->ctx_id = ctx_id;
1116                 key->smb_fid = get_smb_fid(pinfo->private_data);
1117
1118                 value = g_mem_chunk_alloc (dcerpc_bind_value_chunk);
1119                 value->uuid = if_id;
1120                 value->ver = if_ver;
1121
1122                 /* add this entry to the bind table, first removing any
1123                    previous ones that are identical
1124                  */
1125                 if(g_hash_table_lookup(dcerpc_binds, key)){
1126                         g_hash_table_remove(dcerpc_binds, key);
1127                 }
1128                 g_hash_table_insert (dcerpc_binds, key, value);
1129         }
1130
1131         if (check_col (pinfo->cinfo, COL_INFO)) {
1132           col_add_fstr (pinfo->cinfo, COL_INFO, "%s: UUID %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %d.%d",
1133                         hdr->ptype == PDU_BIND ? "Bind" : "Alter Ctx",
1134                         if_id.Data1, if_id.Data2, if_id.Data3,
1135                         if_id.Data4[0], if_id.Data4[1],
1136                         if_id.Data4[2], if_id.Data4[3],
1137                         if_id.Data4[4], if_id.Data4[5],
1138                         if_id.Data4[6], if_id.Data4[7],
1139                         if_ver, if_ver_minor);
1140         }
1141         saw_ctx_item = TRUE;
1142       }
1143
1144       for (j = 0; j < num_trans_items; j++) {
1145         dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
1146         if (dcerpc_tree) {
1147             proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_trans_id, tvb,
1148                                           offset, 16, "HMMM",
1149                                           "Transfer Syntax: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1150                                           trans_id.Data1, trans_id.Data2, trans_id.Data3,
1151                                           trans_id.Data4[0], trans_id.Data4[1],
1152                                           trans_id.Data4[2], trans_id.Data4[3],
1153                                           trans_id.Data4[4], trans_id.Data4[5],
1154                                           trans_id.Data4[6], trans_id.Data4[7]);
1155         }
1156         offset += 16;
1157
1158         offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1159                                         hf_dcerpc_cn_bind_trans_ver, &trans_ver);
1160       }
1161     }
1162
1163     dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr);
1164 }
1165
1166 static void
1167 dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1168                             e_dce_cn_common_hdr_t *hdr)
1169 {
1170     guint16 max_xmit, max_recv;
1171     guint16 sec_addr_len;
1172     guint8 num_results;
1173     guint i;
1174     guint16 result;
1175     guint16 reason;
1176     e_uuid_t trans_id;
1177     guint32 trans_ver;
1178
1179     int offset = 16;
1180
1181     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1182                                     hf_dcerpc_cn_max_xmit, &max_xmit);
1183
1184     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1185                                     hf_dcerpc_cn_max_recv, &max_recv);
1186
1187     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1188                                     hf_dcerpc_cn_assoc_group, NULL);
1189
1190     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1191                                     hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
1192     offset += sec_addr_len;
1193
1194     if (offset % 4) {
1195         offset += 4 - offset % 4;
1196     }
1197
1198     offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1199                                    hf_dcerpc_cn_num_results, &num_results);
1200
1201     /* padding */
1202     offset += 3;
1203
1204     for (i = 0; i < num_results; i++) {
1205         offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, 
1206                                         hdr->drep, hf_dcerpc_cn_ack_result,
1207                                         &result);
1208         offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, 
1209                                         hdr->drep, hf_dcerpc_cn_ack_reason,
1210                                         &reason);
1211
1212         dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
1213         if (dcerpc_tree) {
1214             proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_ack_trans_id, tvb,
1215                                           offset, 16, "HMMM",
1216                                           "Transfer Syntax: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1217                                           trans_id.Data1, trans_id.Data2, trans_id.Data3,
1218                                           trans_id.Data4[0], trans_id.Data4[1],
1219                                           trans_id.Data4[2], trans_id.Data4[3],
1220                                           trans_id.Data4[4], trans_id.Data4[5],
1221                                           trans_id.Data4[6], trans_id.Data4[7]);
1222         }
1223         offset += 16;
1224
1225         offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1226                                         hf_dcerpc_cn_ack_trans_ver, &trans_ver);
1227     }
1228     
1229     dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr);
1230
1231     if (check_col (pinfo->cinfo, COL_INFO)) {
1232         if (num_results != 0 && result == 0) {
1233             col_add_fstr (pinfo->cinfo, COL_INFO, "%s ack: accept  max_xmit: %d  max_recv: %d",
1234                           hdr->ptype == PDU_BIND_ACK ? "Bind" : "Alter ctx",
1235                           max_xmit, max_recv);
1236         } else {
1237             /* FIXME: should put in reason */
1238             col_add_fstr (pinfo->cinfo, COL_INFO, "%s ack: %s",
1239                           hdr->ptype == PDU_BIND_ACK ? "Bind" : "Alter ctx",
1240                           result == 1 ? "User reject" :
1241                           result == 2 ? "Provider reject" :
1242                           "Unknown");
1243         }
1244     }
1245 }
1246
1247 static void
1248 dissect_dcerpc_cn_rqst (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1249                         proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
1250 {
1251     conversation_t *conv;
1252     guint16 ctx_id;
1253     guint16 opnum;
1254     e_uuid_t obj_id;
1255     int auth_sz = 0;
1256     int offset = 16;
1257
1258     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1259                                     hf_dcerpc_cn_alloc_hint, NULL);
1260
1261     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1262                                     hf_dcerpc_cn_ctx_id, &ctx_id);
1263
1264     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1265                                     hf_dcerpc_opnum, &opnum);
1266
1267     if (check_col (pinfo->cinfo, COL_INFO)) {
1268         col_add_fstr (pinfo->cinfo, COL_INFO, "Request: opnum: %d  ctx_id:%d",
1269                          opnum, ctx_id);
1270     }
1271
1272     if (hdr->flags & 0x80) {
1273         dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id);
1274         if (dcerpc_tree) {
1275             proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
1276                                           offset, 16, "HMMM",
1277                                           "Object UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1278                                           obj_id.Data1, obj_id.Data2, obj_id.Data3,
1279                                           obj_id.Data4[0],
1280                                           obj_id.Data4[1],
1281                                           obj_id.Data4[2],
1282                                           obj_id.Data4[3],
1283                                           obj_id.Data4[4],
1284                                           obj_id.Data4[5],
1285                                           obj_id.Data4[6],
1286                                           obj_id.Data4[7]);
1287         }
1288         offset += 16;
1289     }
1290
1291     auth_sz = dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr);
1292
1293     conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
1294                               pinfo->srcport, pinfo->destport, 0);
1295     if (!conv) {
1296
1297     } else {
1298         dcerpc_call_value *value;
1299         int length, reported_length, stub_length;
1300         dcerpc_info di;
1301
1302         /* !!! we can NOT check flags.visited here since this will interact
1303            badly with when SMB handles (i.e. calls the subdissector)
1304            and desegmented pdu's .
1305            Instead we check if this pdu is already in the matched table or not
1306         */
1307         if(!g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num)){
1308                 dcerpc_bind_key bind_key;
1309                 dcerpc_bind_value *bind_value;
1310
1311                 bind_key.conv=conv;
1312                 bind_key.ctx_id=ctx_id;
1313                 bind_key.smb_fid=get_smb_fid(pinfo->private_data);
1314
1315                 if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key))){
1316                         dcerpc_call_key *call_key;
1317                         dcerpc_call_value *call_value;
1318
1319                         /* We found the binding so just add the call
1320                            to both the call table and the matched table
1321                         */
1322                         call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
1323                         call_key->conv=conv;
1324                         call_key->call_id=hdr->call_id;
1325                         call_key->smb_fid=get_smb_fid(pinfo->private_data);
1326
1327                         /* if there is already a matching call in the table
1328                            remove it so it is replaced with the new one */
1329                         if(g_hash_table_lookup(dcerpc_calls, call_key)){
1330                                 g_hash_table_remove(dcerpc_calls, call_key);
1331                         }
1332
1333                         call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
1334                         call_value->uuid = bind_value->uuid;
1335                         call_value->ver = bind_value->ver;
1336                         call_value->opnum = opnum;
1337                         call_value->req_frame=pinfo->fd->num;
1338                         call_value->rep_frame=-1;
1339                         call_value->max_ptr=0;
1340                         call_value->private_data = NULL;
1341                         g_hash_table_insert (dcerpc_calls, call_key, call_value);
1342
1343                         g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);       
1344                 }
1345         }
1346
1347         value=g_hash_table_lookup (dcerpc_matched, (void *)pinfo->fd->num);
1348
1349
1350         if (value) {
1351
1352             /* handoff this call */
1353             length = tvb_length_remaining(tvb, offset);
1354             reported_length = tvb_reported_length_remaining(tvb, offset);
1355             stub_length = hdr->frag_len - offset - auth_sz;
1356             if (length > stub_length)
1357               length = stub_length;
1358             if (reported_length > stub_length)
1359               reported_length = stub_length;
1360             di.conv = conv;
1361             di.call_id = hdr->call_id;
1362             di.smb_fid = get_smb_fid(pinfo->private_data);
1363             di.request = TRUE;
1364             di.call_data = value;
1365
1366             if(value->rep_frame!=-1){
1367                 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in, 
1368                                     tvb, 0, 0, value->rep_frame);
1369             }
1370
1371             dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
1372                                 tvb_new_subset (tvb, offset, length,
1373                                                 reported_length),
1374                                 0, opnum, TRUE, hdr->drep, &di);
1375         }
1376     }
1377 }
1378
1379 static void
1380 dissect_dcerpc_cn_resp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1381                         proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
1382 {
1383     dcerpc_call_value *value = NULL;
1384     conversation_t *conv;
1385     guint16 ctx_id;
1386     int auth_sz = 0;
1387     int offset = 16;
1388
1389     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1390                                     hf_dcerpc_cn_alloc_hint, NULL);
1391
1392     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1393                                     hf_dcerpc_cn_ctx_id, &ctx_id);
1394
1395     if (check_col (pinfo->cinfo, COL_INFO)) {
1396         col_add_fstr (pinfo->cinfo, COL_INFO, "Response: call_id: %d  ctx_id:%d",
1397                       hdr->call_id, ctx_id);
1398     }
1399
1400     offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1401                                    hf_dcerpc_cn_cancel_count, NULL);
1402     /* padding */
1403     offset++;
1404
1405     auth_sz = dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr);
1406
1407     conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
1408                               pinfo->srcport, pinfo->destport, 0);
1409     if (!conv) {
1410         /* no point in creating one here, really */
1411     } else {
1412
1413         /* !!! we can NOT check flags.visited here since this will interact
1414            badly with when SMB handles (i.e. calls the subdissector)
1415            and desegmented pdu's .
1416            Instead we check if this pdu is already in the matched table or not
1417         */
1418         if(!g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num)){
1419                 dcerpc_call_key call_key;
1420                 dcerpc_call_value *call_value;
1421
1422                 call_key.conv=conv;
1423                 call_key.call_id=hdr->call_id;
1424                 call_key.smb_fid=get_smb_fid(pinfo->private_data);
1425
1426                 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
1427                         g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
1428                         if(call_value->rep_frame==-1){
1429                                 call_value->rep_frame=pinfo->fd->num;
1430                         }
1431
1432                 }
1433         }
1434
1435         value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
1436
1437         if (value) {
1438             int length, reported_length, stub_length;
1439             dcerpc_info di;
1440
1441             /* handoff this call */
1442             length = tvb_length_remaining(tvb, offset);
1443             reported_length = tvb_reported_length_remaining(tvb, offset);
1444             stub_length = hdr->frag_len - offset - auth_sz;
1445             if (length > stub_length)
1446               length = stub_length;
1447             if (reported_length > stub_length)
1448               reported_length = stub_length;
1449             di.conv = conv;
1450             di.call_id = hdr->call_id;
1451             di.smb_fid = get_smb_fid(pinfo->private_data);
1452             di.request = FALSE;
1453             di.call_data = value;
1454
1455             proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
1456             if(value->req_frame!=-1){
1457                 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in, 
1458                                     tvb, 0, 0, value->req_frame);
1459             }
1460
1461             dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
1462                                 tvb_new_subset (tvb, offset, length,
1463                                                 reported_length),
1464                                 0, value->opnum, FALSE, hdr->drep, &di);
1465         }
1466     }
1467 }
1468
1469 /*
1470  * DCERPC dissector for connection oriented calls
1471  */
1472 static int
1473 dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
1474                    proto_tree *tree, gboolean can_desegment)
1475 {
1476     static char nulls[4] = { 0 };
1477     int start_offset;
1478     int padding = 0;
1479     proto_item *ti = NULL;
1480     proto_item *tf = NULL;
1481     proto_tree *dcerpc_tree = NULL;
1482     proto_tree *cn_flags_tree = NULL;
1483     proto_tree *drep_tree = NULL;
1484     e_dce_cn_common_hdr_t hdr;
1485
1486     /*
1487      * when done over nbt, dcerpc requests are padded with 4 bytes of null
1488      * data for some reason.
1489      *
1490      * XXX - if that's always the case, the right way to do this would
1491      * be to have a "dissect_dcerpc_cn_nb" routine which strips off
1492      * the 4 bytes of null padding, and make that the dissector
1493      * used for "netbios".
1494      */
1495     if (tvb_bytes_exist (tvb, offset, 4) &&
1496         tvb_memeql (tvb, offset, nulls, 4) == 0) {
1497
1498         /*
1499          * Skip the padding.
1500          */
1501         offset += 4;
1502         padding += 4;
1503     }
1504
1505     /*
1506      * Check if this looks like a C/O DCERPC call
1507      */
1508     if (!tvb_bytes_exist (tvb, offset, sizeof (hdr))) {
1509         return -1;
1510     }
1511     start_offset = offset;
1512     hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
1513     if (hdr.rpc_ver != 5)
1514         return -1;
1515     hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
1516     if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
1517         return -1;
1518     hdr.ptype = tvb_get_guint8 (tvb, offset++);
1519     if (hdr.ptype > 19)
1520         return -1;
1521
1522     if (check_col (pinfo->cinfo, COL_PROTOCOL))
1523         col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
1524     if (check_col (pinfo->cinfo, COL_INFO))
1525         col_set_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
1526
1527     hdr.flags = tvb_get_guint8 (tvb, offset++);
1528     tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
1529     offset += sizeof (hdr.drep);
1530
1531     hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1532     offset += 2;
1533     hdr.auth_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1534     offset += 2;
1535     hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
1536     offset += 4;
1537
1538     offset = start_offset;
1539     if (can_desegment && pinfo->can_desegment
1540         && hdr.frag_len > tvb_length_remaining (tvb, offset)) {
1541         pinfo->desegment_offset = offset;
1542         pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, offset);
1543         return 0;       /* desegmentation required */
1544     }
1545
1546     if (tree) {
1547         ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE);
1548         if (ti) {
1549             dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
1550         }
1551         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver);
1552         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset++, 1, hdr.rpc_ver_minor);
1553         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype);
1554         tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
1555         cn_flags_tree = proto_item_add_subtree (tf, ett_dcerpc_cn_flags);
1556         if (cn_flags_tree) {
1557             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
1558             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
1559             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
1560             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
1561             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
1562             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
1563             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
1564             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
1565         }
1566         offset++;
1567
1568         tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
1569         drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
1570         if (drep_tree) {
1571             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
1572             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
1573             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
1574         }
1575         offset += sizeof (hdr.drep);
1576
1577         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
1578         offset += 2;
1579
1580         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
1581         offset += 2;
1582
1583         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
1584         offset += 4;
1585     }
1586
1587
1588     /*
1589      * Packet type specific stuff is next.
1590      */
1591     switch (hdr.ptype) {
1592     case PDU_BIND:
1593     case PDU_ALTER:
1594         dissect_dcerpc_cn_bind (tvb, pinfo, dcerpc_tree, &hdr);
1595         break;
1596
1597     case PDU_BIND_ACK:
1598     case PDU_ALTER_ACK:
1599         dissect_dcerpc_cn_bind_ack (tvb, pinfo, dcerpc_tree, &hdr);
1600         break;
1601
1602     case PDU_REQ:
1603         dissect_dcerpc_cn_rqst (tvb, pinfo, dcerpc_tree, tree, &hdr);
1604         break;
1605
1606     case PDU_RESP:
1607         dissect_dcerpc_cn_resp (tvb, pinfo, dcerpc_tree, tree, &hdr);
1608         break;
1609
1610     default:
1611         /* might as well dissect the auth info */
1612         dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr);
1613         break;
1614     }
1615     return hdr.frag_len + padding;
1616 }
1617
1618 /*
1619  * DCERPC dissector for connection oriented calls over packet-oriented
1620  * transports
1621  */
1622 static gboolean
1623 dissect_dcerpc_cn_pk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1624 {
1625     /*
1626      * Only one PDU per transport packet, and only one transport
1627      * packet per PDU.
1628      */
1629     if (dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE) == -1) {
1630         /*
1631          * It wasn't a DCERPC PDU.
1632          */
1633         return FALSE;
1634     } else {
1635         /*
1636          * It was.
1637          */
1638         return TRUE;
1639     }
1640 }
1641
1642 /*
1643  * DCERPC dissector for connection oriented calls over byte-stream
1644  * transports
1645  */
1646 static gboolean
1647 dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1648 {
1649     int offset = 0;
1650     int pdu_len;
1651     gboolean ret = FALSE;
1652
1653     /*
1654      * There may be multiple PDUs per transport packet; keep
1655      * processing them.
1656      */
1657     while (tvb_reported_length_remaining(tvb, offset) != 0) {
1658         pdu_len = dissect_dcerpc_cn (tvb, offset, pinfo, tree,
1659                                      dcerpc_cn_desegment);
1660         if (pdu_len == -1) {
1661             /*
1662              * Not a DCERPC PDU.
1663              */
1664             break;
1665         }
1666
1667         /*
1668          * Well, we've seen at least one DCERPC PDU.
1669          */
1670         ret = TRUE;
1671
1672         if (pdu_len == 0) {
1673             /*
1674              * Desegmentation required - bail now.
1675              */
1676             break;
1677         }
1678
1679         /*
1680          * Step to the next PDU.
1681          */
1682         offset += pdu_len;
1683     }
1684     return ret;
1685 }
1686
1687 /*
1688  * DCERPC dissector for connectionless calls
1689  */
1690 static gboolean
1691 dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1692 {
1693     proto_item *ti = NULL;
1694     proto_item *tf = NULL;
1695     proto_tree *dcerpc_tree = NULL;
1696     proto_tree *dg_flags1_tree = NULL;
1697     proto_tree *dg_flags2_tree = NULL;
1698     proto_tree *drep_tree = NULL;
1699     e_dce_dg_common_hdr_t hdr;
1700     int offset = 0;
1701     conversation_t *conv;
1702
1703     /*
1704      * Check if this looks like a CL DCERPC call.  All dg packets
1705      * have an 80 byte header on them.  Which starts with
1706      * version (4), pkt_type.
1707      */
1708     if (!tvb_bytes_exist (tvb, 0, sizeof (hdr))) {
1709         return FALSE;
1710     }
1711     hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
1712     if (hdr.rpc_ver != 4)
1713         return FALSE;
1714     hdr.ptype = tvb_get_guint8 (tvb, offset++);
1715     if (hdr.ptype > 19)
1716         return FALSE;
1717
1718     if (check_col (pinfo->cinfo, COL_PROTOCOL))
1719         col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
1720     if (check_col (pinfo->cinfo, COL_INFO))
1721         col_set_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
1722
1723     hdr.flags1 = tvb_get_guint8 (tvb, offset++);
1724     hdr.flags2 = tvb_get_guint8 (tvb, offset++);
1725     tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
1726     offset += sizeof (hdr.drep);
1727     hdr.serial_hi = tvb_get_guint8 (tvb, offset++);
1728     dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.obj_id);
1729     offset += 16;
1730     dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.if_id);
1731     offset += 16;
1732     dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.act_id);
1733     offset += 16;
1734     hdr.server_boot = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
1735     offset += 4;
1736     hdr.if_ver = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
1737     offset += 4;
1738     hdr.seqnum = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
1739     offset += 4;
1740     hdr.opnum = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1741     offset += 2;
1742     hdr.ihint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1743     offset += 2;
1744     hdr.ahint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1745     offset += 2;
1746     hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1747     offset += 2;
1748     hdr.frag_num = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1749     offset += 2;
1750     hdr.auth_proto = tvb_get_guint8 (tvb, offset++);
1751     hdr.serial_lo = tvb_get_guint8 (tvb, offset++);
1752
1753     if (tree) {
1754         ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, -1, FALSE);
1755         if (ti) {
1756             dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
1757         }
1758         offset = 0;
1759         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver);
1760
1761         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype);
1762
1763         tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
1764         dg_flags1_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags1);
1765         if (dg_flags1_tree) {
1766             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
1767             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
1768             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
1769             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
1770             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
1771             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
1772             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
1773             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
1774         }
1775         offset++;
1776
1777         tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
1778         dg_flags2_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags2);
1779         if (dg_flags2_tree) {
1780             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
1781             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
1782             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
1783             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
1784             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
1785             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
1786             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
1787             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
1788         }
1789         offset++;
1790
1791         tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
1792         drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
1793         if (drep_tree) {
1794             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
1795             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
1796             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
1797         }
1798         offset += sizeof (hdr.drep);
1799
1800         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset++, 1, hdr.serial_hi);
1801
1802         proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
1803                                       offset, 16, "HMMM",
1804                                       "Object: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1805                                       hdr.obj_id.Data1, hdr.obj_id.Data2, hdr.obj_id.Data3,
1806                                       hdr.obj_id.Data4[0],
1807                                       hdr.obj_id.Data4[1],
1808                                       hdr.obj_id.Data4[2],
1809                                       hdr.obj_id.Data4[3],
1810                                       hdr.obj_id.Data4[4],
1811                                       hdr.obj_id.Data4[5],
1812                                       hdr.obj_id.Data4[6],
1813                                       hdr.obj_id.Data4[7]);
1814         offset += 16;
1815
1816         proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
1817                                       offset, 16, "HMMM",
1818                                       "Interface: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1819                                       hdr.if_id.Data1, hdr.if_id.Data2, hdr.if_id.Data3,
1820                                       hdr.if_id.Data4[0],
1821                                       hdr.if_id.Data4[1],
1822                                       hdr.if_id.Data4[2],
1823                                       hdr.if_id.Data4[3],
1824                                       hdr.if_id.Data4[4],
1825                                       hdr.if_id.Data4[5],
1826                                       hdr.if_id.Data4[6],
1827                                       hdr.if_id.Data4[7]);
1828         offset += 16;
1829
1830         proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
1831                                       offset, 16, "HMMM",
1832                                       "Activity: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1833                                       hdr.act_id.Data1, hdr.act_id.Data2, hdr.act_id.Data3,
1834                                       hdr.act_id.Data4[0],
1835                                       hdr.act_id.Data4[1],
1836                                       hdr.act_id.Data4[2],
1837                                       hdr.act_id.Data4[3],
1838                                       hdr.act_id.Data4[4],
1839                                       hdr.act_id.Data4[5],
1840                                       hdr.act_id.Data4[6],
1841                                       hdr.act_id.Data4[7]);
1842         offset += 16;
1843
1844         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_server_boot, tvb, offset, 4, hdr.server_boot);
1845         offset += 4;
1846
1847         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
1848         offset += 4;
1849
1850         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
1851         offset += 4;
1852
1853         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
1854         offset += 2;
1855
1856         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
1857         offset += 2;
1858
1859         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
1860         offset += 2;
1861
1862         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
1863         offset += 2;
1864
1865         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
1866         offset += 2;
1867
1868         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
1869         offset++;
1870
1871         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
1872         offset++;
1873     }
1874     /* 
1875      * keeping track of the conversation shouldn't really be necessary
1876      * for connectionless packets, because everything we need to know
1877      * to dissect is in the header for each packet.  Unfortunately,
1878      * Microsoft's implementation is buggy and often puts the
1879      * completely wrong if_id in the header.  go figure.  So, keep
1880      * track of the seqnum and use that if possible.  Note: that's not
1881      * completely correct.  It should really be done based on both the
1882      * activity_id and seqnum.  I haven't seen anywhere that it would
1883      * make a difference, but for future reference...
1884      */
1885     conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
1886                               pinfo->srcport, pinfo->destport, 0);
1887     if (!conv) {
1888         conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
1889                                  pinfo->srcport, pinfo->destport, 0);
1890     }
1891
1892     /*
1893      * Packet type specific stuff is next.
1894      */
1895
1896     switch (hdr.ptype) {
1897         dcerpc_info di;
1898         dcerpc_call_value *value, v;
1899
1900     case PDU_REQ:
1901
1902         if(!(pinfo->fd->flags.visited)){
1903                 dcerpc_call_value *call_value;
1904                 dcerpc_call_key *call_key;
1905
1906                 call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
1907                 call_key->conv=conv;
1908                 call_key->call_id=hdr.seqnum;
1909                 call_key->smb_fid=get_smb_fid(pinfo->private_data);
1910
1911                 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
1912                 call_value->uuid = hdr.if_id;
1913                 call_value->ver = hdr.if_ver;
1914                 call_value->opnum = hdr.opnum;
1915                 call_value->req_frame=pinfo->fd->num;
1916                 call_value->rep_frame=-1;
1917                 call_value->max_ptr=0;
1918                 call_value->private_data = NULL;
1919                 g_hash_table_insert (dcerpc_calls, call_key, call_value);
1920
1921                 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);       
1922         }
1923
1924         value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
1925         if (!value) {
1926             v.uuid = hdr.if_id;
1927             v.ver = hdr.if_ver;
1928             v.opnum = hdr.opnum;
1929             v.req_frame = pinfo->fd->num;
1930             v.rep_frame = -1;
1931             v.max_ptr = 0;
1932             v.private_data=NULL;
1933             value = &v;
1934         }
1935
1936         di.conv = conv;
1937         di.call_id = hdr.seqnum;
1938         di.smb_fid = -1;
1939         di.request = TRUE;
1940         di.call_data = value;
1941
1942         dcerpc_try_handoff (pinfo, tree, dcerpc_tree, tvb, offset,
1943                             hdr.opnum, TRUE, hdr.drep, &di);
1944         break;
1945     case PDU_RESP:
1946         if(!(pinfo->fd->flags.visited)){
1947                 dcerpc_call_value *call_value;
1948                 dcerpc_call_key call_key;
1949
1950                 call_key.conv=conv;
1951                 call_key.call_id=hdr.seqnum;
1952                 call_key.smb_fid=get_smb_fid(pinfo->private_data);
1953
1954                 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
1955                         g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
1956                         if(call_value->rep_frame==-1){
1957                                 call_value->rep_frame=pinfo->fd->num;
1958                         }
1959                 }
1960         }
1961
1962         value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
1963         if (!value) {
1964             v.uuid = hdr.if_id;
1965             v.ver = hdr.if_ver;
1966             v.opnum = hdr.opnum;
1967             v.req_frame=-1;
1968             v.rep_frame=pinfo->fd->num;
1969             v.private_data=NULL;
1970             value = &v;
1971         }
1972
1973         di.conv = conv;
1974         di.call_id = 0; 
1975         di.smb_fid = -1;
1976         di.request = FALSE;
1977         di.call_data = value;
1978
1979         dcerpc_try_handoff (pinfo, tree, dcerpc_tree, tvb, offset,
1980                             value->opnum, FALSE, hdr.drep, &di);
1981         break;
1982     }
1983
1984     return TRUE;
1985 }
1986
1987 static void
1988 dcerpc_init_protocol (void)
1989 {
1990         /* structures and data for BIND */
1991         if (dcerpc_binds){
1992                 g_hash_table_destroy (dcerpc_binds);
1993         }
1994         dcerpc_binds = g_hash_table_new (dcerpc_bind_hash, dcerpc_bind_equal);
1995
1996         if (dcerpc_bind_key_chunk){
1997                 g_mem_chunk_destroy (dcerpc_bind_key_chunk);
1998         }
1999         dcerpc_bind_key_chunk = g_mem_chunk_new ("dcerpc_bind_key_chunk",
2000                                              sizeof (dcerpc_bind_key),
2001                                              200 * sizeof (dcerpc_bind_key),
2002                                              G_ALLOC_ONLY);
2003         if (dcerpc_bind_value_chunk){
2004                 g_mem_chunk_destroy (dcerpc_bind_value_chunk);
2005         }
2006         dcerpc_bind_value_chunk = g_mem_chunk_new ("dcerpc_bind_value_chunk",
2007                                              sizeof (dcerpc_bind_value),
2008                                              200 * sizeof (dcerpc_bind_value),
2009                                              G_ALLOC_ONLY);
2010         /* structures and data for CALL */
2011         if (dcerpc_calls){
2012                 g_hash_table_destroy (dcerpc_calls);
2013         }
2014         dcerpc_calls = g_hash_table_new (dcerpc_call_hash, dcerpc_call_equal);
2015         if (dcerpc_call_key_chunk){
2016                 g_mem_chunk_destroy (dcerpc_call_key_chunk);
2017         }
2018         dcerpc_call_key_chunk = g_mem_chunk_new ("dcerpc_call_key_chunk",
2019                                              sizeof (dcerpc_call_key),
2020                                              200 * sizeof (dcerpc_call_key),
2021                                              G_ALLOC_ONLY);
2022         if (dcerpc_call_value_chunk){
2023                 g_mem_chunk_destroy (dcerpc_call_value_chunk);
2024         }
2025         dcerpc_call_value_chunk = g_mem_chunk_new ("dcerpc_call_value_chunk",
2026                                              sizeof (dcerpc_call_value),
2027                                              200 * sizeof (dcerpc_call_value),
2028                                              G_ALLOC_ONLY);
2029
2030         /* structure and data for MATCHED */
2031         if (dcerpc_matched){
2032                 g_hash_table_destroy (dcerpc_matched);
2033         }
2034         dcerpc_matched = g_hash_table_new (dcerpc_matched_hash, dcerpc_matched_equal);
2035
2036 }
2037
2038 void
2039 proto_register_dcerpc (void)
2040 {
2041     static hf_register_info hf[] = {
2042         { &hf_dcerpc_request_in,
2043                 { "Request in", "dcerpc.request_in", FT_UINT32, BASE_DEC,
2044                 NULL, 0, "This packet is a response to the packet in this frame", HFILL }},
2045         { &hf_dcerpc_response_in, 
2046                 { "Response in", "dcerpc.response_in", FT_UINT32, BASE_DEC,
2047                 NULL, 0, "The response to this packet is in this packet", HFILL }},
2048         { &hf_dcerpc_referent_id, 
2049                 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
2050                 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
2051         { &hf_dcerpc_ver,
2052           { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2053         { &hf_dcerpc_ver_minor,
2054           { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2055         { &hf_dcerpc_packet_type,
2056           { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_HEX, VALS (pckt_vals), 0x0, "", HFILL }},
2057         { &hf_dcerpc_cn_flags,
2058           { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
2059         { &hf_dcerpc_cn_flags_first_frag,
2060           { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x1, "", HFILL }},
2061         { &hf_dcerpc_cn_flags_last_frag,
2062           { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x2, "", HFILL }},
2063         { &hf_dcerpc_cn_flags_cancel_pending,
2064           { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x4, "", HFILL }},
2065         { &hf_dcerpc_cn_flags_reserved,
2066           { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x8, "", HFILL }},
2067         { &hf_dcerpc_cn_flags_mpx,
2068           { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x10, "", HFILL }},
2069         { &hf_dcerpc_cn_flags_dne,
2070           { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x20, "", HFILL }},
2071         { &hf_dcerpc_cn_flags_maybe,
2072           { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x40, "", HFILL }},
2073         { &hf_dcerpc_cn_flags_object,
2074           { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x80, "", HFILL }},
2075         { &hf_dcerpc_drep,
2076           { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
2077         { &hf_dcerpc_drep_byteorder,
2078           { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS (drep_byteorder_vals), 0x0, "", HFILL }},
2079         { &hf_dcerpc_drep_character,
2080           { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS (drep_character_vals), 0x0, "", HFILL }},
2081         { &hf_dcerpc_drep_fp,
2082           { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS (drep_fp_vals), 0x0, "", HFILL }},
2083         { &hf_dcerpc_cn_frag_len,
2084           { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2085         { &hf_dcerpc_cn_auth_len,
2086           { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2087         { &hf_dcerpc_cn_call_id,
2088           { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2089         { &hf_dcerpc_cn_max_xmit,
2090           { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2091         { &hf_dcerpc_cn_max_recv,
2092           { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2093         { &hf_dcerpc_cn_assoc_group,
2094           { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
2095         { &hf_dcerpc_cn_num_ctx_items,
2096           { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2097         { &hf_dcerpc_cn_ctx_id,
2098           { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2099         { &hf_dcerpc_cn_num_trans_items,
2100           { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2101         { &hf_dcerpc_cn_bind_if_id,
2102           { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2103         { &hf_dcerpc_cn_bind_if_ver,
2104           { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2105         { &hf_dcerpc_cn_bind_if_ver_minor,
2106           { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2107         { &hf_dcerpc_cn_bind_trans_id,
2108           { "Transfer Syntax", "dcerpc.cn_bind_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2109         { &hf_dcerpc_cn_bind_trans_ver,
2110           { "Syntax ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2111         { &hf_dcerpc_cn_alloc_hint,
2112           { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2113         { &hf_dcerpc_cn_sec_addr_len,
2114           { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2115         { &hf_dcerpc_cn_num_results,
2116           { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2117         { &hf_dcerpc_cn_ack_result,
2118           { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2119         { &hf_dcerpc_cn_ack_reason,
2120           { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2121         { &hf_dcerpc_cn_ack_trans_id,
2122           { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2123         { &hf_dcerpc_cn_ack_trans_ver,
2124           { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2125         { &hf_dcerpc_cn_cancel_count,
2126           { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2127         { &hf_dcerpc_auth_type,
2128           { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2129         { &hf_dcerpc_auth_level,
2130           { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2131         { &hf_dcerpc_auth_pad_len,
2132           { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2133         { &hf_dcerpc_auth_rsrvd,
2134           { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2135         { &hf_dcerpc_auth_ctx_id,
2136           { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2137         { &hf_dcerpc_dg_flags1,
2138           { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
2139         { &hf_dcerpc_dg_flags1_rsrvd_01,
2140           { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x01, "", HFILL }},
2141         { &hf_dcerpc_dg_flags1_last_frag,
2142           { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x02, "", HFILL }},
2143         { &hf_dcerpc_dg_flags1_frag,
2144           { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x04, "", HFILL }},
2145         { &hf_dcerpc_dg_flags1_nofack,
2146           { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x08, "", HFILL }},
2147         { &hf_dcerpc_dg_flags1_maybe,
2148           { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x10, "", HFILL }},
2149         { &hf_dcerpc_dg_flags1_idempotent,
2150           { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x20, "", HFILL }},
2151         { &hf_dcerpc_dg_flags1_broadcast,
2152           { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x40, "", HFILL }},
2153         { &hf_dcerpc_dg_flags1_rsrvd_80,
2154           { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x80, "", HFILL }},
2155         { &hf_dcerpc_dg_flags2,
2156           { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
2157         { &hf_dcerpc_dg_flags2_rsrvd_01,
2158           { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x01, "", HFILL }},
2159         { &hf_dcerpc_dg_flags2_cancel_pending,
2160           { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x02, "", HFILL }},
2161         { &hf_dcerpc_dg_flags2_rsrvd_04,
2162           { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x04, "", HFILL }},
2163         { &hf_dcerpc_dg_flags2_rsrvd_08,
2164           { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x08, "", HFILL }},
2165         { &hf_dcerpc_dg_flags2_rsrvd_10,
2166           { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x10, "", HFILL }},
2167         { &hf_dcerpc_dg_flags2_rsrvd_20,
2168           { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x20, "", HFILL }},
2169         { &hf_dcerpc_dg_flags2_rsrvd_40,
2170           { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x40, "", HFILL }},
2171         { &hf_dcerpc_dg_flags2_rsrvd_80,
2172           { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x80, "", HFILL }},
2173         { &hf_dcerpc_dg_serial_lo,
2174           { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
2175         { &hf_dcerpc_dg_serial_hi,
2176           { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
2177         { &hf_dcerpc_dg_ahint,
2178           { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
2179         { &hf_dcerpc_dg_ihint,
2180           { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
2181         { &hf_dcerpc_dg_frag_len,
2182           { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2183         { &hf_dcerpc_dg_frag_num,
2184           { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2185         { &hf_dcerpc_dg_auth_proto,
2186           { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
2187         { &hf_dcerpc_dg_seqnum,
2188           { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
2189         { &hf_dcerpc_dg_server_boot,
2190           { "Server boot time", "dcerpc.dg_server_boot", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
2191         { &hf_dcerpc_dg_if_ver,
2192           { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2193         { &hf_dcerpc_obj_id,
2194           { "Object", "dcerpc.obj_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2195         { &hf_dcerpc_dg_if_id,
2196           { "Interface", "dcerpc.dg_if_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2197         { &hf_dcerpc_dg_act_id,
2198           { "Activitiy", "dcerpc.dg_act_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2199         { &hf_dcerpc_opnum,
2200           { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2201         { &hf_dcerpc_array_max_count,
2202           { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
2203
2204         { &hf_dcerpc_array_offset,
2205           { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
2206
2207         { &hf_dcerpc_array_actual_count,
2208           { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
2209
2210
2211     };
2212     static gint *ett[] = {
2213         &ett_dcerpc,
2214         &ett_dcerpc_cn_flags,
2215         &ett_dcerpc_drep,
2216         &ett_dcerpc_dg_flags1,
2217         &ett_dcerpc_dg_flags2,
2218         &ett_dcerpc_pointer_data,
2219     };
2220
2221     proto_dcerpc = proto_register_protocol ("DCE RPC", "DCERPC", "dcerpc");
2222     proto_register_field_array (proto_dcerpc, hf, array_length (hf));
2223     proto_register_subtree_array (ett, array_length (ett));
2224     register_init_routine (dcerpc_init_protocol);
2225
2226     prefs_register_bool_preference (prefs_register_protocol (proto_dcerpc, 
2227                                                              NULL),
2228                                     "desegment_dcerpc",
2229                                     "Desegment all DCE/RPC over TCP",
2230                                     "Whether the DCE/RPC dissector should desegment all DCE/RPC over TCP",
2231                                     &dcerpc_cn_desegment);
2232     dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
2233 }
2234
2235 void
2236 proto_reg_handoff_dcerpc (void)
2237 {
2238     heur_dissector_add ("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
2239     heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
2240     heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
2241     heur_dissector_add ("smb_transact", dissect_dcerpc_cn_bs, proto_dcerpc);
2242 }