GIOP CosNaming support, from Frank Singleton.
[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.7 2001/07/11 04:49:34 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
42 static const value_string pckt_vals[] = {
43     { 0, "Request"},
44     { 1, "Ping"},
45     { 2, "Response"},
46     { 3, "Fault"},
47     { 4, "Working"},
48     { 5, "Nocall"},
49     { 6, "Reject"},
50     { 7, "Ack"},
51     { 8, "Cl_cancel"},
52     { 9, "Fack"},
53     { 10, "Cancel_ack"},
54     { 11, "Bind"},
55     { 12, "Bind_ack"},
56     { 13, "Bind_nak"},
57     { 14, "Alter_context"},
58     { 15, "Alter_context_resp"},
59     { 16, "AUTH3?"},
60     { 17, "Shutdown"},
61     { 18, "Co_cancel"},
62     { 19, "Orphaned"},
63 };
64
65 static const true_false_string flags_set_truth = {
66   "Set",
67   "Not set"
68 };
69
70 static int proto_dcerpc = -1;
71
72 /* field defines */
73 static int hf_dcerpc_ver = -1;
74 static int hf_dcerpc_ver_minor = -1;
75 static int hf_dcerpc_packet_type = -1;
76 static int hf_dcerpc_cn_flags = -1;
77 static int hf_dcerpc_cn_flags_first_frag = -1;
78 static int hf_dcerpc_cn_flags_last_frag = -1;
79 static int hf_dcerpc_cn_flags_cancel_pending = -1;
80 static int hf_dcerpc_cn_flags_reserved = -1;
81 static int hf_dcerpc_cn_flags_mpx = -1;
82 static int hf_dcerpc_cn_flags_dne = -1;
83 static int hf_dcerpc_cn_flags_maybe = -1;
84 static int hf_dcerpc_cn_flags_object = -1;
85 static int hf_dcerpc_cn_frag_len = -1;
86 static int hf_dcerpc_cn_auth_len = -1;
87 static int hf_dcerpc_cn_call_id = -1;
88 static int hf_dcerpc_cn_max_xmit = -1;
89 static int hf_dcerpc_cn_max_recv = -1;
90 static int hf_dcerpc_cn_assoc_group = -1;
91 static int hf_dcerpc_cn_num_ctx_items = -1;
92 static int hf_dcerpc_cn_ctx_id = -1;
93 static int hf_dcerpc_cn_num_trans_items = -1;
94 static int hf_dcerpc_cn_bind_if_id = -1;
95 static int hf_dcerpc_cn_bind_if_ver = -1;
96 static int hf_dcerpc_cn_bind_if_ver_minor = -1;
97 static int hf_dcerpc_cn_bind_trans_id = -1;
98 static int hf_dcerpc_cn_bind_trans_ver = -1;
99 static int hf_dcerpc_cn_alloc_hint = -1;
100 static int hf_dcerpc_cn_sec_addr_len = -1;
101 static int hf_dcerpc_cn_num_results = -1;
102 static int hf_dcerpc_cn_ack_result = -1;
103 static int hf_dcerpc_cn_ack_reason = -1;
104 static int hf_dcerpc_cn_cancel_count = -1;
105 static int hf_dcerpc_dg_flags1 = -1;
106 static int hf_dcerpc_dg_flags1_rsrvd_01 = -1;
107 static int hf_dcerpc_dg_flags1_last_frag = -1;
108 static int hf_dcerpc_dg_flags1_frag = -1;
109 static int hf_dcerpc_dg_flags1_nofack = -1;
110 static int hf_dcerpc_dg_flags1_maybe = -1;
111 static int hf_dcerpc_dg_flags1_idempotent = -1;
112 static int hf_dcerpc_dg_flags1_broadcast = -1;
113 static int hf_dcerpc_dg_flags1_rsrvd_80 = -1;
114 static int hf_dcerpc_dg_flags2 = -1;
115 static int hf_dcerpc_dg_flags2_rsrvd_01 = -1;
116 static int hf_dcerpc_dg_flags2_cancel_pending = -1;
117 static int hf_dcerpc_dg_flags2_rsrvd_04 = -1;
118 static int hf_dcerpc_dg_flags2_rsrvd_08 = -1;
119 static int hf_dcerpc_dg_flags2_rsrvd_10 = -1;
120 static int hf_dcerpc_dg_flags2_rsrvd_20 = -1;
121 static int hf_dcerpc_dg_flags2_rsrvd_40 = -1;
122 static int hf_dcerpc_dg_flags2_rsrvd_80 = -1;
123 static int hf_dcerpc_dg_serial_hi = -1;
124 static int hf_dcerpc_obj_id = -1;
125 static int hf_dcerpc_dg_if_id = -1;
126 static int hf_dcerpc_dg_act_id = -1;
127 static int hf_dcerpc_dg_serial_lo = -1;
128 static int hf_dcerpc_dg_ahint = -1;
129 static int hf_dcerpc_dg_ihint = -1;
130 static int hf_dcerpc_dg_frag_len = -1;
131 static int hf_dcerpc_dg_frag_num = -1;
132 static int hf_dcerpc_dg_auth_proto = -1;
133 static int hf_dcerpc_opnum = -1;
134 static int hf_dcerpc_dg_seqnum = -1;
135 static int hf_dcerpc_dg_server_boot = -1;
136 static int hf_dcerpc_dg_if_ver = -1;
137
138 static gint ett_dcerpc = -1;
139 static gint ett_dcerpc_cn_flags = -1;
140 static gint ett_dcerpc_dg_flags1 = -1;
141 static gint ett_dcerpc_dg_flags2 = -1;
142
143 /*
144  * Subdissectors
145  */
146
147 /* the registered subdissectors */
148 static GHashTable *dcerpc_uuids;
149
150 typedef struct _dcerpc_uuid_key {
151     e_uuid_t uuid;
152     guint16 ver;
153 } dcerpc_uuid_key;
154
155 typedef struct _dcerpc_uuid_value {
156     int proto;
157     int ett;
158     gchar *name;
159     dcerpc_sub_dissector *procs;
160 } dcerpc_uuid_value;
161
162 static gint
163 dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2)
164 {
165     dcerpc_uuid_key *key1 = (dcerpc_uuid_key *)k1;
166     dcerpc_uuid_key *key2 = (dcerpc_uuid_key *)k2;
167     return ((memcmp (&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
168             && (key1->ver == key2->ver));
169 }
170
171 static guint
172 dcerpc_uuid_hash (gconstpointer k)
173 {
174     dcerpc_uuid_key *key = (dcerpc_uuid_key *)k;
175     /* This isn't perfect, but the Data1 part of these is almost always
176        unique. */
177     return key->uuid.Data1;
178 }
179
180 void
181 dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver,
182                   dcerpc_sub_dissector *procs)
183 {
184     dcerpc_uuid_key *key = g_malloc (sizeof (*key));
185     dcerpc_uuid_value *value = g_malloc (sizeof (*value));
186
187     key->uuid = *uuid;
188     key->ver = ver;
189
190     value->proto = proto;
191     value->ett = ett;
192     value->name = proto_get_protocol_short_name (proto);
193     value->procs = procs;
194
195     g_hash_table_insert (dcerpc_uuids, key, value);
196 }
197
198
199 /*
200  * To keep track of ctx_id mappings.  Should really use some
201  * generic conversation support instead.
202  */
203 static GHashTable *dcerpc_convs;
204
205 typedef struct _dcerpc_conv_key {
206     conversation_t *conv;
207     guint16 ctx_id;
208 } dcerpc_conv_key;
209
210 static GMemChunk *dcerpc_conv_key_chunk;
211
212 typedef struct _dcerpc_conv_value {
213     e_uuid_t uuid;
214     guint16 ver;
215 } dcerpc_conv_value;
216
217 static GMemChunk *dcerpc_conv_value_chunk;
218
219 static gint
220 dcerpc_conv_equal (gconstpointer k1, gconstpointer k2)
221 {
222     dcerpc_conv_key *key1 = (dcerpc_conv_key *)k1;
223     dcerpc_conv_key *key2 = (dcerpc_conv_key *)k2;
224     return (key1->conv == key2->conv
225             && key1->ctx_id == key2->ctx_id);
226 }
227
228 static guint
229 dcerpc_conv_hash (gconstpointer k)
230 {
231     dcerpc_conv_key *key = (dcerpc_conv_key *)k;
232     return ((guint)key->conv) + key->ctx_id;
233 }
234
235
236
237 /*
238  * To keep track of callid mappings.  Should really use some generic
239  * conversation support instead.
240  */
241 static GHashTable *dcerpc_calls;
242
243 typedef struct _dcerpc_call_key {
244     conversation_t *conv;
245     guint32 call_id;
246 } dcerpc_call_key;
247
248 static GMemChunk *dcerpc_call_key_chunk;
249
250 typedef struct _dcerpc_call_value {
251     e_uuid_t uuid;
252     guint16 ver;
253     guint16 opnum;
254 } dcerpc_call_value;
255
256 static GMemChunk *dcerpc_call_value_chunk;
257
258 static gint
259 dcerpc_call_equal (gconstpointer k1, gconstpointer k2)
260 {
261     dcerpc_call_key *key1 = (dcerpc_call_key *)k1;
262     dcerpc_call_key *key2 = (dcerpc_call_key *)k2;
263     return (key1->conv == key2->conv
264             && key1->call_id == key2->call_id);
265 }
266
267 static guint
268 dcerpc_call_hash (gconstpointer k)
269 {
270     dcerpc_call_key *key = (dcerpc_call_key *)k;
271     return ((guint32)key->conv) ^ key->call_id;
272 }
273
274 static void
275 dcerpc_call_add_map (guint32 call_id, conversation_t *conv,
276                      guint16 opnum, guint16 ver, e_uuid_t *uuid)
277 {
278     dcerpc_call_key *key = g_mem_chunk_alloc (dcerpc_call_key_chunk);
279     dcerpc_call_value *value = g_mem_chunk_alloc (dcerpc_call_value_chunk);
280
281     key->call_id = call_id;
282     key->conv = conv;
283     value->uuid = *uuid;
284     value->ver = ver;
285     value->opnum = opnum;
286     g_hash_table_insert (dcerpc_calls, key, value);
287 }
288
289 static dcerpc_call_value*
290 dcerpc_call_lookup (guint32 call_id, conversation_t *conv)
291 {
292     dcerpc_call_key key;
293
294     key.call_id = call_id;
295     key.conv = conv;
296     return g_hash_table_lookup (dcerpc_calls, &key);
297 }
298
299
300 /*
301  * Utility functions.  Modeled after packet-rpc.c
302  */
303
304 int
305 dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo,
306                       proto_tree *tree, char *drep, 
307                       int hfindex, guint8 *pdata)
308 {
309     guint8 data;
310
311     data = tvb_get_guint8 (tvb, offset);
312     if (tree) {
313         proto_tree_add_item (tree, hfindex, tvb, offset, 1, (drep[0] & 0x10));
314     }
315     if (pdata)
316         *pdata = data;
317     return offset + 1;
318 }
319
320 int
321 dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo,
322                        proto_tree *tree, char *drep, 
323                        int hfindex, guint16 *pdata)
324 {
325     guint16 data;
326
327     data = ((drep[0] & 0x10)
328             ? tvb_get_letohs (tvb, offset)
329             : tvb_get_ntohs (tvb, offset));
330     
331     if (tree) {
332         proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10));
333     }
334     if (pdata)
335         *pdata = data;
336     return offset + 2;
337 }
338
339 int
340 dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo,
341                        proto_tree *tree, char *drep, 
342                        int hfindex, guint32 *pdata)
343 {
344     guint32 data;
345
346     data = ((drep[0] & 0x10)
347             ? tvb_get_letohl (tvb, offset)
348             : tvb_get_ntohl (tvb, offset));
349     
350     if (tree) {
351         proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10));
352     }
353     if (pdata)
354         *pdata = data;
355     return offset+4;
356 }
357
358 /*
359  * a couple simpler things
360  */
361 guint16
362 dcerpc_tvb_get_ntohs (tvbuff_t *tvb, gint offset, char *drep)
363 {
364     if (drep[0] & 0x10) {
365         return tvb_get_letohs (tvb, offset);
366     } else {
367         return tvb_get_ntohs (tvb, offset);
368     }
369 }
370
371 guint32
372 dcerpc_tvb_get_ntohl (tvbuff_t *tvb, gint offset, char *drep)
373 {
374     if (drep[0] & 0x10) {
375         return tvb_get_letohl (tvb, offset);
376     } else {
377         return tvb_get_ntohl (tvb, offset);
378     }
379 }
380
381 void
382 dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, char *drep, e_uuid_t *uuid)
383 {
384     unsigned int i;
385     uuid->Data1 = dcerpc_tvb_get_ntohl (tvb, offset, drep);
386     uuid->Data2 = dcerpc_tvb_get_ntohs (tvb, offset+4, drep);
387     uuid->Data3 = dcerpc_tvb_get_ntohs (tvb, offset+6, drep);
388
389     for (i=0; i<sizeof (uuid->Data4); i++) {
390         uuid->Data4[i] = tvb_get_guint8 (tvb, offset+8+i);
391     }
392 }
393
394 static int
395 dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
396                     tvbuff_t *tvb, gint offset,
397                     e_uuid_t *uuid, guint16 ver, 
398                     guint16 opnum, gboolean is_rqst)
399 {
400     dcerpc_uuid_key key;
401     dcerpc_uuid_value *sub_proto;
402     proto_item *sub_item;
403     proto_tree *sub_tree;
404     dcerpc_sub_dissector *proc;
405     gchar *name = NULL;
406
407     key.uuid = *uuid;
408     key.ver = ver;
409
410     
411     if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == 0)
412         return -1;
413
414     if (tree) {
415         sub_item = proto_tree_add_item (tree, sub_proto->proto, tvb, offset, 
416                                         tvb_length (tvb) - offset, FALSE);
417         if (sub_item) {
418             sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
419         }
420         
421     }
422     for (proc = sub_proto->procs; proc->name; proc++) {
423         if (proc->num == opnum) {
424             name = proc->name;
425             break;
426         }
427     }
428
429     if (!name)
430         name = "Unknown?!";
431
432     if (check_col (pinfo->fd, COL_INFO)) {
433         col_add_fstr (pinfo->fd, COL_INFO, "%s %s:%s(...)",
434                       is_rqst ? "rqst" : "rply",
435                       sub_proto->name, name);
436     }
437
438     if (check_col (pinfo->fd, COL_PROTOCOL)) {
439         col_set_str (pinfo->fd, COL_PROTOCOL, sub_proto->name);
440     }
441     /* FIXME: call approp. dissector */
442     return 0;
443 }
444
445
446 /*
447  * Connection oriented packet types
448  */
449
450 static void
451 dissect_dcerpc_cn_bind (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
452                         e_dce_cn_common_hdr_t *hdr)
453 {
454     conversation_t *conv = NULL;
455     dcerpc_conv_key *key;
456     dcerpc_conv_value *value;
457     guint8 num_ctx_items;
458     guint16 ctx_id;
459     guint16 num_trans_items;
460     e_uuid_t if_id;
461     e_uuid_t trans_id;
462     guint32 trans_ver;
463     guint16 if_ver, if_ver_minor;
464     int offset = 16;
465
466     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
467                                     hf_dcerpc_cn_max_xmit, NULL);
468
469     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
470                                     hf_dcerpc_cn_max_recv, NULL);
471
472     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
473                                     hf_dcerpc_cn_assoc_group, NULL);
474
475     offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
476                                     hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
477
478     /* padding */
479     offset += 3;
480
481     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
482                                     hf_dcerpc_cn_ctx_id, &ctx_id);
483
484     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
485                                     hf_dcerpc_cn_num_trans_items, &num_trans_items);
486
487     dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
488     if (dcerpc_tree) {
489         proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_if_id, tvb,
490                                       offset, 16, "HMMM",
491                                       "Interface UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
492                                       if_id.Data1, if_id.Data2, if_id.Data3,
493                                       if_id.Data4[0], if_id.Data4[1],
494                                       if_id.Data4[2], if_id.Data4[3],
495                                       if_id.Data4[4], if_id.Data4[5],
496                                       if_id.Data4[6], if_id.Data4[7]);
497     }
498     offset += 16;
499
500     if (hdr->drep[0] & 0x10) {
501         offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
502                                         hf_dcerpc_cn_bind_if_ver, &if_ver);
503         offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
504                                         hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
505     } else {
506         offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
507                                         hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
508         offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
509                                         hf_dcerpc_cn_bind_if_ver, &if_ver);
510     }
511
512     dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
513     if (dcerpc_tree) {
514         proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_trans_id, tvb,
515                                       offset, 16, "HMMM",
516                                       "Transfer Syntax: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
517                                       trans_id.Data1, trans_id.Data2, trans_id.Data3,
518                                       trans_id.Data4[0], trans_id.Data4[1],
519                                       trans_id.Data4[2], trans_id.Data4[3],
520                                       trans_id.Data4[4], trans_id.Data4[5],
521                                       trans_id.Data4[6], trans_id.Data4[7]);
522     }
523     offset += 16;
524
525     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
526                                     hf_dcerpc_cn_bind_trans_ver, &trans_ver);
527
528     if (check_col (pinfo->fd, COL_INFO)) {
529         col_add_fstr (pinfo->fd, COL_INFO, "%s: UUID %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %d.%d",
530                       hdr->ptype == PDU_BIND ? "Bind" : "Alter Ctx",
531                       if_id.Data1, if_id.Data2, if_id.Data3,
532                       if_id.Data4[0], if_id.Data4[1],
533                       if_id.Data4[2], if_id.Data4[3],
534                       if_id.Data4[4], if_id.Data4[5],
535                       if_id.Data4[6], if_id.Data4[7],
536                       if_ver, if_ver_minor);
537     }
538     conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
539                               pinfo->srcport, pinfo->destport, 0);
540     if (conv == NULL) {
541         conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
542                                  pinfo->srcport, pinfo->destport, NULL, 0);
543     }
544
545     key = g_mem_chunk_alloc (dcerpc_conv_key_chunk);
546     key->conv = conv;
547     key->ctx_id = ctx_id;
548
549     value = g_mem_chunk_alloc (dcerpc_conv_value_chunk);
550     value->uuid = if_id;
551     value->ver = if_ver;
552
553     g_hash_table_insert (dcerpc_convs, key, value);
554 }
555
556 static void
557 dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
558                             e_dce_cn_common_hdr_t *hdr)
559 {
560     guint16 max_xmit, max_recv;
561     guint16 sec_addr_len;
562     guint8 num_results;
563     guint16 result = 0;
564     guint16 reason = 0;
565
566     int offset = 16;
567
568     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
569                                     hf_dcerpc_cn_max_xmit, &max_xmit);
570
571     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
572                                     hf_dcerpc_cn_max_recv, &max_recv);
573
574     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
575                                     hf_dcerpc_cn_assoc_group, NULL);
576
577     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
578                                     hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
579     offset += sec_addr_len;
580
581     if (offset % 4) {
582         offset += 4 - offset % 4;
583     }
584
585     offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
586                                    hf_dcerpc_cn_num_results, &num_results);
587
588     /* padding */
589     offset += 3;
590
591     if (num_results == 1) {
592         offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, 
593                                         hdr->drep, hf_dcerpc_cn_ack_result,
594                                         &result);
595         offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, 
596                                         hdr->drep, hf_dcerpc_cn_ack_reason,
597                                         &reason);
598     }
599     
600     if (check_col (pinfo->fd, COL_INFO)) {
601         if (num_results == 1 && result == 0) {
602             col_add_fstr (pinfo->fd, COL_INFO, "%s ack: accept  max_xmit: %d  max_recv: %d",
603                           hdr->ptype == PDU_BIND_ACK ? "Bind" : "Alter ctx",
604                           max_xmit, max_recv);
605         } else {
606             /* FIXME: should put in reason */
607             col_add_fstr (pinfo->fd, COL_INFO, "%s ack: %s",
608                           hdr->ptype == PDU_BIND_ACK ? "Bind" : "Alter ctx",
609                           result == 1 ? "User reject" :
610                           result == 2 ? "Provider reject" :
611                           "Unknown");
612         }
613     }
614 }
615
616 static void
617 dissect_dcerpc_cn_rqst (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
618                         proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
619 {
620     conversation_t *conv;
621     guint16 ctx_id;
622     guint16 opnum;
623     e_uuid_t obj_id;
624
625     int offset = 16;
626
627     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
628                                     hf_dcerpc_cn_alloc_hint, NULL);
629
630     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
631                                     hf_dcerpc_cn_ctx_id, &ctx_id);
632
633     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
634                                     hf_dcerpc_opnum, &opnum);
635
636     if (hdr->flags & 0x80) {
637         dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id);
638         if (dcerpc_tree) {
639             proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
640                                           offset, 16, "HMMM",
641                                           "Object UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
642                                           obj_id.Data1, obj_id.Data2, obj_id.Data3,
643                                           obj_id.Data4[0],
644                                           obj_id.Data4[1],
645                                           obj_id.Data4[2],
646                                           obj_id.Data4[3],
647                                           obj_id.Data4[4],
648                                           obj_id.Data4[5],
649                                           obj_id.Data4[6],
650                                           obj_id.Data4[7]);
651         }
652         offset += 16;
653     }
654
655     if (check_col (pinfo->fd, COL_INFO)) {
656         col_add_fstr (pinfo->fd, COL_INFO, "Request: opnum: %d  ctx_id:%d",
657                          opnum, ctx_id);
658     }
659
660     conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
661                               pinfo->srcport, pinfo->destport, 0);
662     if (!conv) {
663
664     } else {
665         dcerpc_conv_key key;
666         dcerpc_conv_value *value;
667
668         key.conv = conv;
669         key.ctx_id = ctx_id;
670
671         value = g_hash_table_lookup (dcerpc_convs, &key);
672         if (value) {
673             /* add an entry for this call, so we can catch the reply */
674             dcerpc_call_add_map (hdr->call_id, conv, opnum,
675                                  value->ver, &value->uuid);
676
677             /* handoff this call */
678             dcerpc_try_handoff (pinfo, tree, tvb, offset,
679                                 &value->uuid, value->ver,
680                                 opnum, TRUE);
681         }
682     }
683 }
684
685 static void
686 dissect_dcerpc_cn_resp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
687                         proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
688 {
689     conversation_t *conv;
690     guint16 ctx_id;
691
692     int offset = 16;
693
694     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
695                                     hf_dcerpc_cn_alloc_hint, NULL);
696
697     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
698                                     hf_dcerpc_cn_ctx_id, &ctx_id);
699
700     offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
701                                    hf_dcerpc_cn_cancel_count, NULL);
702     /* padding */
703     offset++;
704
705     if (check_col (pinfo->fd, COL_INFO)) {
706         col_add_fstr (pinfo->fd, COL_INFO, "Response: call_id: %d  ctx_id:%d",
707                       hdr->call_id, ctx_id);
708     }
709
710     conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
711                               pinfo->srcport, pinfo->destport, 0);
712     if (!conv) {
713         /* no point in creating one here, really */
714     } else {
715         dcerpc_call_value *value = dcerpc_call_lookup (hdr->call_id, conv);
716         if (value) {
717             dcerpc_try_handoff (pinfo, tree, tvb, offset, 
718                                 &value->uuid, value->ver,
719                                 value->opnum, FALSE);
720         }
721     }
722 }
723
724 /*
725  * DCERPC dissector for connection oriented calls
726  */
727 static gboolean
728 dissect_dcerpc_cn (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
729 {
730     proto_item *ti = NULL;
731     proto_item *tf = NULL;
732     proto_tree *dcerpc_tree = NULL;
733     proto_tree *cn_flags_tree = NULL;
734     e_dce_cn_common_hdr_t hdr;
735     int offset = 0;
736
737     /*
738      * Check if this looks like a C/O DCERPC call
739      */
740     if (!tvb_bytes_exist (tvb, 0, sizeof (hdr))) {
741         return FALSE;
742     }
743     hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
744     if (hdr.rpc_ver != 5)
745         return FALSE;
746     hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
747     if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
748         return FALSE;
749     hdr.ptype = tvb_get_guint8 (tvb, offset++);
750     if (hdr.ptype > 19)
751         return FALSE;
752
753     if (check_col (pinfo->fd, COL_PROTOCOL))
754         col_set_str (pinfo->fd, COL_PROTOCOL, "DCERPC");
755     if (check_col (pinfo->fd, COL_INFO))
756         col_set_str (pinfo->fd, COL_INFO, pckt_vals[hdr.ptype].strptr);
757
758     hdr.flags = tvb_get_guint8 (tvb, offset++);
759     tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
760     offset += sizeof (hdr.drep);
761
762     hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
763     offset += 2;
764     hdr.auth_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
765     offset += 2;
766     hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
767     offset += 4;
768
769     if (tree) {
770         ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, tvb_length(tvb), FALSE);
771         if (ti) {
772             dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
773         }
774         offset = 0;
775         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver);
776         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset++, 1, hdr.rpc_ver_minor);
777         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype);
778         tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
779         cn_flags_tree = proto_item_add_subtree (tf, ett_dcerpc_cn_flags);
780         if (cn_flags_tree) {
781             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
782             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
783             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
784             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
785             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
786             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
787             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
788             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
789         }
790         offset++;
791
792         proto_tree_add_text (dcerpc_tree, tvb, offset, sizeof (hdr.drep), "Data Rep");
793         offset += sizeof (hdr.drep);
794
795         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
796         offset += 2;
797
798         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
799         offset += 2;
800
801         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
802         offset += 4;
803     }
804     /*
805      * Packet type specific stuff is next.
806      */
807     switch (hdr.ptype) {
808     case PDU_BIND:
809     case PDU_ALTER:
810         dissect_dcerpc_cn_bind (tvb, pinfo, dcerpc_tree, &hdr);
811         break;
812
813     case PDU_BIND_ACK:
814     case PDU_ALTER_ACK:
815         dissect_dcerpc_cn_bind_ack (tvb, pinfo, dcerpc_tree, &hdr);
816         break;
817
818     case PDU_REQ:
819         dissect_dcerpc_cn_rqst (tvb, pinfo, dcerpc_tree, tree, &hdr);
820         break;
821
822     case PDU_RESP:
823         dissect_dcerpc_cn_resp (tvb, pinfo, dcerpc_tree, tree, &hdr);
824         break;
825
826     default:
827         break;
828     }
829     return TRUE;
830 }
831
832 /*
833  * DCERPC dissector for connectionless calls
834  */
835 static gboolean
836 dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
837 {
838     proto_item *ti = NULL;
839     proto_item *tf = NULL;
840     proto_tree *dcerpc_tree = NULL;
841     proto_tree *dg_flags1_tree = NULL;
842     proto_tree *dg_flags2_tree = NULL;
843     e_dce_dg_common_hdr_t hdr;
844     int offset = 0;
845     conversation_t *conv;
846
847     /*
848      * Check if this looks like a CL DCERPC call.  All dg packets
849      * have an 80 byte header on them.  Which starts with
850      * version (4), pkt_type.
851      */
852     if (!tvb_bytes_exist (tvb, 0, sizeof (hdr))) {
853         return FALSE;
854     }
855     hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
856     if (hdr.rpc_ver != 4)
857         return FALSE;
858     hdr.ptype = tvb_get_guint8 (tvb, offset++);
859     if (hdr.ptype > 19)
860         return FALSE;
861
862     if (check_col (pinfo->fd, COL_PROTOCOL))
863         col_set_str (pinfo->fd, COL_PROTOCOL, "DCERPC");
864     if (check_col (pinfo->fd, COL_INFO))
865         col_set_str (pinfo->fd, COL_INFO, pckt_vals[hdr.ptype].strptr);
866
867     hdr.flags1 = tvb_get_guint8 (tvb, offset++);
868     hdr.flags2 = tvb_get_guint8 (tvb, offset++);
869     tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
870     offset += sizeof (hdr.drep);
871     hdr.serial_hi = tvb_get_guint8 (tvb, offset++);
872     dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.obj_id);
873     offset += 16;
874     dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.if_id);
875     offset += 16;
876     dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.act_id);
877     offset += 16;
878     hdr.server_boot = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
879     offset += 4;
880     hdr.if_ver = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
881     offset += 4;
882     hdr.seqnum = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
883     offset += 4;
884     hdr.opnum = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
885     offset += 2;
886     hdr.ihint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
887     offset += 2;
888     hdr.ahint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
889     offset += 2;
890     hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
891     offset += 2;
892     hdr.frag_num = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
893     offset += 2;
894     hdr.auth_proto = tvb_get_guint8 (tvb, offset++);
895     hdr.serial_lo = tvb_get_guint8 (tvb, offset++);
896
897     if (tree) {
898         ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, tvb_length(tvb), FALSE);
899         if (ti) {
900             dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
901         }
902         offset = 0;
903         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver);
904
905         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype);
906
907         tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
908         dg_flags1_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags1);
909         if (dg_flags1_tree) {
910             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
911             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
912             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
913             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
914             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
915             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
916             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
917             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
918         }
919         offset++;
920
921         tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
922         dg_flags2_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags2);
923         if (dg_flags2_tree) {
924             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
925             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
926             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
927             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
928             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
929             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
930             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
931             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
932         }
933         offset++;
934
935         proto_tree_add_text (dcerpc_tree, tvb, offset, sizeof (hdr.drep), "Data Rep");
936         offset += sizeof (hdr.drep);
937
938         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset++, 1, hdr.serial_hi);
939
940         proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
941                                       offset, 16, "HMMM",
942                                       "Object: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
943                                       hdr.obj_id.Data1, hdr.obj_id.Data2, hdr.obj_id.Data3,
944                                       hdr.obj_id.Data4[0],
945                                       hdr.obj_id.Data4[1],
946                                       hdr.obj_id.Data4[2],
947                                       hdr.obj_id.Data4[3],
948                                       hdr.obj_id.Data4[4],
949                                       hdr.obj_id.Data4[5],
950                                       hdr.obj_id.Data4[6],
951                                       hdr.obj_id.Data4[7]);
952         offset += 16;
953
954         proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
955                                       offset, 16, "HMMM",
956                                       "Interface: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
957                                       hdr.if_id.Data1, hdr.if_id.Data2, hdr.if_id.Data3,
958                                       hdr.if_id.Data4[0],
959                                       hdr.if_id.Data4[1],
960                                       hdr.if_id.Data4[2],
961                                       hdr.if_id.Data4[3],
962                                       hdr.if_id.Data4[4],
963                                       hdr.if_id.Data4[5],
964                                       hdr.if_id.Data4[6],
965                                       hdr.if_id.Data4[7]);
966         offset += 16;
967
968         proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
969                                       offset, 16, "HMMM",
970                                       "Activity: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
971                                       hdr.act_id.Data1, hdr.act_id.Data2, hdr.act_id.Data3,
972                                       hdr.act_id.Data4[0],
973                                       hdr.act_id.Data4[1],
974                                       hdr.act_id.Data4[2],
975                                       hdr.act_id.Data4[3],
976                                       hdr.act_id.Data4[4],
977                                       hdr.act_id.Data4[5],
978                                       hdr.act_id.Data4[6],
979                                       hdr.act_id.Data4[7]);
980         offset += 16;
981
982         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_server_boot, tvb, offset, 4, hdr.server_boot);
983         offset += 4;
984
985         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
986         offset += 4;
987
988         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
989         offset += 4;
990
991         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
992         offset += 2;
993
994         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
995         offset += 2;
996
997         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
998         offset += 2;
999
1000         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
1001         offset += 2;
1002
1003         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
1004         offset += 2;
1005
1006         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
1007         offset++;
1008
1009         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
1010         offset++;
1011     }
1012     /* 
1013      * keeping track of the conversation shouldn't really be necessary
1014      * for connectionless packets, because everything we need to know
1015      * to dissect is in the header for each packet.  Unfortunately,
1016      * Microsoft's implementation is buggy and often puts the
1017      * completely wrong if_id in the header.  go figure.  So, keep
1018      * track of the seqnum and use that if possible.  Note: that's not
1019      * completely correct.  It should really be done based on both the
1020      * activity_id and seqnum.  I haven't seen anywhere that it would
1021      * make a difference, but for future reference...
1022      */
1023     conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
1024                               pinfo->srcport, pinfo->destport, 0);
1025     if (!conv) {
1026         conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
1027                                  pinfo->srcport, pinfo->destport, NULL, 0);
1028     }
1029
1030     /*
1031      * Packet type specific stuff is next.
1032      */
1033     switch (hdr.ptype) {
1034     case PDU_REQ:
1035         dcerpc_call_add_map (hdr.seqnum, conv, hdr.opnum,
1036                              hdr.if_ver, &hdr.if_id);
1037         dcerpc_try_handoff (pinfo, tree, tvb, offset,
1038                             &hdr.if_id, hdr.if_ver, hdr.opnum, TRUE);
1039         break;
1040     case PDU_RESP:
1041         {
1042             dcerpc_call_value *v = dcerpc_call_lookup (hdr.seqnum, conv);
1043             if (v) {
1044                 dcerpc_try_handoff (pinfo, tree, tvb, offset,
1045                                     &v->uuid, v->ver, v->opnum, FALSE);
1046             } else {
1047                 dcerpc_try_handoff (pinfo, tree, tvb, offset,
1048                                     &hdr.if_id, hdr.if_ver, hdr.opnum, FALSE);
1049             }
1050         }
1051         break;
1052     }
1053
1054     return TRUE;
1055 }
1056
1057 static void
1058 dcerpc_init_protocol (void)
1059 {
1060     if (dcerpc_convs)
1061         g_hash_table_destroy (dcerpc_convs);
1062     if (dcerpc_calls)
1063         g_hash_table_destroy (dcerpc_calls);
1064     if (dcerpc_conv_key_chunk)
1065         g_mem_chunk_destroy (dcerpc_conv_key_chunk);
1066     if (dcerpc_conv_value_chunk)
1067         g_mem_chunk_destroy (dcerpc_conv_value_chunk);
1068     if (dcerpc_call_key_chunk)
1069         g_mem_chunk_destroy (dcerpc_call_key_chunk);
1070     if (dcerpc_call_value_chunk)
1071         g_mem_chunk_destroy (dcerpc_call_value_chunk);
1072
1073     dcerpc_convs = g_hash_table_new (dcerpc_conv_hash, dcerpc_conv_equal);
1074     dcerpc_calls = g_hash_table_new (dcerpc_call_hash, dcerpc_call_equal);
1075     dcerpc_conv_key_chunk = g_mem_chunk_new ("dcerpc_conv_key_chunk",
1076                                              sizeof (dcerpc_conv_key),
1077                                              200 * sizeof (dcerpc_conv_key),
1078                                              G_ALLOC_ONLY);
1079     dcerpc_conv_value_chunk = g_mem_chunk_new ("dcerpc_conv_value_chunk",
1080                                              sizeof (dcerpc_conv_value),
1081                                              200 * sizeof (dcerpc_conv_value),
1082                                              G_ALLOC_ONLY);
1083     dcerpc_call_key_chunk = g_mem_chunk_new ("dcerpc_call_key_chunk",
1084                                              sizeof (dcerpc_call_key),
1085                                              200 * sizeof (dcerpc_call_key),
1086                                              G_ALLOC_ONLY);
1087     dcerpc_call_value_chunk = g_mem_chunk_new ("dcerpc_call_value_chunk",
1088                                              sizeof (dcerpc_call_value),
1089                                              200 * sizeof (dcerpc_call_value),
1090                                              G_ALLOC_ONLY);
1091 }
1092
1093 void
1094 proto_register_dcerpc (void)
1095 {
1096     static hf_register_info hf[] = {
1097         { &hf_dcerpc_ver,
1098           { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
1099         { &hf_dcerpc_ver_minor,
1100           { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
1101         { &hf_dcerpc_packet_type,
1102           { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_HEX, VALS (pckt_vals), 0x0, "", HFILL }},
1103         { &hf_dcerpc_cn_flags,
1104           { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
1105         { &hf_dcerpc_cn_flags_first_frag,
1106           { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x1, "", HFILL }},
1107         { &hf_dcerpc_cn_flags_last_frag,
1108           { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x2, "", HFILL }},
1109         { &hf_dcerpc_cn_flags_cancel_pending,
1110           { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x4, "", HFILL }},
1111         { &hf_dcerpc_cn_flags_reserved,
1112           { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x8, "", HFILL }},
1113         { &hf_dcerpc_cn_flags_mpx,
1114           { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x10, "", HFILL }},
1115         { &hf_dcerpc_cn_flags_dne,
1116           { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x20, "", HFILL }},
1117         { &hf_dcerpc_cn_flags_maybe,
1118           { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x40, "", HFILL }},
1119         { &hf_dcerpc_cn_flags_object,
1120           { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x80, "", HFILL }},
1121         { &hf_dcerpc_cn_frag_len,
1122           { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
1123         { &hf_dcerpc_cn_auth_len,
1124           { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
1125         { &hf_dcerpc_cn_call_id,
1126           { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
1127         { &hf_dcerpc_cn_max_xmit,
1128           { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
1129         { &hf_dcerpc_cn_max_recv,
1130           { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
1131         { &hf_dcerpc_cn_assoc_group,
1132           { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
1133         { &hf_dcerpc_cn_num_ctx_items,
1134           { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
1135         { &hf_dcerpc_cn_ctx_id,
1136           { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
1137         { &hf_dcerpc_cn_num_trans_items,
1138           { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
1139         { &hf_dcerpc_cn_bind_if_id,
1140           { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
1141         { &hf_dcerpc_cn_bind_if_ver,
1142           { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
1143         { &hf_dcerpc_cn_bind_if_ver_minor,
1144           { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
1145         { &hf_dcerpc_cn_bind_trans_id,
1146           { "Transfer Syntax", "dcerpc.cn_bind_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
1147         { &hf_dcerpc_cn_bind_trans_ver,
1148           { "Syntax ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
1149         { &hf_dcerpc_cn_alloc_hint,
1150           { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
1151         { &hf_dcerpc_cn_sec_addr_len,
1152           { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
1153         { &hf_dcerpc_cn_num_results,
1154           { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
1155         { &hf_dcerpc_cn_ack_result,
1156           { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
1157         { &hf_dcerpc_cn_ack_reason,
1158           { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
1159         { &hf_dcerpc_cn_cancel_count,
1160           { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
1161         { &hf_dcerpc_dg_flags1,
1162           { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
1163         { &hf_dcerpc_dg_flags1_rsrvd_01,
1164           { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x01, "", HFILL }},
1165         { &hf_dcerpc_dg_flags1_last_frag,
1166           { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x02, "", HFILL }},
1167         { &hf_dcerpc_dg_flags1_frag,
1168           { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x04, "", HFILL }},
1169         { &hf_dcerpc_dg_flags1_nofack,
1170           { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x08, "", HFILL }},
1171         { &hf_dcerpc_dg_flags1_maybe,
1172           { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x10, "", HFILL }},
1173         { &hf_dcerpc_dg_flags1_idempotent,
1174           { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x20, "", HFILL }},
1175         { &hf_dcerpc_dg_flags1_broadcast,
1176           { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x40, "", HFILL }},
1177         { &hf_dcerpc_dg_flags1_rsrvd_80,
1178           { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x80, "", HFILL }},
1179         { &hf_dcerpc_dg_flags2,
1180           { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
1181         { &hf_dcerpc_dg_flags2_rsrvd_01,
1182           { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x01, "", HFILL }},
1183         { &hf_dcerpc_dg_flags2_cancel_pending,
1184           { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x02, "", HFILL }},
1185         { &hf_dcerpc_dg_flags2_rsrvd_04,
1186           { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x04, "", HFILL }},
1187         { &hf_dcerpc_dg_flags2_rsrvd_08,
1188           { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x08, "", HFILL }},
1189         { &hf_dcerpc_dg_flags2_rsrvd_10,
1190           { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x10, "", HFILL }},
1191         { &hf_dcerpc_dg_flags2_rsrvd_20,
1192           { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x20, "", HFILL }},
1193         { &hf_dcerpc_dg_flags2_rsrvd_40,
1194           { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x40, "", HFILL }},
1195         { &hf_dcerpc_dg_flags2_rsrvd_80,
1196           { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x80, "", HFILL }},
1197         { &hf_dcerpc_dg_serial_lo,
1198           { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
1199         { &hf_dcerpc_dg_serial_hi,
1200           { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
1201         { &hf_dcerpc_dg_ahint,
1202           { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
1203         { &hf_dcerpc_dg_ihint,
1204           { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
1205         { &hf_dcerpc_dg_frag_len,
1206           { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
1207         { &hf_dcerpc_dg_frag_num,
1208           { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
1209         { &hf_dcerpc_dg_auth_proto,
1210           { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
1211         { &hf_dcerpc_dg_seqnum,
1212           { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
1213         { &hf_dcerpc_dg_server_boot,
1214           { "Server boot time", "dcerpc.dg_server_boot", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
1215         { &hf_dcerpc_dg_if_ver,
1216           { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
1217         { &hf_dcerpc_obj_id,
1218           { "Object", "dcerpc.obj_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
1219         { &hf_dcerpc_dg_if_id,
1220           { "Interface", "dcerpc.dg_if_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
1221         { &hf_dcerpc_dg_act_id,
1222           { "Activitiy", "dcerpc.dg_act_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
1223         { &hf_dcerpc_opnum,
1224           { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
1225
1226
1227     };
1228     static gint *ett[] = {
1229         &ett_dcerpc,
1230         &ett_dcerpc_cn_flags,
1231         &ett_dcerpc_dg_flags1,
1232         &ett_dcerpc_dg_flags2,
1233     };
1234
1235     proto_dcerpc = proto_register_protocol ("DCE RPC", "DCERPC", "dcerpc");
1236     proto_register_field_array (proto_dcerpc, hf, array_length (hf));
1237     proto_register_subtree_array (ett, array_length (ett));
1238     register_init_routine (dcerpc_init_protocol);
1239
1240     dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
1241 }
1242
1243 void
1244 proto_reg_handoff_dcerpc (void)
1245 {
1246     heur_dissector_add ("tcp", dissect_dcerpc_cn, proto_dcerpc);
1247     heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
1248 }