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