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