9ca8fec673079f16c9ee12256b51fb909a49d665
[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.26 2002/01/24 09:20:47 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #ifdef HAVE_SYS_TYPES_H
31 #include <sys/types.h>
32 #endif
33
34 #include <string.h>
35 #include <ctype.h>
36
37 #include <glib.h>
38 #include <epan/packet.h>
39 #include "packet-dcerpc.h"
40 #include <epan/conversation.h>
41 #include "prefs.h"
42
43 static const value_string pckt_vals[] = {
44     { 0, "Request"},
45     { 1, "Ping"},
46     { 2, "Response"},
47     { 3, "Fault"},
48     { 4, "Working"},
49     { 5, "Nocall"},
50     { 6, "Reject"},
51     { 7, "Ack"},
52     { 8, "Cl_cancel"},
53     { 9, "Fack"},
54     { 10, "Cancel_ack"},
55     { 11, "Bind"},
56     { 12, "Bind_ack"},
57     { 13, "Bind_nak"},
58     { 14, "Alter_context"},
59     { 15, "Alter_context_resp"},
60     { 16, "AUTH3?"},
61     { 17, "Shutdown"},
62     { 18, "Co_cancel"},
63     { 19, "Orphaned"},
64     { 0,  NULL }
65 };
66
67 static const value_string drep_byteorder_vals[] = {
68     { 0, "Big-endian" },
69     { 1, "Little-endian" },
70     { 0,  NULL }
71 };
72
73 static const value_string drep_character_vals[] = {
74     { 0, "ASCII" },
75     { 1, "EBCDIC" },
76     { 0,  NULL }
77 };
78
79 static const value_string drep_fp_vals[] = {
80     { 0, "IEEE" },
81     { 1, "VAX" },
82     { 2, "Cray" },
83     { 3, "IBM" },
84     { 0,  NULL }
85 };
86
87 static const true_false_string flags_set_truth = {
88   "Set",
89   "Not set"
90 };
91
92 static int proto_dcerpc = -1;
93
94 /* field defines */
95 static int hf_dcerpc_request_in = -1;
96 static int hf_dcerpc_response_in = -1;
97 static int hf_dcerpc_ver = -1;
98 static int hf_dcerpc_ver_minor = -1;
99 static int hf_dcerpc_packet_type = -1;
100 static int hf_dcerpc_cn_flags = -1;
101 static int hf_dcerpc_cn_flags_first_frag = -1;
102 static int hf_dcerpc_cn_flags_last_frag = -1;
103 static int hf_dcerpc_cn_flags_cancel_pending = -1;
104 static int hf_dcerpc_cn_flags_reserved = -1;
105 static int hf_dcerpc_cn_flags_mpx = -1;
106 static int hf_dcerpc_cn_flags_dne = -1;
107 static int hf_dcerpc_cn_flags_maybe = -1;
108 static int hf_dcerpc_cn_flags_object = -1;
109 static int hf_dcerpc_drep = -1;
110 static int hf_dcerpc_drep_byteorder = -1;
111 static int hf_dcerpc_drep_character = -1;
112 static int hf_dcerpc_drep_fp = -1;
113 static int hf_dcerpc_cn_frag_len = -1;
114 static int hf_dcerpc_cn_auth_len = -1;
115 static int hf_dcerpc_cn_call_id = -1;
116 static int hf_dcerpc_cn_max_xmit = -1;
117 static int hf_dcerpc_cn_max_recv = -1;
118 static int hf_dcerpc_cn_assoc_group = -1;
119 static int hf_dcerpc_cn_num_ctx_items = -1;
120 static int hf_dcerpc_cn_ctx_id = -1;
121 static int hf_dcerpc_cn_num_trans_items = -1;
122 static int hf_dcerpc_cn_bind_if_id = -1;
123 static int hf_dcerpc_cn_bind_if_ver = -1;
124 static int hf_dcerpc_cn_bind_if_ver_minor = -1;
125 static int hf_dcerpc_cn_bind_trans_id = -1;
126 static int hf_dcerpc_cn_bind_trans_ver = -1;
127 static int hf_dcerpc_cn_alloc_hint = -1;
128 static int hf_dcerpc_cn_sec_addr_len = -1;
129 static int hf_dcerpc_cn_num_results = -1;
130 static int hf_dcerpc_cn_ack_result = -1;
131 static int hf_dcerpc_cn_ack_reason = -1;
132 static int hf_dcerpc_cn_ack_trans_id = -1;
133 static int hf_dcerpc_cn_ack_trans_ver = -1;
134 static int hf_dcerpc_cn_cancel_count = -1;
135 static int hf_dcerpc_auth_type = -1;
136 static int hf_dcerpc_auth_level = -1;
137 static int hf_dcerpc_auth_pad_len = -1;
138 static int hf_dcerpc_auth_rsrvd = -1;
139 static int hf_dcerpc_auth_ctx_id = -1;
140 static int hf_dcerpc_dg_flags1 = -1;
141 static int hf_dcerpc_dg_flags1_rsrvd_01 = -1;
142 static int hf_dcerpc_dg_flags1_last_frag = -1;
143 static int hf_dcerpc_dg_flags1_frag = -1;
144 static int hf_dcerpc_dg_flags1_nofack = -1;
145 static int hf_dcerpc_dg_flags1_maybe = -1;
146 static int hf_dcerpc_dg_flags1_idempotent = -1;
147 static int hf_dcerpc_dg_flags1_broadcast = -1;
148 static int hf_dcerpc_dg_flags1_rsrvd_80 = -1;
149 static int hf_dcerpc_dg_flags2 = -1;
150 static int hf_dcerpc_dg_flags2_rsrvd_01 = -1;
151 static int hf_dcerpc_dg_flags2_cancel_pending = -1;
152 static int hf_dcerpc_dg_flags2_rsrvd_04 = -1;
153 static int hf_dcerpc_dg_flags2_rsrvd_08 = -1;
154 static int hf_dcerpc_dg_flags2_rsrvd_10 = -1;
155 static int hf_dcerpc_dg_flags2_rsrvd_20 = -1;
156 static int hf_dcerpc_dg_flags2_rsrvd_40 = -1;
157 static int hf_dcerpc_dg_flags2_rsrvd_80 = -1;
158 static int hf_dcerpc_dg_serial_hi = -1;
159 static int hf_dcerpc_obj_id = -1;
160 static int hf_dcerpc_dg_if_id = -1;
161 static int hf_dcerpc_dg_act_id = -1;
162 static int hf_dcerpc_dg_serial_lo = -1;
163 static int hf_dcerpc_dg_ahint = -1;
164 static int hf_dcerpc_dg_ihint = -1;
165 static int hf_dcerpc_dg_frag_len = -1;
166 static int hf_dcerpc_dg_frag_num = -1;
167 static int hf_dcerpc_dg_auth_proto = -1;
168 static int hf_dcerpc_opnum = -1;
169 static int hf_dcerpc_dg_seqnum = -1;
170 static int hf_dcerpc_dg_server_boot = -1;
171 static int hf_dcerpc_dg_if_ver = -1;
172
173 static gint ett_dcerpc = -1;
174 static gint ett_dcerpc_cn_flags = -1;
175 static gint ett_dcerpc_drep = -1;
176 static gint ett_dcerpc_dg_flags1 = -1;
177 static gint ett_dcerpc_dg_flags2 = -1;
178
179 /* try to desegment big DCE/RPC packets over TCP? */
180 static gboolean dcerpc_cn_desegment = TRUE;
181
182
183 /*
184  * Subdissectors
185  */
186
187 /* the registered subdissectors */
188 static GHashTable *dcerpc_uuids;
189
190 typedef struct _dcerpc_uuid_key {
191     e_uuid_t uuid;
192     guint16 ver;
193 } dcerpc_uuid_key;
194
195 typedef struct _dcerpc_uuid_value {
196     int proto;
197     int ett;
198     gchar *name;
199     dcerpc_sub_dissector *procs;
200 } dcerpc_uuid_value;
201
202 static gint
203 dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2)
204 {
205     dcerpc_uuid_key *key1 = (dcerpc_uuid_key *)k1;
206     dcerpc_uuid_key *key2 = (dcerpc_uuid_key *)k2;
207     return ((memcmp (&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
208             && (key1->ver == key2->ver));
209 }
210
211 static guint
212 dcerpc_uuid_hash (gconstpointer k)
213 {
214     dcerpc_uuid_key *key = (dcerpc_uuid_key *)k;
215     /* This isn't perfect, but the Data1 part of these is almost always
216        unique. */
217     return key->uuid.Data1;
218 }
219
220 void
221 dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver,
222                   dcerpc_sub_dissector *procs)
223 {
224     dcerpc_uuid_key *key = g_malloc (sizeof (*key));
225     dcerpc_uuid_value *value = g_malloc (sizeof (*value));
226
227     key->uuid = *uuid;
228     key->ver = ver;
229
230     value->proto = proto;
231     value->ett = ett;
232     value->name = proto_get_protocol_short_name (proto);
233     value->procs = procs;
234
235     g_hash_table_insert (dcerpc_uuids, key, value);
236 }
237
238
239 /*
240  * To keep track of ctx_id mappings.
241  *
242  * Everytime we see a bind call we update this table.
243  * Note that we always specify a SMB FID. For non-SMB transports this
244  * value is 0.
245  */
246 static GHashTable *dcerpc_binds=NULL;
247
248 typedef struct _dcerpc_bind_key {
249     conversation_t *conv;
250     guint16 ctx_id;
251     guint16 smb_fid;
252 } dcerpc_bind_key;
253
254 typedef struct _dcerpc_bind_value {
255         e_uuid_t uuid;
256         guint16 ver;
257 } dcerpc_bind_value;
258
259 static GMemChunk *dcerpc_bind_key_chunk=NULL;
260 static GMemChunk *dcerpc_bind_value_chunk=NULL;
261
262 static gint
263 dcerpc_bind_equal (gconstpointer k1, gconstpointer k2)
264 {
265     dcerpc_bind_key *key1 = (dcerpc_bind_key *)k1;
266     dcerpc_bind_key *key2 = (dcerpc_bind_key *)k2;
267     return (key1->conv == key2->conv
268             && key1->ctx_id == key2->ctx_id
269             && key1->smb_fid == key2->smb_fid);
270 }
271
272 static guint
273 dcerpc_bind_hash (gconstpointer k)
274 {
275     dcerpc_bind_key *key = (dcerpc_bind_key *)k;
276     return ((guint)key->conv) + key->ctx_id + key->smb_fid;
277 }
278
279 /*
280  * To keep track of callid mappings.  Should really use some generic
281  * conversation support instead.
282  */
283 static GHashTable *dcerpc_calls=NULL;
284
285 typedef struct _dcerpc_call_key {
286     conversation_t *conv;
287     guint32 call_id;
288     guint16 smb_fid;
289 } dcerpc_call_key;
290
291 static GMemChunk *dcerpc_call_key_chunk=NULL;
292
293 static GMemChunk *dcerpc_call_value_chunk=NULL;
294
295 static gint
296 dcerpc_call_equal (gconstpointer k1, gconstpointer k2)
297 {
298     dcerpc_call_key *key1 = (dcerpc_call_key *)k1;
299     dcerpc_call_key *key2 = (dcerpc_call_key *)k2;
300     return (key1->conv == key2->conv
301             && key1->call_id == key2->call_id
302             && key1->smb_fid == key2->smb_fid);
303 }
304
305 static guint
306 dcerpc_call_hash (gconstpointer k)
307 {
308     dcerpc_call_key *key = (dcerpc_call_key *)k;
309     return ((guint32)key->conv) + key->call_id + key->smb_fid;
310 }
311
312
313 /* to keep track of matched calls/responses
314    this one uses the same value struct as calls, but the key is the frame id
315 */
316 static GHashTable *dcerpc_matched=NULL;
317 static gint
318 dcerpc_matched_equal (gconstpointer k1, gconstpointer k2)
319 {
320         return (guint32)k1 == (guint32)k2;
321 }
322
323 static guint
324 dcerpc_matched_hash (gconstpointer k)
325 {
326         return (guint32)k;
327 }
328
329
330
331 /*
332  * Utility functions.  Modeled after packet-rpc.c
333  */
334
335 int
336 dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo,
337                       proto_tree *tree, char *drep, 
338                       int hfindex, guint8 *pdata)
339 {
340     guint8 data;
341
342     data = tvb_get_guint8 (tvb, offset);
343     if (tree) {
344         proto_tree_add_item (tree, hfindex, tvb, offset, 1, (drep[0] & 0x10));
345     }
346     if (pdata)
347         *pdata = data;
348     return offset + 1;
349 }
350
351 int
352 dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo,
353                        proto_tree *tree, char *drep, 
354                        int hfindex, guint16 *pdata)
355 {
356     guint16 data;
357
358     data = ((drep[0] & 0x10)
359             ? tvb_get_letohs (tvb, offset)
360             : tvb_get_ntohs (tvb, offset));
361     
362     if (tree) {
363         proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10));
364     }
365     if (pdata)
366         *pdata = data;
367     return offset + 2;
368 }
369
370 int
371 dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo,
372                        proto_tree *tree, char *drep, 
373                        int hfindex, guint32 *pdata)
374 {
375     guint32 data;
376
377     data = ((drep[0] & 0x10)
378             ? tvb_get_letohl (tvb, offset)
379             : tvb_get_ntohl (tvb, offset));
380     
381     if (tree) {
382         proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10));
383     }
384     if (pdata)
385         *pdata = data;
386     return offset+4;
387 }
388
389 /*
390  * a couple simpler things
391  */
392 guint16
393 dcerpc_tvb_get_ntohs (tvbuff_t *tvb, gint offset, char *drep)
394 {
395     if (drep[0] & 0x10) {
396         return tvb_get_letohs (tvb, offset);
397     } else {
398         return tvb_get_ntohs (tvb, offset);
399     }
400 }
401
402 guint32
403 dcerpc_tvb_get_ntohl (tvbuff_t *tvb, gint offset, char *drep)
404 {
405     if (drep[0] & 0x10) {
406         return tvb_get_letohl (tvb, offset);
407     } else {
408         return tvb_get_ntohl (tvb, offset);
409     }
410 }
411
412 void
413 dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, char *drep, e_uuid_t *uuid)
414 {
415     unsigned int i;
416     uuid->Data1 = dcerpc_tvb_get_ntohl (tvb, offset, drep);
417     uuid->Data2 = dcerpc_tvb_get_ntohs (tvb, offset+4, drep);
418     uuid->Data3 = dcerpc_tvb_get_ntohs (tvb, offset+6, drep);
419
420     for (i=0; i<sizeof (uuid->Data4); i++) {
421         uuid->Data4[i] = tvb_get_guint8 (tvb, offset+8+i);
422     }
423 }
424
425 static int
426 dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
427                     proto_tree *dcerpc_tree,
428                     tvbuff_t *tvb, gint offset,
429                     guint16 opnum, gboolean is_rqst,
430                     char *drep, dcerpc_info *info)
431 {
432     dcerpc_uuid_key key;
433     dcerpc_uuid_value *sub_proto;
434     int length;
435     proto_tree *sub_tree = NULL;
436     dcerpc_sub_dissector *proc;
437     gchar *name = NULL;
438     dcerpc_dissect_fnct_t *sub_dissect;
439     const char *saved_proto;
440     void *saved_private_data;
441
442     key.uuid = info->call_data->uuid;
443     key.ver = info->call_data->ver;
444
445     
446     if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == NULL
447          || !proto_is_protocol_enabled(sub_proto->proto)) {
448         /*
449          * We don't have a dissector for this UUID, or the protocol
450          * for that UUID is disabled.
451          */
452         length = tvb_length_remaining (tvb, offset);
453         if (length > 0) {
454             proto_tree_add_text (dcerpc_tree, tvb, offset, length,
455                                  "Stub data (%d byte%s)", length,
456                                  plurality(length, "", "s"));
457         }
458         return -1;
459     }
460
461     if (tree) {
462         proto_item *sub_item;
463         sub_item = proto_tree_add_item (tree, sub_proto->proto, tvb, offset, 
464                                         -1, FALSE);
465
466         if (sub_item) {
467             sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
468         }
469         
470     }
471     for (proc = sub_proto->procs; proc->name; proc++) {
472         if (proc->num == opnum) {
473             name = proc->name;
474             break;
475         }
476     }
477
478     if (!name)
479         name = "Unknown?!";
480
481     if (check_col (pinfo->cinfo, COL_INFO)) {
482         col_add_fstr (pinfo->cinfo, COL_INFO, "%s %s(...)",
483                       is_rqst ? "rqst" : "rply", name);
484     }
485
486     if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
487         col_set_str (pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
488     }
489
490     sub_dissect = is_rqst ? proc->dissect_rqst : proc->dissect_resp;
491     if (sub_dissect) {
492         saved_proto = pinfo->current_proto;
493         saved_private_data = pinfo->private_data;
494         pinfo->current_proto = sub_proto->name;
495         pinfo->private_data = (void *)info;
496
497         sub_dissect (tvb, offset, pinfo, sub_tree, drep);
498
499         pinfo->current_proto = saved_proto;
500         pinfo->private_data = saved_private_data;
501     } else {
502         length = tvb_length_remaining (tvb, offset);
503         if (length > 0) {
504             proto_tree_add_text (sub_tree, tvb, offset, length,
505                                  "Stub data (%d byte%s)", length,
506                                  plurality(length, "", "s"));
507         }
508     }
509     return 0;
510 }
511
512 static int
513 dissect_dcerpc_cn_auth (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
514                         e_dce_cn_common_hdr_t *hdr)
515 {
516     int offset;
517     guint8 auth_pad_len;
518
519     /*
520      * The authentication information is at the *end* of the PDU; in
521      * request and response PDUs, the request and response stub data
522      * come before it.
523      *
524      * If the full packet is here, and we've got an auth len, and it's
525      * valid, then dissect the auth info
526      */
527     if (tvb_length (tvb) >= hdr->frag_len
528         && hdr->auth_len
529         && (hdr->auth_len + 8 <= hdr->frag_len)) {
530
531         offset = hdr->frag_len - (hdr->auth_len + 8);
532         
533         offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
534                                        hf_dcerpc_auth_type, NULL);
535         offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
536                                        hf_dcerpc_auth_level, NULL);
537         offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
538                                        hf_dcerpc_auth_pad_len, &auth_pad_len);
539         offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
540                                        hf_dcerpc_auth_rsrvd, NULL);
541         offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
542                                         hf_dcerpc_auth_ctx_id, NULL);
543
544         proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len, "Auth Data");
545
546         /* figure out where the auth padding starts */
547         offset = hdr->frag_len - (hdr->auth_len + 8 + auth_pad_len);
548         if (offset > 0 && auth_pad_len) {
549             proto_tree_add_text (dcerpc_tree, tvb, offset, 
550                                  auth_pad_len, "Auth padding");
551             return hdr->auth_len + 8 + auth_pad_len;
552         } else {
553             return hdr->auth_len + 8;
554         }
555     } else {
556         return 0;
557     }
558 }
559
560
561 /* We need to hash in the SMB fid number to generate a unique hash table
562    key as DCERPC over SMB allows several pipes over the same TCP/IP
563    socket. */
564
565 static guint16 get_smb_fid (void *private_data)
566 {
567     dcerpc_private_info *priv = (dcerpc_private_info *)private_data;
568         
569     if (!priv)
570         return 0;       /* Nothing to see here */
571
572     /* DCERPC over smb */
573
574     if (priv->transport_type == DCERPC_TRANSPORT_SMB)
575         return priv->data.smb.fid;
576
577     /* Some other transport... */
578
579     return 0;
580 }
581
582 /*
583  * Connection oriented packet types
584  */
585
586 static void
587 dissect_dcerpc_cn_bind (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
588                         e_dce_cn_common_hdr_t *hdr)
589 {
590     conversation_t *conv = NULL;
591     guint8 num_ctx_items;
592     guint i;
593     gboolean saw_ctx_item = FALSE;
594     guint16 ctx_id;
595     guint16 num_trans_items;
596     guint j;
597     e_uuid_t if_id;
598     e_uuid_t trans_id;
599     guint32 trans_ver;
600     guint16 if_ver, if_ver_minor;
601     int offset = 16;
602
603     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
604                                     hf_dcerpc_cn_max_xmit, NULL);
605
606     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
607                                     hf_dcerpc_cn_max_recv, NULL);
608
609     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
610                                     hf_dcerpc_cn_assoc_group, NULL);
611
612     offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
613                                     hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
614
615     /* padding */
616     offset += 3;
617
618     for (i = 0; i < num_ctx_items; i++) {
619       offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
620                                       hf_dcerpc_cn_ctx_id, &ctx_id);
621
622       offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
623                                       hf_dcerpc_cn_num_trans_items, &num_trans_items);
624
625       dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
626       if (dcerpc_tree) {
627           proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_if_id, tvb,
628                                         offset, 16, "HMMM",
629                                         "Interface UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
630                                         if_id.Data1, if_id.Data2, if_id.Data3,
631                                         if_id.Data4[0], if_id.Data4[1],
632                                         if_id.Data4[2], if_id.Data4[3],
633                                         if_id.Data4[4], if_id.Data4[5],
634                                         if_id.Data4[6], if_id.Data4[7]);
635       }
636       offset += 16;
637
638       if (hdr->drep[0] & 0x10) {
639           offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
640                                           hf_dcerpc_cn_bind_if_ver, &if_ver);
641           offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
642                                           hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
643       } else {
644           offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
645                                           hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
646           offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
647                                           hf_dcerpc_cn_bind_if_ver, &if_ver);
648       }
649
650       if (!saw_ctx_item) {
651         conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
652                                   pinfo->srcport, pinfo->destport, 0);
653         if (conv == NULL) {
654             conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
655                                      pinfo->srcport, pinfo->destport, 0);
656         }
657
658         /* if this is the first time we see this packet, we need to
659            update the dcerpc_binds table so that any later calls can
660            match to the interface.
661            XXX We assume that BINDs will NEVER be fragmented.
662         */
663         if(!(pinfo->fd->flags.visited)){
664                 dcerpc_bind_key *key;
665                 dcerpc_bind_value *value;
666
667                 key = g_mem_chunk_alloc (dcerpc_bind_key_chunk);
668                 key->conv = conv;
669                 key->ctx_id = ctx_id;
670                 key->smb_fid = get_smb_fid(pinfo->private_data);
671
672                 value = g_mem_chunk_alloc (dcerpc_bind_value_chunk);
673                 value->uuid = if_id;
674                 value->ver = if_ver;
675
676                 /* add this entry to the bind table, first removing any
677                    previous ones that are identical
678                  */
679                 if(g_hash_table_lookup(dcerpc_binds, key)){
680                         g_hash_table_remove(dcerpc_binds, key);
681                 }
682                 g_hash_table_insert (dcerpc_binds, key, value);
683         }
684
685         if (check_col (pinfo->cinfo, COL_INFO)) {
686           col_add_fstr (pinfo->cinfo, COL_INFO, "%s: UUID %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %d.%d",
687                         hdr->ptype == PDU_BIND ? "Bind" : "Alter Ctx",
688                         if_id.Data1, if_id.Data2, if_id.Data3,
689                         if_id.Data4[0], if_id.Data4[1],
690                         if_id.Data4[2], if_id.Data4[3],
691                         if_id.Data4[4], if_id.Data4[5],
692                         if_id.Data4[6], if_id.Data4[7],
693                         if_ver, if_ver_minor);
694         }
695         saw_ctx_item = TRUE;
696       }
697
698       for (j = 0; j < num_trans_items; j++) {
699         dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
700         if (dcerpc_tree) {
701             proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_trans_id, tvb,
702                                           offset, 16, "HMMM",
703                                           "Transfer Syntax: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
704                                           trans_id.Data1, trans_id.Data2, trans_id.Data3,
705                                           trans_id.Data4[0], trans_id.Data4[1],
706                                           trans_id.Data4[2], trans_id.Data4[3],
707                                           trans_id.Data4[4], trans_id.Data4[5],
708                                           trans_id.Data4[6], trans_id.Data4[7]);
709         }
710         offset += 16;
711
712         offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
713                                         hf_dcerpc_cn_bind_trans_ver, &trans_ver);
714       }
715     }
716
717     dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr);
718 }
719
720 static void
721 dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
722                             e_dce_cn_common_hdr_t *hdr)
723 {
724     guint16 max_xmit, max_recv;
725     guint16 sec_addr_len;
726     guint8 num_results;
727     guint i;
728     guint16 result;
729     guint16 reason;
730     e_uuid_t trans_id;
731     guint32 trans_ver;
732
733     int offset = 16;
734
735     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
736                                     hf_dcerpc_cn_max_xmit, &max_xmit);
737
738     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
739                                     hf_dcerpc_cn_max_recv, &max_recv);
740
741     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
742                                     hf_dcerpc_cn_assoc_group, NULL);
743
744     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
745                                     hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
746     offset += sec_addr_len;
747
748     if (offset % 4) {
749         offset += 4 - offset % 4;
750     }
751
752     offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
753                                    hf_dcerpc_cn_num_results, &num_results);
754
755     /* padding */
756     offset += 3;
757
758     for (i = 0; i < num_results; i++) {
759         offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, 
760                                         hdr->drep, hf_dcerpc_cn_ack_result,
761                                         &result);
762         offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, 
763                                         hdr->drep, hf_dcerpc_cn_ack_reason,
764                                         &reason);
765
766         dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
767         if (dcerpc_tree) {
768             proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_ack_trans_id, tvb,
769                                           offset, 16, "HMMM",
770                                           "Transfer Syntax: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
771                                           trans_id.Data1, trans_id.Data2, trans_id.Data3,
772                                           trans_id.Data4[0], trans_id.Data4[1],
773                                           trans_id.Data4[2], trans_id.Data4[3],
774                                           trans_id.Data4[4], trans_id.Data4[5],
775                                           trans_id.Data4[6], trans_id.Data4[7]);
776         }
777         offset += 16;
778
779         offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
780                                         hf_dcerpc_cn_ack_trans_ver, &trans_ver);
781     }
782     
783     dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr);
784
785     if (check_col (pinfo->cinfo, COL_INFO)) {
786         if (num_results != 0 && result == 0) {
787             col_add_fstr (pinfo->cinfo, COL_INFO, "%s ack: accept  max_xmit: %d  max_recv: %d",
788                           hdr->ptype == PDU_BIND_ACK ? "Bind" : "Alter ctx",
789                           max_xmit, max_recv);
790         } else {
791             /* FIXME: should put in reason */
792             col_add_fstr (pinfo->cinfo, COL_INFO, "%s ack: %s",
793                           hdr->ptype == PDU_BIND_ACK ? "Bind" : "Alter ctx",
794                           result == 1 ? "User reject" :
795                           result == 2 ? "Provider reject" :
796                           "Unknown");
797         }
798     }
799 }
800
801 static void
802 dissect_dcerpc_cn_rqst (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
803                         proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
804 {
805     conversation_t *conv;
806     guint16 ctx_id;
807     guint16 opnum;
808     e_uuid_t obj_id;
809     int auth_sz = 0;
810     int offset = 16;
811
812     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
813                                     hf_dcerpc_cn_alloc_hint, NULL);
814
815     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
816                                     hf_dcerpc_cn_ctx_id, &ctx_id);
817
818     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
819                                     hf_dcerpc_opnum, &opnum);
820
821     if (check_col (pinfo->cinfo, COL_INFO)) {
822         col_add_fstr (pinfo->cinfo, COL_INFO, "Request: opnum: %d  ctx_id:%d",
823                          opnum, ctx_id);
824     }
825
826     if (hdr->flags & 0x80) {
827         dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id);
828         if (dcerpc_tree) {
829             proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
830                                           offset, 16, "HMMM",
831                                           "Object UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
832                                           obj_id.Data1, obj_id.Data2, obj_id.Data3,
833                                           obj_id.Data4[0],
834                                           obj_id.Data4[1],
835                                           obj_id.Data4[2],
836                                           obj_id.Data4[3],
837                                           obj_id.Data4[4],
838                                           obj_id.Data4[5],
839                                           obj_id.Data4[6],
840                                           obj_id.Data4[7]);
841         }
842         offset += 16;
843     }
844
845     auth_sz = dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr);
846
847     conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
848                               pinfo->srcport, pinfo->destport, 0);
849     if (!conv) {
850
851     } else {
852         dcerpc_call_value *value;
853         int length, reported_length, stub_length;
854         dcerpc_info di;
855
856         /* !!! we can NOT check flags.visited here since this will interact
857            badly with when SMB handles (i.e. calls the subdissector)
858            and desegmented pdu's .
859            Instead we check if this pdu is already in the matched table or not
860         */
861         if(!g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num)){
862                 dcerpc_bind_key bind_key;
863                 dcerpc_bind_value *bind_value;
864
865                 bind_key.conv=conv;
866                 bind_key.ctx_id=ctx_id;
867                 bind_key.smb_fid=get_smb_fid(pinfo->private_data);
868
869                 if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key))){
870                         dcerpc_call_key *call_key;
871                         dcerpc_call_value *call_value;
872
873                         /* We found the binding so just add the call
874                            to both the call table and the matched table
875                         */
876                         call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
877                         call_key->conv=conv;
878                         call_key->call_id=hdr->call_id;
879                         call_key->smb_fid=get_smb_fid(pinfo->private_data);
880
881                         /* if there is already a matching call in the table
882                            remove it so it is replaced with the new one */
883                         if(g_hash_table_lookup(dcerpc_calls, call_key)){
884                                 g_hash_table_remove(dcerpc_calls, call_key);
885                         }
886
887                         call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
888                         call_value->uuid = bind_value->uuid;
889                         call_value->ver = bind_value->ver;
890                         call_value->opnum = opnum;
891                         call_value->req_frame=pinfo->fd->num;
892                         call_value->rep_frame=-1;
893                         call_value->private_data = NULL;
894                         g_hash_table_insert (dcerpc_calls, call_key, call_value);
895
896                         g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);       
897                 }
898         }
899
900         value=g_hash_table_lookup (dcerpc_matched, (void *)pinfo->fd->num);
901
902
903         if (value) {
904
905             /* handoff this call */
906             length = tvb_length_remaining(tvb, offset);
907             reported_length = tvb_reported_length_remaining(tvb, offset);
908             stub_length = hdr->frag_len - offset - auth_sz;
909             if (length > stub_length)
910               length = stub_length;
911             if (reported_length > stub_length)
912               reported_length = stub_length;
913             di.conv = conv;
914             di.call_id = hdr->call_id;
915             di.smb_fid = get_smb_fid(pinfo->private_data);
916             di.call_data = value;
917
918             if(value->rep_frame!=-1){
919                 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in, 
920                                     tvb, 0, 0, value->rep_frame);
921             }
922
923             dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
924                                 tvb_new_subset (tvb, offset, length,
925                                                 reported_length),
926                                 0, opnum, TRUE, hdr->drep, &di);
927         }
928     }
929 }
930
931 static void
932 dissect_dcerpc_cn_resp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
933                         proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
934 {
935     dcerpc_call_value *value = NULL;
936     conversation_t *conv;
937     guint16 ctx_id;
938     int auth_sz = 0;
939     int offset = 16;
940
941     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
942                                     hf_dcerpc_cn_alloc_hint, NULL);
943
944     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
945                                     hf_dcerpc_cn_ctx_id, &ctx_id);
946
947     if (check_col (pinfo->cinfo, COL_INFO)) {
948         col_add_fstr (pinfo->cinfo, COL_INFO, "Response: call_id: %d  ctx_id:%d",
949                       hdr->call_id, ctx_id);
950     }
951
952     offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
953                                    hf_dcerpc_cn_cancel_count, NULL);
954     /* padding */
955     offset++;
956
957     auth_sz = dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr);
958
959     conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
960                               pinfo->srcport, pinfo->destport, 0);
961     if (!conv) {
962         /* no point in creating one here, really */
963     } else {
964
965         /* !!! we can NOT check flags.visited here since this will interact
966            badly with when SMB handles (i.e. calls the subdissector)
967            and desegmented pdu's .
968            Instead we check if this pdu is already in the matched table or not
969         */
970         if(!g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num)){
971                 dcerpc_call_key call_key;
972                 dcerpc_call_value *call_value;
973
974                 call_key.conv=conv;
975                 call_key.call_id=hdr->call_id;
976                 call_key.smb_fid=get_smb_fid(pinfo->private_data);
977
978                 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
979                         g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
980                         if(call_value->rep_frame==-1){
981                                 call_value->rep_frame=pinfo->fd->num;
982                         }
983
984                 }
985         }
986
987         value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
988
989         if (value) {
990             int length, reported_length, stub_length;
991             dcerpc_info di;
992
993             /* handoff this call */
994             length = tvb_length_remaining(tvb, offset);
995             reported_length = tvb_reported_length_remaining(tvb, offset);
996             stub_length = hdr->frag_len - offset - auth_sz;
997             if (length > stub_length)
998               length = stub_length;
999             if (reported_length > stub_length)
1000               reported_length = stub_length;
1001             di.conv = conv;
1002             di.call_id = hdr->call_id;
1003             di.smb_fid = get_smb_fid(pinfo->private_data);
1004             di.call_data = value;
1005
1006             if(value->req_frame!=-1){
1007                 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in, 
1008                                     tvb, 0, 0, value->req_frame);
1009             }
1010
1011             dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
1012                                 tvb_new_subset (tvb, offset, length,
1013                                                 reported_length),
1014                                 0, value->opnum, FALSE, hdr->drep, &di);
1015         }
1016     }
1017 }
1018
1019 /*
1020  * DCERPC dissector for connection oriented calls
1021  */
1022 static int
1023 dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
1024                    proto_tree *tree, gboolean can_desegment)
1025 {
1026     static char nulls[4] = { 0 };
1027     int start_offset;
1028     int padding = 0;
1029     proto_item *ti = NULL;
1030     proto_item *tf = NULL;
1031     proto_tree *dcerpc_tree = NULL;
1032     proto_tree *cn_flags_tree = NULL;
1033     proto_tree *drep_tree = NULL;
1034     e_dce_cn_common_hdr_t hdr;
1035
1036     /*
1037      * when done over nbt, dcerpc requests are padded with 4 bytes of null
1038      * data for some reason.
1039      *
1040      * XXX - if that's always the case, the right way to do this would
1041      * be to have a "dissect_dcerpc_cn_nb" routine which strips off
1042      * the 4 bytes of null padding, and make that the dissector
1043      * used for "netbios".
1044      */
1045     if (tvb_bytes_exist (tvb, offset, 4) &&
1046         tvb_memeql (tvb, offset, nulls, 4) == 0) {
1047
1048         /*
1049          * Skip the padding.
1050          */
1051         offset += 4;
1052         padding += 4;
1053     }
1054
1055     /*
1056      * Check if this looks like a C/O DCERPC call
1057      */
1058     if (!tvb_bytes_exist (tvb, offset, sizeof (hdr))) {
1059         return -1;
1060     }
1061     start_offset = offset;
1062     hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
1063     if (hdr.rpc_ver != 5)
1064         return -1;
1065     hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
1066     if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
1067         return -1;
1068     hdr.ptype = tvb_get_guint8 (tvb, offset++);
1069     if (hdr.ptype > 19)
1070         return -1;
1071
1072     if (check_col (pinfo->cinfo, COL_PROTOCOL))
1073         col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
1074     if (check_col (pinfo->cinfo, COL_INFO))
1075         col_set_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
1076
1077     hdr.flags = tvb_get_guint8 (tvb, offset++);
1078     tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
1079     offset += sizeof (hdr.drep);
1080
1081     hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1082     offset += 2;
1083     hdr.auth_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1084     offset += 2;
1085     hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
1086     offset += 4;
1087
1088     offset = start_offset;
1089     if (can_desegment && pinfo->can_desegment
1090         && hdr.frag_len > tvb_length_remaining (tvb, offset)) {
1091         pinfo->desegment_offset = offset;
1092         pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, offset);
1093         return 0;       /* desegmentation required */
1094     }
1095
1096     if (tree) {
1097         ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE);
1098         if (ti) {
1099             dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
1100         }
1101         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver);
1102         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset++, 1, hdr.rpc_ver_minor);
1103         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype);
1104         tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
1105         cn_flags_tree = proto_item_add_subtree (tf, ett_dcerpc_cn_flags);
1106         if (cn_flags_tree) {
1107             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
1108             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
1109             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
1110             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
1111             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
1112             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
1113             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
1114             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
1115         }
1116         offset++;
1117
1118         tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
1119         drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
1120         if (drep_tree) {
1121             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
1122             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
1123             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
1124         }
1125         offset += sizeof (hdr.drep);
1126
1127         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
1128         offset += 2;
1129
1130         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
1131         offset += 2;
1132
1133         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
1134         offset += 4;
1135     }
1136
1137
1138     /*
1139      * Packet type specific stuff is next.
1140      */
1141     switch (hdr.ptype) {
1142     case PDU_BIND:
1143     case PDU_ALTER:
1144         dissect_dcerpc_cn_bind (tvb, pinfo, dcerpc_tree, &hdr);
1145         break;
1146
1147     case PDU_BIND_ACK:
1148     case PDU_ALTER_ACK:
1149         dissect_dcerpc_cn_bind_ack (tvb, pinfo, dcerpc_tree, &hdr);
1150         break;
1151
1152     case PDU_REQ:
1153         dissect_dcerpc_cn_rqst (tvb, pinfo, dcerpc_tree, tree, &hdr);
1154         break;
1155
1156     case PDU_RESP:
1157         dissect_dcerpc_cn_resp (tvb, pinfo, dcerpc_tree, tree, &hdr);
1158         break;
1159
1160     default:
1161         /* might as well dissect the auth info */
1162         dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr);
1163         break;
1164     }
1165     return hdr.frag_len + padding;
1166 }
1167
1168 /*
1169  * DCERPC dissector for connection oriented calls over packet-oriented
1170  * transports
1171  */
1172 static gboolean
1173 dissect_dcerpc_cn_pk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1174 {
1175     /*
1176      * Only one PDU per transport packet, and only one transport
1177      * packet per PDU.
1178      */
1179     if (dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE) == -1) {
1180         /*
1181          * It wasn't a DCERPC PDU.
1182          */
1183         return FALSE;
1184     } else {
1185         /*
1186          * It was.
1187          */
1188         return TRUE;
1189     }
1190 }
1191
1192 /*
1193  * DCERPC dissector for connection oriented calls over byte-stream
1194  * transports
1195  */
1196 static gboolean
1197 dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1198 {
1199     int offset = 0;
1200     int pdu_len;
1201     gboolean ret = FALSE;
1202
1203     /*
1204      * There may be multiple PDUs per transport packet; keep
1205      * processing them.
1206      */
1207     while (tvb_reported_length_remaining(tvb, offset) != 0) {
1208         pdu_len = dissect_dcerpc_cn (tvb, offset, pinfo, tree,
1209                                      dcerpc_cn_desegment);
1210         if (pdu_len == -1) {
1211             /*
1212              * Not a DCERPC PDU.
1213              */
1214             break;
1215         }
1216
1217         /*
1218          * Well, we've seen at least one DCERPC PDU.
1219          */
1220         ret = TRUE;
1221
1222         if (pdu_len == 0) {
1223             /*
1224              * Desegmentation required - bail now.
1225              */
1226             break;
1227         }
1228
1229         /*
1230          * Step to the next PDU.
1231          */
1232         offset += pdu_len;
1233     }
1234     return ret;
1235 }
1236
1237 /*
1238  * DCERPC dissector for connectionless calls
1239  */
1240 static gboolean
1241 dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1242 {
1243     proto_item *ti = NULL;
1244     proto_item *tf = NULL;
1245     proto_tree *dcerpc_tree = NULL;
1246     proto_tree *dg_flags1_tree = NULL;
1247     proto_tree *dg_flags2_tree = NULL;
1248     proto_tree *drep_tree = NULL;
1249     e_dce_dg_common_hdr_t hdr;
1250     int offset = 0;
1251     conversation_t *conv;
1252
1253     /*
1254      * Check if this looks like a CL DCERPC call.  All dg packets
1255      * have an 80 byte header on them.  Which starts with
1256      * version (4), pkt_type.
1257      */
1258     if (!tvb_bytes_exist (tvb, 0, sizeof (hdr))) {
1259         return FALSE;
1260     }
1261     hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
1262     if (hdr.rpc_ver != 4)
1263         return FALSE;
1264     hdr.ptype = tvb_get_guint8 (tvb, offset++);
1265     if (hdr.ptype > 19)
1266         return FALSE;
1267
1268     if (check_col (pinfo->cinfo, COL_PROTOCOL))
1269         col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
1270     if (check_col (pinfo->cinfo, COL_INFO))
1271         col_set_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
1272
1273     hdr.flags1 = tvb_get_guint8 (tvb, offset++);
1274     hdr.flags2 = tvb_get_guint8 (tvb, offset++);
1275     tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
1276     offset += sizeof (hdr.drep);
1277     hdr.serial_hi = tvb_get_guint8 (tvb, offset++);
1278     dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.obj_id);
1279     offset += 16;
1280     dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.if_id);
1281     offset += 16;
1282     dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.act_id);
1283     offset += 16;
1284     hdr.server_boot = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
1285     offset += 4;
1286     hdr.if_ver = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
1287     offset += 4;
1288     hdr.seqnum = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
1289     offset += 4;
1290     hdr.opnum = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1291     offset += 2;
1292     hdr.ihint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1293     offset += 2;
1294     hdr.ahint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1295     offset += 2;
1296     hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1297     offset += 2;
1298     hdr.frag_num = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1299     offset += 2;
1300     hdr.auth_proto = tvb_get_guint8 (tvb, offset++);
1301     hdr.serial_lo = tvb_get_guint8 (tvb, offset++);
1302
1303     if (tree) {
1304         ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, -1, FALSE);
1305         if (ti) {
1306             dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
1307         }
1308         offset = 0;
1309         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver);
1310
1311         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype);
1312
1313         tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
1314         dg_flags1_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags1);
1315         if (dg_flags1_tree) {
1316             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
1317             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
1318             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
1319             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
1320             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
1321             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
1322             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
1323             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
1324         }
1325         offset++;
1326
1327         tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
1328         dg_flags2_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags2);
1329         if (dg_flags2_tree) {
1330             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
1331             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
1332             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
1333             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
1334             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
1335             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
1336             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
1337             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
1338         }
1339         offset++;
1340
1341         tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
1342         drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
1343         if (drep_tree) {
1344             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
1345             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
1346             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
1347         }
1348         offset += sizeof (hdr.drep);
1349
1350         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset++, 1, hdr.serial_hi);
1351
1352         proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
1353                                       offset, 16, "HMMM",
1354                                       "Object: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1355                                       hdr.obj_id.Data1, hdr.obj_id.Data2, hdr.obj_id.Data3,
1356                                       hdr.obj_id.Data4[0],
1357                                       hdr.obj_id.Data4[1],
1358                                       hdr.obj_id.Data4[2],
1359                                       hdr.obj_id.Data4[3],
1360                                       hdr.obj_id.Data4[4],
1361                                       hdr.obj_id.Data4[5],
1362                                       hdr.obj_id.Data4[6],
1363                                       hdr.obj_id.Data4[7]);
1364         offset += 16;
1365
1366         proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
1367                                       offset, 16, "HMMM",
1368                                       "Interface: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1369                                       hdr.if_id.Data1, hdr.if_id.Data2, hdr.if_id.Data3,
1370                                       hdr.if_id.Data4[0],
1371                                       hdr.if_id.Data4[1],
1372                                       hdr.if_id.Data4[2],
1373                                       hdr.if_id.Data4[3],
1374                                       hdr.if_id.Data4[4],
1375                                       hdr.if_id.Data4[5],
1376                                       hdr.if_id.Data4[6],
1377                                       hdr.if_id.Data4[7]);
1378         offset += 16;
1379
1380         proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
1381                                       offset, 16, "HMMM",
1382                                       "Activity: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1383                                       hdr.act_id.Data1, hdr.act_id.Data2, hdr.act_id.Data3,
1384                                       hdr.act_id.Data4[0],
1385                                       hdr.act_id.Data4[1],
1386                                       hdr.act_id.Data4[2],
1387                                       hdr.act_id.Data4[3],
1388                                       hdr.act_id.Data4[4],
1389                                       hdr.act_id.Data4[5],
1390                                       hdr.act_id.Data4[6],
1391                                       hdr.act_id.Data4[7]);
1392         offset += 16;
1393
1394         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_server_boot, tvb, offset, 4, hdr.server_boot);
1395         offset += 4;
1396
1397         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
1398         offset += 4;
1399
1400         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
1401         offset += 4;
1402
1403         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
1404         offset += 2;
1405
1406         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
1407         offset += 2;
1408
1409         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
1410         offset += 2;
1411
1412         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
1413         offset += 2;
1414
1415         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
1416         offset += 2;
1417
1418         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
1419         offset++;
1420
1421         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
1422         offset++;
1423     }
1424     /* 
1425      * keeping track of the conversation shouldn't really be necessary
1426      * for connectionless packets, because everything we need to know
1427      * to dissect is in the header for each packet.  Unfortunately,
1428      * Microsoft's implementation is buggy and often puts the
1429      * completely wrong if_id in the header.  go figure.  So, keep
1430      * track of the seqnum and use that if possible.  Note: that's not
1431      * completely correct.  It should really be done based on both the
1432      * activity_id and seqnum.  I haven't seen anywhere that it would
1433      * make a difference, but for future reference...
1434      */
1435     conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
1436                               pinfo->srcport, pinfo->destport, 0);
1437     if (!conv) {
1438         conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
1439                                  pinfo->srcport, pinfo->destport, 0);
1440     }
1441
1442     /*
1443      * Packet type specific stuff is next.
1444      */
1445
1446     switch (hdr.ptype) {
1447         dcerpc_info di;
1448         dcerpc_call_value *value, v;
1449
1450     case PDU_REQ:
1451
1452         if(!(pinfo->fd->flags.visited)){
1453                 dcerpc_call_value *call_value;
1454                 dcerpc_call_key *call_key;
1455
1456                 call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
1457                 call_key->conv=conv;
1458                 call_key->call_id=hdr.seqnum;
1459                 call_key->smb_fid=get_smb_fid(pinfo->private_data);
1460
1461                 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
1462                 call_value->uuid = hdr.if_id;
1463                 call_value->ver = hdr.if_ver;
1464                 call_value->opnum = hdr.opnum;
1465                 call_value->req_frame=pinfo->fd->num;
1466                 call_value->rep_frame=-1;
1467                 call_value->private_data = NULL;
1468                 g_hash_table_insert (dcerpc_calls, call_key, call_value);
1469
1470                 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);       
1471         }
1472
1473         value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
1474
1475         di.conv = conv;
1476         di.call_id = hdr.seqnum;
1477         di.smb_fid = -1;
1478         di.call_data = value;
1479
1480         dcerpc_try_handoff (pinfo, tree, dcerpc_tree, tvb, offset,
1481                             hdr.opnum, TRUE, hdr.drep, &di);
1482         break;
1483     case PDU_RESP:
1484         if(!(pinfo->fd->flags.visited)){
1485                 dcerpc_call_value *call_value;
1486                 dcerpc_call_key call_key;
1487
1488                 call_key.conv=conv;
1489                 call_key.call_id=hdr.seqnum;
1490                 call_key.smb_fid=get_smb_fid(pinfo->private_data);
1491
1492                 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
1493                         g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
1494                         if(call_value->rep_frame==-1){
1495                                 call_value->rep_frame=pinfo->fd->num;
1496                         }
1497                 }
1498         }
1499
1500         value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
1501
1502         di.conv = conv;
1503         di.call_id = 0; 
1504         di.smb_fid = -1;
1505         if(value) {
1506                 di.call_data = value;
1507         } else {
1508                 v.uuid = hdr.if_id;
1509                 v.ver=hdr.if_ver;
1510                 v.req_frame=-1;
1511                 v.rep_frame=pinfo->fd->num;
1512                 v.private_data=NULL;
1513                 di.call_data = &v;
1514         }
1515         dcerpc_try_handoff (pinfo, tree, dcerpc_tree, tvb, offset,
1516                         hdr.opnum, FALSE, hdr.drep, &di);
1517         break;
1518     }
1519
1520     return TRUE;
1521 }
1522
1523 static void
1524 dcerpc_init_protocol (void)
1525 {
1526         /* structures and data for BIND */
1527         if (dcerpc_binds){
1528                 g_hash_table_destroy (dcerpc_binds);
1529         }
1530         dcerpc_binds = g_hash_table_new (dcerpc_bind_hash, dcerpc_bind_equal);
1531
1532         if (dcerpc_bind_key_chunk){
1533                 g_mem_chunk_destroy (dcerpc_bind_key_chunk);
1534         }
1535         dcerpc_bind_key_chunk = g_mem_chunk_new ("dcerpc_bind_key_chunk",
1536                                              sizeof (dcerpc_bind_key),
1537                                              200 * sizeof (dcerpc_bind_key),
1538                                              G_ALLOC_ONLY);
1539         if (dcerpc_bind_value_chunk){
1540                 g_mem_chunk_destroy (dcerpc_bind_value_chunk);
1541         }
1542         dcerpc_bind_value_chunk = g_mem_chunk_new ("dcerpc_bind_value_chunk",
1543                                              sizeof (dcerpc_bind_value),
1544                                              200 * sizeof (dcerpc_bind_value),
1545                                              G_ALLOC_ONLY);
1546         /* structures and data for CALL */
1547         if (dcerpc_calls){
1548                 g_hash_table_destroy (dcerpc_calls);
1549         }
1550         dcerpc_calls = g_hash_table_new (dcerpc_call_hash, dcerpc_call_equal);
1551         if (dcerpc_call_key_chunk){
1552                 g_mem_chunk_destroy (dcerpc_call_key_chunk);
1553         }
1554         dcerpc_call_key_chunk = g_mem_chunk_new ("dcerpc_call_key_chunk",
1555                                              sizeof (dcerpc_call_key),
1556                                              200 * sizeof (dcerpc_call_key),
1557                                              G_ALLOC_ONLY);
1558         if (dcerpc_call_value_chunk){
1559                 g_mem_chunk_destroy (dcerpc_call_value_chunk);
1560         }
1561         dcerpc_call_value_chunk = g_mem_chunk_new ("dcerpc_call_value_chunk",
1562                                              sizeof (dcerpc_call_value),
1563                                              200 * sizeof (dcerpc_call_value),
1564                                              G_ALLOC_ONLY);
1565
1566         /* structure and data for MATCHED */
1567         if (dcerpc_matched){
1568                 g_hash_table_destroy (dcerpc_matched);
1569         }
1570         dcerpc_matched = g_hash_table_new (dcerpc_matched_hash, dcerpc_matched_equal);
1571
1572 }
1573
1574 void
1575 proto_register_dcerpc (void)
1576 {
1577     static hf_register_info hf[] = {
1578         { &hf_dcerpc_request_in,
1579                 { "Request in", "dcerpc.request_in", FT_UINT32, BASE_DEC,
1580                 NULL, 0, "This packet is a response to the packet in this frame", HFILL }},
1581         { &hf_dcerpc_response_in, 
1582                 { "Response in", "dcerpc.response_in", FT_UINT32, BASE_DEC,
1583                 NULL, 0, "The response to this packet is in this packet", HFILL }},
1584         { &hf_dcerpc_ver,
1585           { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
1586         { &hf_dcerpc_ver_minor,
1587           { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
1588         { &hf_dcerpc_packet_type,
1589           { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_HEX, VALS (pckt_vals), 0x0, "", HFILL }},
1590         { &hf_dcerpc_cn_flags,
1591           { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
1592         { &hf_dcerpc_cn_flags_first_frag,
1593           { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x1, "", HFILL }},
1594         { &hf_dcerpc_cn_flags_last_frag,
1595           { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x2, "", HFILL }},
1596         { &hf_dcerpc_cn_flags_cancel_pending,
1597           { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x4, "", HFILL }},
1598         { &hf_dcerpc_cn_flags_reserved,
1599           { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x8, "", HFILL }},
1600         { &hf_dcerpc_cn_flags_mpx,
1601           { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x10, "", HFILL }},
1602         { &hf_dcerpc_cn_flags_dne,
1603           { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x20, "", HFILL }},
1604         { &hf_dcerpc_cn_flags_maybe,
1605           { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x40, "", HFILL }},
1606         { &hf_dcerpc_cn_flags_object,
1607           { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x80, "", HFILL }},
1608         { &hf_dcerpc_drep,
1609           { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
1610         { &hf_dcerpc_drep_byteorder,
1611           { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS (drep_byteorder_vals), 0x0, "", HFILL }},
1612         { &hf_dcerpc_drep_character,
1613           { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS (drep_character_vals), 0x0, "", HFILL }},
1614         { &hf_dcerpc_drep_fp,
1615           { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS (drep_fp_vals), 0x0, "", HFILL }},
1616         { &hf_dcerpc_cn_frag_len,
1617           { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
1618         { &hf_dcerpc_cn_auth_len,
1619           { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
1620         { &hf_dcerpc_cn_call_id,
1621           { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
1622         { &hf_dcerpc_cn_max_xmit,
1623           { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
1624         { &hf_dcerpc_cn_max_recv,
1625           { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
1626         { &hf_dcerpc_cn_assoc_group,
1627           { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
1628         { &hf_dcerpc_cn_num_ctx_items,
1629           { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
1630         { &hf_dcerpc_cn_ctx_id,
1631           { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
1632         { &hf_dcerpc_cn_num_trans_items,
1633           { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
1634         { &hf_dcerpc_cn_bind_if_id,
1635           { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
1636         { &hf_dcerpc_cn_bind_if_ver,
1637           { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
1638         { &hf_dcerpc_cn_bind_if_ver_minor,
1639           { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
1640         { &hf_dcerpc_cn_bind_trans_id,
1641           { "Transfer Syntax", "dcerpc.cn_bind_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
1642         { &hf_dcerpc_cn_bind_trans_ver,
1643           { "Syntax ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
1644         { &hf_dcerpc_cn_alloc_hint,
1645           { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
1646         { &hf_dcerpc_cn_sec_addr_len,
1647           { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
1648         { &hf_dcerpc_cn_num_results,
1649           { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
1650         { &hf_dcerpc_cn_ack_result,
1651           { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
1652         { &hf_dcerpc_cn_ack_reason,
1653           { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
1654         { &hf_dcerpc_cn_ack_trans_id,
1655           { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
1656         { &hf_dcerpc_cn_ack_trans_ver,
1657           { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
1658         { &hf_dcerpc_cn_cancel_count,
1659           { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
1660         { &hf_dcerpc_auth_type,
1661           { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
1662         { &hf_dcerpc_auth_level,
1663           { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
1664         { &hf_dcerpc_auth_pad_len,
1665           { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
1666         { &hf_dcerpc_auth_rsrvd,
1667           { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
1668         { &hf_dcerpc_auth_ctx_id,
1669           { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
1670         { &hf_dcerpc_dg_flags1,
1671           { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
1672         { &hf_dcerpc_dg_flags1_rsrvd_01,
1673           { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x01, "", HFILL }},
1674         { &hf_dcerpc_dg_flags1_last_frag,
1675           { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x02, "", HFILL }},
1676         { &hf_dcerpc_dg_flags1_frag,
1677           { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x04, "", HFILL }},
1678         { &hf_dcerpc_dg_flags1_nofack,
1679           { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x08, "", HFILL }},
1680         { &hf_dcerpc_dg_flags1_maybe,
1681           { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x10, "", HFILL }},
1682         { &hf_dcerpc_dg_flags1_idempotent,
1683           { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x20, "", HFILL }},
1684         { &hf_dcerpc_dg_flags1_broadcast,
1685           { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x40, "", HFILL }},
1686         { &hf_dcerpc_dg_flags1_rsrvd_80,
1687           { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x80, "", HFILL }},
1688         { &hf_dcerpc_dg_flags2,
1689           { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
1690         { &hf_dcerpc_dg_flags2_rsrvd_01,
1691           { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x01, "", HFILL }},
1692         { &hf_dcerpc_dg_flags2_cancel_pending,
1693           { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x02, "", HFILL }},
1694         { &hf_dcerpc_dg_flags2_rsrvd_04,
1695           { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x04, "", HFILL }},
1696         { &hf_dcerpc_dg_flags2_rsrvd_08,
1697           { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x08, "", HFILL }},
1698         { &hf_dcerpc_dg_flags2_rsrvd_10,
1699           { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x10, "", HFILL }},
1700         { &hf_dcerpc_dg_flags2_rsrvd_20,
1701           { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x20, "", HFILL }},
1702         { &hf_dcerpc_dg_flags2_rsrvd_40,
1703           { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x40, "", HFILL }},
1704         { &hf_dcerpc_dg_flags2_rsrvd_80,
1705           { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x80, "", HFILL }},
1706         { &hf_dcerpc_dg_serial_lo,
1707           { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
1708         { &hf_dcerpc_dg_serial_hi,
1709           { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
1710         { &hf_dcerpc_dg_ahint,
1711           { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
1712         { &hf_dcerpc_dg_ihint,
1713           { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
1714         { &hf_dcerpc_dg_frag_len,
1715           { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
1716         { &hf_dcerpc_dg_frag_num,
1717           { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
1718         { &hf_dcerpc_dg_auth_proto,
1719           { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
1720         { &hf_dcerpc_dg_seqnum,
1721           { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
1722         { &hf_dcerpc_dg_server_boot,
1723           { "Server boot time", "dcerpc.dg_server_boot", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
1724         { &hf_dcerpc_dg_if_ver,
1725           { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
1726         { &hf_dcerpc_obj_id,
1727           { "Object", "dcerpc.obj_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
1728         { &hf_dcerpc_dg_if_id,
1729           { "Interface", "dcerpc.dg_if_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
1730         { &hf_dcerpc_dg_act_id,
1731           { "Activitiy", "dcerpc.dg_act_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
1732         { &hf_dcerpc_opnum,
1733           { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
1734
1735
1736     };
1737     static gint *ett[] = {
1738         &ett_dcerpc,
1739         &ett_dcerpc_cn_flags,
1740         &ett_dcerpc_drep,
1741         &ett_dcerpc_dg_flags1,
1742         &ett_dcerpc_dg_flags2,
1743     };
1744
1745     proto_dcerpc = proto_register_protocol ("DCE RPC", "DCERPC", "dcerpc");
1746     proto_register_field_array (proto_dcerpc, hf, array_length (hf));
1747     proto_register_subtree_array (ett, array_length (ett));
1748     register_init_routine (dcerpc_init_protocol);
1749
1750     prefs_register_bool_preference (prefs_register_protocol (proto_dcerpc, 
1751                                                              NULL),
1752                                     "desegment_dcerpc",
1753                                     "Desegment all DCE/RPC over TCP",
1754                                     "Whether the DCE/RPC dissector should desegment all DCE/RPC over TCP",
1755                                     &dcerpc_cn_desegment);
1756     dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
1757 }
1758
1759 void
1760 proto_reg_handoff_dcerpc (void)
1761 {
1762     heur_dissector_add ("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
1763     heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
1764     heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
1765     heur_dissector_add ("smb_transact", dissect_dcerpc_cn_bs, proto_dcerpc);
1766 }