2 * Routines for DCERPC packet disassembly
3 * Copyright 2001, Todd Sabin <tas@webspan.net>
5 * $Id: packet-dcerpc.c,v 1.38 2002/03/10 03:11:10 guy Exp $
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@ethereal.com>
9 * Copyright 1998 Gerald Combs
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.
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.
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.
30 #ifdef HAVE_SYS_TYPES_H
31 #include <sys/types.h>
38 #include <epan/packet.h>
39 #include "packet-dcerpc.h"
40 #include <epan/conversation.h>
43 static const value_string pckt_vals[] = {
58 { 14, "Alter_context"},
59 { 15, "Alter_context_resp"},
67 static const value_string drep_byteorder_vals[] = {
69 { 1, "Little-endian" },
73 static const value_string drep_character_vals[] = {
79 static const value_string drep_fp_vals[] = {
87 static const true_false_string flags_set_truth = {
92 static int proto_dcerpc = -1;
95 static int hf_dcerpc_request_in = -1;
96 static int hf_dcerpc_response_in = -1;
97 static int hf_dcerpc_ver = -1;
98 static int hf_dcerpc_ver_minor = -1;
99 static int hf_dcerpc_packet_type = -1;
100 static int hf_dcerpc_cn_flags = -1;
101 static int hf_dcerpc_cn_flags_first_frag = -1;
102 static int hf_dcerpc_cn_flags_last_frag = -1;
103 static int hf_dcerpc_cn_flags_cancel_pending = -1;
104 static int hf_dcerpc_cn_flags_reserved = -1;
105 static int hf_dcerpc_cn_flags_mpx = -1;
106 static int hf_dcerpc_cn_flags_dne = -1;
107 static int hf_dcerpc_cn_flags_maybe = -1;
108 static int hf_dcerpc_cn_flags_object = -1;
109 static int hf_dcerpc_drep = -1;
110 static int hf_dcerpc_drep_byteorder = -1;
111 static int hf_dcerpc_drep_character = -1;
112 static int hf_dcerpc_drep_fp = -1;
113 static int hf_dcerpc_cn_frag_len = -1;
114 static int hf_dcerpc_cn_auth_len = -1;
115 static int hf_dcerpc_cn_call_id = -1;
116 static int hf_dcerpc_cn_max_xmit = -1;
117 static int hf_dcerpc_cn_max_recv = -1;
118 static int hf_dcerpc_cn_assoc_group = -1;
119 static int hf_dcerpc_cn_num_ctx_items = -1;
120 static int hf_dcerpc_cn_ctx_id = -1;
121 static int hf_dcerpc_cn_num_trans_items = -1;
122 static int hf_dcerpc_cn_bind_if_id = -1;
123 static int hf_dcerpc_cn_bind_if_ver = -1;
124 static int hf_dcerpc_cn_bind_if_ver_minor = -1;
125 static int hf_dcerpc_cn_bind_trans_id = -1;
126 static int hf_dcerpc_cn_bind_trans_ver = -1;
127 static int hf_dcerpc_cn_alloc_hint = -1;
128 static int hf_dcerpc_cn_sec_addr_len = -1;
129 static int hf_dcerpc_cn_num_results = -1;
130 static int hf_dcerpc_cn_ack_result = -1;
131 static int hf_dcerpc_cn_ack_reason = -1;
132 static int hf_dcerpc_cn_ack_trans_id = -1;
133 static int hf_dcerpc_cn_ack_trans_ver = -1;
134 static int hf_dcerpc_cn_cancel_count = -1;
135 static int hf_dcerpc_auth_type = -1;
136 static int hf_dcerpc_auth_level = -1;
137 static int hf_dcerpc_auth_pad_len = -1;
138 static int hf_dcerpc_auth_rsrvd = -1;
139 static int hf_dcerpc_auth_ctx_id = -1;
140 static int hf_dcerpc_dg_flags1 = -1;
141 static int hf_dcerpc_dg_flags1_rsrvd_01 = -1;
142 static int hf_dcerpc_dg_flags1_last_frag = -1;
143 static int hf_dcerpc_dg_flags1_frag = -1;
144 static int hf_dcerpc_dg_flags1_nofack = -1;
145 static int hf_dcerpc_dg_flags1_maybe = -1;
146 static int hf_dcerpc_dg_flags1_idempotent = -1;
147 static int hf_dcerpc_dg_flags1_broadcast = -1;
148 static int hf_dcerpc_dg_flags1_rsrvd_80 = -1;
149 static int hf_dcerpc_dg_flags2 = -1;
150 static int hf_dcerpc_dg_flags2_rsrvd_01 = -1;
151 static int hf_dcerpc_dg_flags2_cancel_pending = -1;
152 static int hf_dcerpc_dg_flags2_rsrvd_04 = -1;
153 static int hf_dcerpc_dg_flags2_rsrvd_08 = -1;
154 static int hf_dcerpc_dg_flags2_rsrvd_10 = -1;
155 static int hf_dcerpc_dg_flags2_rsrvd_20 = -1;
156 static int hf_dcerpc_dg_flags2_rsrvd_40 = -1;
157 static int hf_dcerpc_dg_flags2_rsrvd_80 = -1;
158 static int hf_dcerpc_dg_serial_hi = -1;
159 static int hf_dcerpc_obj_id = -1;
160 static int hf_dcerpc_dg_if_id = -1;
161 static int hf_dcerpc_dg_act_id = -1;
162 static int hf_dcerpc_dg_serial_lo = -1;
163 static int hf_dcerpc_dg_ahint = -1;
164 static int hf_dcerpc_dg_ihint = -1;
165 static int hf_dcerpc_dg_frag_len = -1;
166 static int hf_dcerpc_dg_frag_num = -1;
167 static int hf_dcerpc_dg_auth_proto = -1;
168 static int hf_dcerpc_opnum = -1;
169 static int hf_dcerpc_dg_seqnum = -1;
170 static int hf_dcerpc_dg_server_boot = -1;
171 static int hf_dcerpc_dg_if_ver = -1;
172 static int hf_dcerpc_array_max_count = -1;
173 static int hf_dcerpc_array_offset = -1;
174 static int hf_dcerpc_array_actual_count = -1;
175 static int hf_dcerpc_referent_id = -1;
177 static gint ett_dcerpc = -1;
178 static gint ett_dcerpc_cn_flags = -1;
179 static gint ett_dcerpc_drep = -1;
180 static gint ett_dcerpc_dg_flags1 = -1;
181 static gint ett_dcerpc_dg_flags2 = -1;
182 static gint ett_dcerpc_pointer_data = -1;
184 /* try to desegment big DCE/RPC packets over TCP? */
185 static gboolean dcerpc_cn_desegment = TRUE;
192 /* the registered subdissectors */
193 static GHashTable *dcerpc_uuids;
195 typedef struct _dcerpc_uuid_key {
200 typedef struct _dcerpc_uuid_value {
204 dcerpc_sub_dissector *procs;
208 dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2)
210 dcerpc_uuid_key *key1 = (dcerpc_uuid_key *)k1;
211 dcerpc_uuid_key *key2 = (dcerpc_uuid_key *)k2;
212 return ((memcmp (&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
213 && (key1->ver == key2->ver));
217 dcerpc_uuid_hash (gconstpointer k)
219 dcerpc_uuid_key *key = (dcerpc_uuid_key *)k;
220 /* This isn't perfect, but the Data1 part of these is almost always
222 return key->uuid.Data1;
226 dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver,
227 dcerpc_sub_dissector *procs)
229 dcerpc_uuid_key *key = g_malloc (sizeof (*key));
230 dcerpc_uuid_value *value = g_malloc (sizeof (*value));
235 value->proto = proto;
237 value->name = proto_get_protocol_short_name (proto);
238 value->procs = procs;
240 g_hash_table_insert (dcerpc_uuids, key, value);
245 * To keep track of ctx_id mappings.
247 * Everytime we see a bind call we update this table.
248 * Note that we always specify a SMB FID. For non-SMB transports this
251 static GHashTable *dcerpc_binds=NULL;
253 typedef struct _dcerpc_bind_key {
254 conversation_t *conv;
259 typedef struct _dcerpc_bind_value {
264 static GMemChunk *dcerpc_bind_key_chunk=NULL;
265 static GMemChunk *dcerpc_bind_value_chunk=NULL;
268 dcerpc_bind_equal (gconstpointer k1, gconstpointer k2)
270 dcerpc_bind_key *key1 = (dcerpc_bind_key *)k1;
271 dcerpc_bind_key *key2 = (dcerpc_bind_key *)k2;
272 return (key1->conv == key2->conv
273 && key1->ctx_id == key2->ctx_id
274 && key1->smb_fid == key2->smb_fid);
278 dcerpc_bind_hash (gconstpointer k)
280 dcerpc_bind_key *key = (dcerpc_bind_key *)k;
281 return ((guint)key->conv) + key->ctx_id + key->smb_fid;
285 * To keep track of callid mappings. Should really use some generic
286 * conversation support instead.
288 static GHashTable *dcerpc_calls=NULL;
290 typedef struct _dcerpc_call_key {
291 conversation_t *conv;
296 static GMemChunk *dcerpc_call_key_chunk=NULL;
298 static GMemChunk *dcerpc_call_value_chunk=NULL;
301 dcerpc_call_equal (gconstpointer k1, gconstpointer k2)
303 dcerpc_call_key *key1 = (dcerpc_call_key *)k1;
304 dcerpc_call_key *key2 = (dcerpc_call_key *)k2;
305 return (key1->conv == key2->conv
306 && key1->call_id == key2->call_id
307 && key1->smb_fid == key2->smb_fid);
311 dcerpc_call_hash (gconstpointer k)
313 dcerpc_call_key *key = (dcerpc_call_key *)k;
314 return ((guint32)key->conv) + key->call_id + key->smb_fid;
318 /* to keep track of matched calls/responses
319 this one uses the same value struct as calls, but the key is the frame id
321 static GHashTable *dcerpc_matched=NULL;
323 dcerpc_matched_equal (gconstpointer k1, gconstpointer k2)
325 return (guint32)k1 == (guint32)k2;
329 dcerpc_matched_hash (gconstpointer k)
337 * Utility functions. Modeled after packet-rpc.c
341 dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo,
342 proto_tree *tree, char *drep,
343 int hfindex, guint8 *pdata)
347 data = tvb_get_guint8 (tvb, offset);
349 proto_tree_add_item (tree, hfindex, tvb, offset, 1, (drep[0] & 0x10));
357 dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo,
358 proto_tree *tree, char *drep,
359 int hfindex, guint16 *pdata)
363 data = ((drep[0] & 0x10)
364 ? tvb_get_letohs (tvb, offset)
365 : tvb_get_ntohs (tvb, offset));
368 proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10));
376 dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo,
377 proto_tree *tree, char *drep,
378 int hfindex, guint32 *pdata)
382 data = ((drep[0] & 0x10)
383 ? tvb_get_letohl (tvb, offset)
384 : tvb_get_ntohl (tvb, offset));
387 proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10));
395 dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo,
396 proto_tree *tree, char *drep,
397 int hfindex, unsigned char *pdata)
400 tvb_memcpy(tvb, pdata, offset, 8);
401 if(drep[0] & 0x10){/* XXX this might be the wrong way around */
403 data=pdata[0];pdata[0]=pdata[7];pdata[7]=data;
404 data=pdata[1];pdata[1]=pdata[6];pdata[6]=data;
405 data=pdata[2];pdata[2]=pdata[5];pdata[5]=data;
406 data=pdata[3];pdata[3]=pdata[4];pdata[4]=data;
411 proto_tree_add_item(tree, hfindex, tvb, offset, 8, (drep[0] & 0x10));
418 * a couple simpler things
421 dcerpc_tvb_get_ntohs (tvbuff_t *tvb, gint offset, char *drep)
423 if (drep[0] & 0x10) {
424 return tvb_get_letohs (tvb, offset);
426 return tvb_get_ntohs (tvb, offset);
431 dcerpc_tvb_get_ntohl (tvbuff_t *tvb, gint offset, char *drep)
433 if (drep[0] & 0x10) {
434 return tvb_get_letohl (tvb, offset);
436 return tvb_get_ntohl (tvb, offset);
441 dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, char *drep, e_uuid_t *uuid)
444 uuid->Data1 = dcerpc_tvb_get_ntohl (tvb, offset, drep);
445 uuid->Data2 = dcerpc_tvb_get_ntohs (tvb, offset+4, drep);
446 uuid->Data3 = dcerpc_tvb_get_ntohs (tvb, offset+6, drep);
448 for (i=0; i<sizeof (uuid->Data4); i++) {
449 uuid->Data4[i] = tvb_get_guint8 (tvb, offset+8+i);
456 /* function to dissect a unidimensional conformant array */
458 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
459 proto_tree *tree, char *drep,
460 dcerpc_dissect_fnct_t *fnct)
465 di=pinfo->private_data;
466 if(di->conformant_run){
467 /* conformant run, just dissect the max_count header */
468 di->conformant_run=0;
469 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
470 hf_dcerpc_array_max_count, &di->array_max_count);
471 di->array_max_count_offset=offset-4;
472 di->conformant_run=1;
474 /* we dont dont remember where in the bytestream this fields was */
475 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
477 /* real run, dissect the elements */
478 for(i=0;i<di->array_max_count;i++){
479 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
485 /* function to dissect a unidimensional conformant and varying array */
487 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
488 proto_tree *tree, char *drep,
489 dcerpc_dissect_fnct_t *fnct)
494 di=pinfo->private_data;
495 if(di->conformant_run){
496 /* conformant run, just dissect the max_count header */
497 di->conformant_run=0;
498 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
499 hf_dcerpc_array_max_count, &di->array_max_count);
500 di->array_max_count_offset=offset-4;
501 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
502 hf_dcerpc_array_offset, &di->array_offset);
503 di->array_offset_offset=offset-4;
504 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
505 hf_dcerpc_array_actual_count, &di->array_actual_count);
506 di->array_actual_count_offset=offset-4;
507 di->conformant_run=1;
509 /* we dont dont remember where in the bytestream these fields were */
510 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
511 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
512 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
514 /* real run, dissect the elements */
515 for(i=0;i<di->array_actual_count;i++){
516 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
524 /* ndr pointer handling */
525 /* list of pointers encountered so far */
526 static GSList *ndr_pointer_list = NULL;
528 /* position where in the list to insert newly encountered pointers */
529 static int ndr_pointer_list_pos=0;
531 /* boolean controlling whether pointers are top-level or embedded */
532 static gboolean pointers_are_top_level = TRUE;
534 /* as a kludge, we represent all embedded reference pointers as id==-1
535 hoping that his will not collide with any non-ref pointers */
536 typedef struct ndr_pointer_data {
539 dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
542 } ndr_pointer_data_t;
545 init_ndr_pointer_list(packet_info *pinfo)
549 di=pinfo->private_data;
550 di->conformant_run=0;
552 while(ndr_pointer_list){
553 ndr_pointer_data_t *npd;
555 npd=g_slist_nth_data(ndr_pointer_list, 0);
556 ndr_pointer_list=g_slist_remove(ndr_pointer_list, npd);
562 ndr_pointer_list=NULL;
563 ndr_pointer_list_pos=0;
564 pointers_are_top_level=TRUE;
568 dissect_deferred_pointers(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, char *drep)
570 int found_new_pointer;
573 di=pinfo->private_data;
578 len=g_slist_length(ndr_pointer_list);
580 ndr_pointer_data_t *tnpd;
581 tnpd=g_slist_nth_data(ndr_pointer_list, i);
583 dcerpc_dissect_fnct_t *fnct;
588 ndr_pointer_list_pos=i+1;
589 di->hf_index=tnpd->hf_index;
590 di->levels=tnpd->levels;
591 /* first a run to handle any conformant
593 di->conformant_run=1;
594 offset = (*(fnct))(tvb, offset, pinfo, NULL, drep);
595 /* now we dissect the actual pointer */
596 di->conformant_run=0;
597 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, drep);
601 } while(found_new_pointer);
608 add_pointer_to_list(packet_info *pinfo, proto_tree *tree,
609 dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index, int levels)
611 ndr_pointer_data_t *npd;
613 /* check if this pointer is valid */
616 dcerpc_call_value *value;
618 di=pinfo->private_data;
622 if(!(pinfo->fd->flags.visited)){
623 if(id>value->max_ptr){
628 /* if we havent seen the request bail out since we cant
629 know whether this is the first non-NULL instance
631 if(value->req_frame==-1){
632 /* XXX THROW EXCEPTION */
635 /* We saw this one in the request frame, nothing to
637 if(id<=value->max_ptr){
643 npd=g_malloc(sizeof(ndr_pointer_data_t));
647 npd->hf_index=hf_index;
649 ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
650 ndr_pointer_list_pos);
651 ndr_pointer_list_pos++;
656 find_pointer_index(guint32 id)
658 ndr_pointer_data_t *npd;
661 len=g_slist_length(ndr_pointer_list);
663 npd=g_slist_nth_data(ndr_pointer_list, i);
674 /* this function dissects an NDR pointer and stores the callback for later deferred dissection.
675 * fnct is the callback function for when we have reached this object in the bytestream.
676 * type is what type of pointer this is
677 * text is what text we should put in any created tree node
678 * hf_index is what hf value we want to pass to the callback function when it is called,
679 * the callback can later pich this one up from di->hf_index.
680 * levels is a generic int we want to pass to teh callback function.
681 * the callback can later pick it up from di->levels
683 * See packet-dcerpc-samr.c for examples
686 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
687 proto_tree *tree, char *drep,
688 dcerpc_dissect_fnct_t *fnct, int type, char *text, int hf_index, int levels)
692 di=pinfo->private_data;
693 if(di->conformant_run){
694 /* this call was only for dissecting the header for any
695 embedded conformant array. we will not parse any
696 pointers in this mode.
701 /*TOP LEVEL REFERENCE POINTER*/
702 if( pointers_are_top_level
703 && (type==NDR_POINTER_REF) ){
704 add_pointer_to_list(pinfo, tree, fnct, 0xffffffff, hf_index, levels);
708 /*TOP LEVEL FULL POINTER*/
709 if( pointers_are_top_level
710 && (type==NDR_POINTER_PTR) ){
716 /* get the referent id */
717 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
719 /* we got a NULL pointer */
721 proto_tree_add_text(tree, tvb, offset-4, 4,
722 "(NULL pointer) %s",text);
726 /* see if we have seen this pointer before */
727 idx=find_pointer_index(id);
729 /* we have seen this pointer before */
731 proto_tree_add_text(tree, tvb, offset-4, 4,
732 "(duplicate PTR) %s",text);
737 item=proto_tree_add_text(tree, tvb, offset-4, 4,
739 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
740 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
741 add_pointer_to_list(pinfo, tr, fnct, id, hf_index, levels);
744 /*TOP LEVEL UNIQUE POINTER*/
745 if( pointers_are_top_level
746 && (type==NDR_POINTER_UNIQUE) ){
752 /* get the referent id */
753 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
755 /* we got a NULL pointer */
757 proto_tree_add_text(tree, tvb, offset-4, 4,
758 "(NULL pointer) %s",text);
763 item=proto_tree_add_text(tree, tvb, offset-4, 4,
765 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
766 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
767 add_pointer_to_list(pinfo, tr, fnct, 0xffffffff, hf_index, levels);
771 /*EMBEDDED REFERENCE POINTER*/
772 if( (!pointers_are_top_level)
773 && (type==NDR_POINTER_REF) ){
778 /* get the referent id */
779 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
782 item=proto_tree_add_text(tree, tvb, offset-4, 4,
784 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
785 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
786 add_pointer_to_list(pinfo, tr, fnct, 0xffffffff, hf_index, levels);
790 /*EMBEDDED UNIQUE POINTER*/
791 if( (!pointers_are_top_level)
792 && (type==NDR_POINTER_UNIQUE) ){
798 /* get the referent id */
799 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
801 /* we got a NULL pointer */
803 proto_tree_add_text(tree, tvb, offset-4, 4,
804 "(NULL pointer) %s", text);
809 item=proto_tree_add_text(tree, tvb, offset-4, 4,
811 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
812 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
813 add_pointer_to_list(pinfo, tr, fnct, 0xffffffff, hf_index, levels);
817 /*EMBEDDED FULL POINTER*/
818 if( (!pointers_are_top_level)
819 && (type==NDR_POINTER_PTR) ){
825 /* get the referent id */
826 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
828 /* we got a NULL pointer */
830 proto_tree_add_text(tree, tvb, offset-4, 4,
831 "(NULL pointer) %s",text);
835 /* see if we have seen this pointer before */
836 idx=find_pointer_index(id);
838 /* we have seen this pointer before */
840 proto_tree_add_text(tree, tvb, offset-4, 4,
841 "(duplicate PTR) %s",text);
846 item=proto_tree_add_text(tree, tvb, offset-4, 4,
848 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
849 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
850 add_pointer_to_list(pinfo, tr, fnct, id, hf_index, levels);
856 /* After each top level pointer we have dissected we have to
857 dissect all deferrals before we move on to the next top level
859 if(pointers_are_top_level==TRUE){
860 pointers_are_top_level=FALSE;
861 offset = dissect_deferred_pointers(pinfo, tree, tvb, offset, drep);
862 pointers_are_top_level=TRUE;
871 dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
872 proto_tree *dcerpc_tree,
873 tvbuff_t *tvb, gint offset,
874 guint16 opnum, gboolean is_rqst,
875 char *drep, dcerpc_info *info)
878 dcerpc_uuid_value *sub_proto;
880 proto_tree *sub_tree = NULL;
881 dcerpc_sub_dissector *proc;
883 dcerpc_dissect_fnct_t *sub_dissect;
884 const char *saved_proto;
885 void *saved_private_data;
887 key.uuid = info->call_data->uuid;
888 key.ver = info->call_data->ver;
891 if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == NULL
892 || !proto_is_protocol_enabled(sub_proto->proto)) {
894 * We don't have a dissector for this UUID, or the protocol
895 * for that UUID is disabled.
897 length = tvb_length_remaining (tvb, offset);
899 proto_tree_add_text (dcerpc_tree, tvb, offset, length,
900 "Stub data (%d byte%s)", length,
901 plurality(length, "", "s"));
907 proto_item *sub_item;
908 sub_item = proto_tree_add_item (tree, sub_proto->proto, tvb, offset,
912 sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
916 for (proc = sub_proto->procs; proc->name; proc++) {
917 if (proc->num == opnum) {
926 if (check_col (pinfo->cinfo, COL_INFO)) {
927 col_add_fstr (pinfo->cinfo, COL_INFO, "%s %s(...)",
928 is_rqst ? "rqst" : "rply", name);
931 if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
932 col_set_str (pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
935 sub_dissect = is_rqst ? proc->dissect_rqst : proc->dissect_resp;
937 saved_proto = pinfo->current_proto;
938 saved_private_data = pinfo->private_data;
939 pinfo->current_proto = sub_proto->name;
940 pinfo->private_data = (void *)info;
942 init_ndr_pointer_list(pinfo);
943 offset = sub_dissect (tvb, offset, pinfo, sub_tree, drep);
945 pinfo->current_proto = saved_proto;
946 pinfo->private_data = saved_private_data;
948 length = tvb_length_remaining (tvb, offset);
950 proto_tree_add_text (sub_tree, tvb, offset, length,
951 "Stub data (%d byte%s)", length,
952 plurality(length, "", "s"));
959 dissect_dcerpc_cn_auth (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
960 e_dce_cn_common_hdr_t *hdr)
966 * The authentication information is at the *end* of the PDU; in
967 * request and response PDUs, the request and response stub data
970 * If the full packet is here, and we've got an auth len, and it's
971 * valid, then dissect the auth info
973 if (tvb_length (tvb) >= hdr->frag_len
975 && (hdr->auth_len + 8 <= hdr->frag_len)) {
977 offset = hdr->frag_len - (hdr->auth_len + 8);
979 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
980 hf_dcerpc_auth_type, NULL);
981 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
982 hf_dcerpc_auth_level, NULL);
983 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
984 hf_dcerpc_auth_pad_len, &auth_pad_len);
985 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
986 hf_dcerpc_auth_rsrvd, NULL);
987 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
988 hf_dcerpc_auth_ctx_id, NULL);
990 proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len, "Auth Data");
992 /* figure out where the auth padding starts */
993 offset = hdr->frag_len - (hdr->auth_len + 8 + auth_pad_len);
994 if (offset > 0 && auth_pad_len) {
995 proto_tree_add_text (dcerpc_tree, tvb, offset,
996 auth_pad_len, "Auth padding");
997 return hdr->auth_len + 8 + auth_pad_len;
999 return hdr->auth_len + 8;
1007 /* We need to hash in the SMB fid number to generate a unique hash table
1008 key as DCERPC over SMB allows several pipes over the same TCP/IP
1011 static guint16 get_smb_fid (void *private_data)
1013 dcerpc_private_info *priv = (dcerpc_private_info *)private_data;
1016 return 0; /* Nothing to see here */
1018 /* DCERPC over smb */
1020 if (priv->transport_type == DCERPC_TRANSPORT_SMB)
1021 return priv->data.smb.fid;
1023 /* Some other transport... */
1029 * Connection oriented packet types
1033 dissect_dcerpc_cn_bind (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1034 e_dce_cn_common_hdr_t *hdr)
1036 conversation_t *conv = NULL;
1037 guint8 num_ctx_items;
1039 gboolean saw_ctx_item = FALSE;
1041 guint16 num_trans_items;
1046 guint16 if_ver, if_ver_minor;
1049 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1050 hf_dcerpc_cn_max_xmit, NULL);
1052 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1053 hf_dcerpc_cn_max_recv, NULL);
1055 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1056 hf_dcerpc_cn_assoc_group, NULL);
1058 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1059 hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
1064 for (i = 0; i < num_ctx_items; i++) {
1065 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1066 hf_dcerpc_cn_ctx_id, &ctx_id);
1068 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1069 hf_dcerpc_cn_num_trans_items, &num_trans_items);
1071 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
1073 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_if_id, tvb,
1075 "Interface UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1076 if_id.Data1, if_id.Data2, if_id.Data3,
1077 if_id.Data4[0], if_id.Data4[1],
1078 if_id.Data4[2], if_id.Data4[3],
1079 if_id.Data4[4], if_id.Data4[5],
1080 if_id.Data4[6], if_id.Data4[7]);
1084 if (hdr->drep[0] & 0x10) {
1085 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1086 hf_dcerpc_cn_bind_if_ver, &if_ver);
1087 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1088 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
1090 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1091 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
1092 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1093 hf_dcerpc_cn_bind_if_ver, &if_ver);
1096 if (!saw_ctx_item) {
1097 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
1098 pinfo->srcport, pinfo->destport, 0);
1100 conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
1101 pinfo->srcport, pinfo->destport, 0);
1104 /* if this is the first time we see this packet, we need to
1105 update the dcerpc_binds table so that any later calls can
1106 match to the interface.
1107 XXX We assume that BINDs will NEVER be fragmented.
1109 if(!(pinfo->fd->flags.visited)){
1110 dcerpc_bind_key *key;
1111 dcerpc_bind_value *value;
1113 key = g_mem_chunk_alloc (dcerpc_bind_key_chunk);
1115 key->ctx_id = ctx_id;
1116 key->smb_fid = get_smb_fid(pinfo->private_data);
1118 value = g_mem_chunk_alloc (dcerpc_bind_value_chunk);
1119 value->uuid = if_id;
1120 value->ver = if_ver;
1122 /* add this entry to the bind table, first removing any
1123 previous ones that are identical
1125 if(g_hash_table_lookup(dcerpc_binds, key)){
1126 g_hash_table_remove(dcerpc_binds, key);
1128 g_hash_table_insert (dcerpc_binds, key, value);
1131 if (check_col (pinfo->cinfo, COL_INFO)) {
1132 col_add_fstr (pinfo->cinfo, COL_INFO, "%s: UUID %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %d.%d",
1133 hdr->ptype == PDU_BIND ? "Bind" : "Alter Ctx",
1134 if_id.Data1, if_id.Data2, if_id.Data3,
1135 if_id.Data4[0], if_id.Data4[1],
1136 if_id.Data4[2], if_id.Data4[3],
1137 if_id.Data4[4], if_id.Data4[5],
1138 if_id.Data4[6], if_id.Data4[7],
1139 if_ver, if_ver_minor);
1141 saw_ctx_item = TRUE;
1144 for (j = 0; j < num_trans_items; j++) {
1145 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
1147 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_trans_id, tvb,
1149 "Transfer Syntax: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1150 trans_id.Data1, trans_id.Data2, trans_id.Data3,
1151 trans_id.Data4[0], trans_id.Data4[1],
1152 trans_id.Data4[2], trans_id.Data4[3],
1153 trans_id.Data4[4], trans_id.Data4[5],
1154 trans_id.Data4[6], trans_id.Data4[7]);
1158 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1159 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
1163 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr);
1167 dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1168 e_dce_cn_common_hdr_t *hdr)
1170 guint16 max_xmit, max_recv;
1171 guint16 sec_addr_len;
1181 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1182 hf_dcerpc_cn_max_xmit, &max_xmit);
1184 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1185 hf_dcerpc_cn_max_recv, &max_recv);
1187 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1188 hf_dcerpc_cn_assoc_group, NULL);
1190 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1191 hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
1192 offset += sec_addr_len;
1195 offset += 4 - offset % 4;
1198 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1199 hf_dcerpc_cn_num_results, &num_results);
1204 for (i = 0; i < num_results; i++) {
1205 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
1206 hdr->drep, hf_dcerpc_cn_ack_result,
1208 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
1209 hdr->drep, hf_dcerpc_cn_ack_reason,
1212 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
1214 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_ack_trans_id, tvb,
1216 "Transfer Syntax: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1217 trans_id.Data1, trans_id.Data2, trans_id.Data3,
1218 trans_id.Data4[0], trans_id.Data4[1],
1219 trans_id.Data4[2], trans_id.Data4[3],
1220 trans_id.Data4[4], trans_id.Data4[5],
1221 trans_id.Data4[6], trans_id.Data4[7]);
1225 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1226 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
1229 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr);
1231 if (check_col (pinfo->cinfo, COL_INFO)) {
1232 if (num_results != 0 && result == 0) {
1233 col_add_fstr (pinfo->cinfo, COL_INFO, "%s ack: accept max_xmit: %d max_recv: %d",
1234 hdr->ptype == PDU_BIND_ACK ? "Bind" : "Alter ctx",
1235 max_xmit, max_recv);
1237 /* FIXME: should put in reason */
1238 col_add_fstr (pinfo->cinfo, COL_INFO, "%s ack: %s",
1239 hdr->ptype == PDU_BIND_ACK ? "Bind" : "Alter ctx",
1240 result == 1 ? "User reject" :
1241 result == 2 ? "Provider reject" :
1248 dissect_dcerpc_cn_rqst (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1249 proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
1251 conversation_t *conv;
1258 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1259 hf_dcerpc_cn_alloc_hint, NULL);
1261 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1262 hf_dcerpc_cn_ctx_id, &ctx_id);
1264 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1265 hf_dcerpc_opnum, &opnum);
1267 if (check_col (pinfo->cinfo, COL_INFO)) {
1268 col_add_fstr (pinfo->cinfo, COL_INFO, "Request: opnum: %d ctx_id:%d",
1272 if (hdr->flags & 0x80) {
1273 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id);
1275 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
1277 "Object UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1278 obj_id.Data1, obj_id.Data2, obj_id.Data3,
1291 auth_sz = dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr);
1293 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
1294 pinfo->srcport, pinfo->destport, 0);
1298 dcerpc_call_value *value;
1299 int length, reported_length, stub_length;
1302 /* !!! we can NOT check flags.visited here since this will interact
1303 badly with when SMB handles (i.e. calls the subdissector)
1304 and desegmented pdu's .
1305 Instead we check if this pdu is already in the matched table or not
1307 if(!g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num)){
1308 dcerpc_bind_key bind_key;
1309 dcerpc_bind_value *bind_value;
1312 bind_key.ctx_id=ctx_id;
1313 bind_key.smb_fid=get_smb_fid(pinfo->private_data);
1315 if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key))){
1316 dcerpc_call_key *call_key;
1317 dcerpc_call_value *call_value;
1319 /* We found the binding so just add the call
1320 to both the call table and the matched table
1322 call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
1323 call_key->conv=conv;
1324 call_key->call_id=hdr->call_id;
1325 call_key->smb_fid=get_smb_fid(pinfo->private_data);
1327 /* if there is already a matching call in the table
1328 remove it so it is replaced with the new one */
1329 if(g_hash_table_lookup(dcerpc_calls, call_key)){
1330 g_hash_table_remove(dcerpc_calls, call_key);
1333 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
1334 call_value->uuid = bind_value->uuid;
1335 call_value->ver = bind_value->ver;
1336 call_value->opnum = opnum;
1337 call_value->req_frame=pinfo->fd->num;
1338 call_value->rep_frame=-1;
1339 call_value->max_ptr=0;
1340 call_value->private_data = NULL;
1341 g_hash_table_insert (dcerpc_calls, call_key, call_value);
1343 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
1347 value=g_hash_table_lookup (dcerpc_matched, (void *)pinfo->fd->num);
1352 /* handoff this call */
1353 length = tvb_length_remaining(tvb, offset);
1354 reported_length = tvb_reported_length_remaining(tvb, offset);
1355 stub_length = hdr->frag_len - offset - auth_sz;
1356 if (length > stub_length)
1357 length = stub_length;
1358 if (reported_length > stub_length)
1359 reported_length = stub_length;
1361 di.call_id = hdr->call_id;
1362 di.smb_fid = get_smb_fid(pinfo->private_data);
1364 di.call_data = value;
1366 if(value->rep_frame!=-1){
1367 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
1368 tvb, 0, 0, value->rep_frame);
1371 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
1372 tvb_new_subset (tvb, offset, length,
1374 0, opnum, TRUE, hdr->drep, &di);
1380 dissect_dcerpc_cn_resp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1381 proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
1383 dcerpc_call_value *value = NULL;
1384 conversation_t *conv;
1389 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1390 hf_dcerpc_cn_alloc_hint, NULL);
1392 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1393 hf_dcerpc_cn_ctx_id, &ctx_id);
1395 if (check_col (pinfo->cinfo, COL_INFO)) {
1396 col_add_fstr (pinfo->cinfo, COL_INFO, "Response: call_id: %d ctx_id:%d",
1397 hdr->call_id, ctx_id);
1400 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1401 hf_dcerpc_cn_cancel_count, NULL);
1405 auth_sz = dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr);
1407 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
1408 pinfo->srcport, pinfo->destport, 0);
1410 /* no point in creating one here, really */
1413 /* !!! we can NOT check flags.visited here since this will interact
1414 badly with when SMB handles (i.e. calls the subdissector)
1415 and desegmented pdu's .
1416 Instead we check if this pdu is already in the matched table or not
1418 if(!g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num)){
1419 dcerpc_call_key call_key;
1420 dcerpc_call_value *call_value;
1423 call_key.call_id=hdr->call_id;
1424 call_key.smb_fid=get_smb_fid(pinfo->private_data);
1426 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
1427 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
1428 if(call_value->rep_frame==-1){
1429 call_value->rep_frame=pinfo->fd->num;
1435 value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
1438 int length, reported_length, stub_length;
1441 /* handoff this call */
1442 length = tvb_length_remaining(tvb, offset);
1443 reported_length = tvb_reported_length_remaining(tvb, offset);
1444 stub_length = hdr->frag_len - offset - auth_sz;
1445 if (length > stub_length)
1446 length = stub_length;
1447 if (reported_length > stub_length)
1448 reported_length = stub_length;
1450 di.call_id = hdr->call_id;
1451 di.smb_fid = get_smb_fid(pinfo->private_data);
1453 di.call_data = value;
1455 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
1456 if(value->req_frame!=-1){
1457 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
1458 tvb, 0, 0, value->req_frame);
1461 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
1462 tvb_new_subset (tvb, offset, length,
1464 0, value->opnum, FALSE, hdr->drep, &di);
1470 * DCERPC dissector for connection oriented calls
1473 dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
1474 proto_tree *tree, gboolean can_desegment)
1476 static char nulls[4] = { 0 };
1479 proto_item *ti = NULL;
1480 proto_item *tf = NULL;
1481 proto_tree *dcerpc_tree = NULL;
1482 proto_tree *cn_flags_tree = NULL;
1483 proto_tree *drep_tree = NULL;
1484 e_dce_cn_common_hdr_t hdr;
1487 * when done over nbt, dcerpc requests are padded with 4 bytes of null
1488 * data for some reason.
1490 * XXX - if that's always the case, the right way to do this would
1491 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
1492 * the 4 bytes of null padding, and make that the dissector
1493 * used for "netbios".
1495 if (tvb_bytes_exist (tvb, offset, 4) &&
1496 tvb_memeql (tvb, offset, nulls, 4) == 0) {
1506 * Check if this looks like a C/O DCERPC call
1508 if (!tvb_bytes_exist (tvb, offset, sizeof (hdr))) {
1511 start_offset = offset;
1512 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
1513 if (hdr.rpc_ver != 5)
1515 hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
1516 if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
1518 hdr.ptype = tvb_get_guint8 (tvb, offset++);
1522 if (check_col (pinfo->cinfo, COL_PROTOCOL))
1523 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
1524 if (check_col (pinfo->cinfo, COL_INFO))
1525 col_set_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
1527 hdr.flags = tvb_get_guint8 (tvb, offset++);
1528 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
1529 offset += sizeof (hdr.drep);
1531 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1533 hdr.auth_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1535 hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
1538 offset = start_offset;
1539 if (can_desegment && pinfo->can_desegment
1540 && hdr.frag_len > tvb_length_remaining (tvb, offset)) {
1541 pinfo->desegment_offset = offset;
1542 pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, offset);
1543 return 0; /* desegmentation required */
1547 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE);
1549 dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
1551 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver);
1552 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset++, 1, hdr.rpc_ver_minor);
1553 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype);
1554 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
1555 cn_flags_tree = proto_item_add_subtree (tf, ett_dcerpc_cn_flags);
1556 if (cn_flags_tree) {
1557 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
1558 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
1559 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
1560 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
1561 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
1562 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
1563 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
1564 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
1568 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
1569 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
1571 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
1572 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
1573 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
1575 offset += sizeof (hdr.drep);
1577 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
1580 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
1583 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
1589 * Packet type specific stuff is next.
1591 switch (hdr.ptype) {
1594 dissect_dcerpc_cn_bind (tvb, pinfo, dcerpc_tree, &hdr);
1599 dissect_dcerpc_cn_bind_ack (tvb, pinfo, dcerpc_tree, &hdr);
1603 dissect_dcerpc_cn_rqst (tvb, pinfo, dcerpc_tree, tree, &hdr);
1607 dissect_dcerpc_cn_resp (tvb, pinfo, dcerpc_tree, tree, &hdr);
1611 /* might as well dissect the auth info */
1612 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr);
1615 return hdr.frag_len + padding;
1619 * DCERPC dissector for connection oriented calls over packet-oriented
1623 dissect_dcerpc_cn_pk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1626 * Only one PDU per transport packet, and only one transport
1629 if (dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE) == -1) {
1631 * It wasn't a DCERPC PDU.
1643 * DCERPC dissector for connection oriented calls over byte-stream
1647 dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1651 gboolean ret = FALSE;
1654 * There may be multiple PDUs per transport packet; keep
1657 while (tvb_reported_length_remaining(tvb, offset) != 0) {
1658 pdu_len = dissect_dcerpc_cn (tvb, offset, pinfo, tree,
1659 dcerpc_cn_desegment);
1660 if (pdu_len == -1) {
1668 * Well, we've seen at least one DCERPC PDU.
1674 * Desegmentation required - bail now.
1680 * Step to the next PDU.
1688 * DCERPC dissector for connectionless calls
1691 dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1693 proto_item *ti = NULL;
1694 proto_item *tf = NULL;
1695 proto_tree *dcerpc_tree = NULL;
1696 proto_tree *dg_flags1_tree = NULL;
1697 proto_tree *dg_flags2_tree = NULL;
1698 proto_tree *drep_tree = NULL;
1699 e_dce_dg_common_hdr_t hdr;
1701 conversation_t *conv;
1704 * Check if this looks like a CL DCERPC call. All dg packets
1705 * have an 80 byte header on them. Which starts with
1706 * version (4), pkt_type.
1708 if (!tvb_bytes_exist (tvb, 0, sizeof (hdr))) {
1711 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
1712 if (hdr.rpc_ver != 4)
1714 hdr.ptype = tvb_get_guint8 (tvb, offset++);
1718 if (check_col (pinfo->cinfo, COL_PROTOCOL))
1719 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
1720 if (check_col (pinfo->cinfo, COL_INFO))
1721 col_set_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
1723 hdr.flags1 = tvb_get_guint8 (tvb, offset++);
1724 hdr.flags2 = tvb_get_guint8 (tvb, offset++);
1725 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
1726 offset += sizeof (hdr.drep);
1727 hdr.serial_hi = tvb_get_guint8 (tvb, offset++);
1728 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.obj_id);
1730 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.if_id);
1732 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.act_id);
1734 hdr.server_boot = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
1736 hdr.if_ver = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
1738 hdr.seqnum = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
1740 hdr.opnum = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1742 hdr.ihint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1744 hdr.ahint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1746 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1748 hdr.frag_num = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1750 hdr.auth_proto = tvb_get_guint8 (tvb, offset++);
1751 hdr.serial_lo = tvb_get_guint8 (tvb, offset++);
1754 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, -1, FALSE);
1756 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
1759 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver);
1761 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype);
1763 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
1764 dg_flags1_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags1);
1765 if (dg_flags1_tree) {
1766 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
1767 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
1768 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
1769 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
1770 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
1771 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
1772 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
1773 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
1777 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
1778 dg_flags2_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags2);
1779 if (dg_flags2_tree) {
1780 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
1781 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
1782 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
1783 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
1784 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
1785 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
1786 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
1787 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
1791 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
1792 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
1794 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
1795 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
1796 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
1798 offset += sizeof (hdr.drep);
1800 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset++, 1, hdr.serial_hi);
1802 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
1804 "Object: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1805 hdr.obj_id.Data1, hdr.obj_id.Data2, hdr.obj_id.Data3,
1806 hdr.obj_id.Data4[0],
1807 hdr.obj_id.Data4[1],
1808 hdr.obj_id.Data4[2],
1809 hdr.obj_id.Data4[3],
1810 hdr.obj_id.Data4[4],
1811 hdr.obj_id.Data4[5],
1812 hdr.obj_id.Data4[6],
1813 hdr.obj_id.Data4[7]);
1816 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
1818 "Interface: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1819 hdr.if_id.Data1, hdr.if_id.Data2, hdr.if_id.Data3,
1827 hdr.if_id.Data4[7]);
1830 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
1832 "Activity: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1833 hdr.act_id.Data1, hdr.act_id.Data2, hdr.act_id.Data3,
1834 hdr.act_id.Data4[0],
1835 hdr.act_id.Data4[1],
1836 hdr.act_id.Data4[2],
1837 hdr.act_id.Data4[3],
1838 hdr.act_id.Data4[4],
1839 hdr.act_id.Data4[5],
1840 hdr.act_id.Data4[6],
1841 hdr.act_id.Data4[7]);
1844 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_server_boot, tvb, offset, 4, hdr.server_boot);
1847 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
1850 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
1853 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
1856 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
1859 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
1862 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
1865 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
1868 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
1871 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
1875 * keeping track of the conversation shouldn't really be necessary
1876 * for connectionless packets, because everything we need to know
1877 * to dissect is in the header for each packet. Unfortunately,
1878 * Microsoft's implementation is buggy and often puts the
1879 * completely wrong if_id in the header. go figure. So, keep
1880 * track of the seqnum and use that if possible. Note: that's not
1881 * completely correct. It should really be done based on both the
1882 * activity_id and seqnum. I haven't seen anywhere that it would
1883 * make a difference, but for future reference...
1885 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
1886 pinfo->srcport, pinfo->destport, 0);
1888 conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
1889 pinfo->srcport, pinfo->destport, 0);
1893 * Packet type specific stuff is next.
1896 switch (hdr.ptype) {
1898 dcerpc_call_value *value, v;
1902 if(!(pinfo->fd->flags.visited)){
1903 dcerpc_call_value *call_value;
1904 dcerpc_call_key *call_key;
1906 call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
1907 call_key->conv=conv;
1908 call_key->call_id=hdr.seqnum;
1909 call_key->smb_fid=get_smb_fid(pinfo->private_data);
1911 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
1912 call_value->uuid = hdr.if_id;
1913 call_value->ver = hdr.if_ver;
1914 call_value->opnum = hdr.opnum;
1915 call_value->req_frame=pinfo->fd->num;
1916 call_value->rep_frame=-1;
1917 call_value->max_ptr=0;
1918 call_value->private_data = NULL;
1919 g_hash_table_insert (dcerpc_calls, call_key, call_value);
1921 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
1924 value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
1928 v.opnum = hdr.opnum;
1929 v.req_frame = pinfo->fd->num;
1932 v.private_data=NULL;
1937 di.call_id = hdr.seqnum;
1940 di.call_data = value;
1942 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, tvb, offset,
1943 hdr.opnum, TRUE, hdr.drep, &di);
1946 if(!(pinfo->fd->flags.visited)){
1947 dcerpc_call_value *call_value;
1948 dcerpc_call_key call_key;
1951 call_key.call_id=hdr.seqnum;
1952 call_key.smb_fid=get_smb_fid(pinfo->private_data);
1954 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
1955 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
1956 if(call_value->rep_frame==-1){
1957 call_value->rep_frame=pinfo->fd->num;
1962 value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
1966 v.opnum = hdr.opnum;
1968 v.rep_frame=pinfo->fd->num;
1969 v.private_data=NULL;
1977 di.call_data = value;
1979 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, tvb, offset,
1980 value->opnum, FALSE, hdr.drep, &di);
1988 dcerpc_init_protocol (void)
1990 /* structures and data for BIND */
1992 g_hash_table_destroy (dcerpc_binds);
1994 dcerpc_binds = g_hash_table_new (dcerpc_bind_hash, dcerpc_bind_equal);
1996 if (dcerpc_bind_key_chunk){
1997 g_mem_chunk_destroy (dcerpc_bind_key_chunk);
1999 dcerpc_bind_key_chunk = g_mem_chunk_new ("dcerpc_bind_key_chunk",
2000 sizeof (dcerpc_bind_key),
2001 200 * sizeof (dcerpc_bind_key),
2003 if (dcerpc_bind_value_chunk){
2004 g_mem_chunk_destroy (dcerpc_bind_value_chunk);
2006 dcerpc_bind_value_chunk = g_mem_chunk_new ("dcerpc_bind_value_chunk",
2007 sizeof (dcerpc_bind_value),
2008 200 * sizeof (dcerpc_bind_value),
2010 /* structures and data for CALL */
2012 g_hash_table_destroy (dcerpc_calls);
2014 dcerpc_calls = g_hash_table_new (dcerpc_call_hash, dcerpc_call_equal);
2015 if (dcerpc_call_key_chunk){
2016 g_mem_chunk_destroy (dcerpc_call_key_chunk);
2018 dcerpc_call_key_chunk = g_mem_chunk_new ("dcerpc_call_key_chunk",
2019 sizeof (dcerpc_call_key),
2020 200 * sizeof (dcerpc_call_key),
2022 if (dcerpc_call_value_chunk){
2023 g_mem_chunk_destroy (dcerpc_call_value_chunk);
2025 dcerpc_call_value_chunk = g_mem_chunk_new ("dcerpc_call_value_chunk",
2026 sizeof (dcerpc_call_value),
2027 200 * sizeof (dcerpc_call_value),
2030 /* structure and data for MATCHED */
2031 if (dcerpc_matched){
2032 g_hash_table_destroy (dcerpc_matched);
2034 dcerpc_matched = g_hash_table_new (dcerpc_matched_hash, dcerpc_matched_equal);
2039 proto_register_dcerpc (void)
2041 static hf_register_info hf[] = {
2042 { &hf_dcerpc_request_in,
2043 { "Request in", "dcerpc.request_in", FT_UINT32, BASE_DEC,
2044 NULL, 0, "This packet is a response to the packet in this frame", HFILL }},
2045 { &hf_dcerpc_response_in,
2046 { "Response in", "dcerpc.response_in", FT_UINT32, BASE_DEC,
2047 NULL, 0, "The response to this packet is in this packet", HFILL }},
2048 { &hf_dcerpc_referent_id,
2049 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
2050 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
2052 { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2053 { &hf_dcerpc_ver_minor,
2054 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2055 { &hf_dcerpc_packet_type,
2056 { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_HEX, VALS (pckt_vals), 0x0, "", HFILL }},
2057 { &hf_dcerpc_cn_flags,
2058 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
2059 { &hf_dcerpc_cn_flags_first_frag,
2060 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x1, "", HFILL }},
2061 { &hf_dcerpc_cn_flags_last_frag,
2062 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x2, "", HFILL }},
2063 { &hf_dcerpc_cn_flags_cancel_pending,
2064 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x4, "", HFILL }},
2065 { &hf_dcerpc_cn_flags_reserved,
2066 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x8, "", HFILL }},
2067 { &hf_dcerpc_cn_flags_mpx,
2068 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x10, "", HFILL }},
2069 { &hf_dcerpc_cn_flags_dne,
2070 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x20, "", HFILL }},
2071 { &hf_dcerpc_cn_flags_maybe,
2072 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x40, "", HFILL }},
2073 { &hf_dcerpc_cn_flags_object,
2074 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x80, "", HFILL }},
2076 { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
2077 { &hf_dcerpc_drep_byteorder,
2078 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS (drep_byteorder_vals), 0x0, "", HFILL }},
2079 { &hf_dcerpc_drep_character,
2080 { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS (drep_character_vals), 0x0, "", HFILL }},
2081 { &hf_dcerpc_drep_fp,
2082 { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS (drep_fp_vals), 0x0, "", HFILL }},
2083 { &hf_dcerpc_cn_frag_len,
2084 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2085 { &hf_dcerpc_cn_auth_len,
2086 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2087 { &hf_dcerpc_cn_call_id,
2088 { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2089 { &hf_dcerpc_cn_max_xmit,
2090 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2091 { &hf_dcerpc_cn_max_recv,
2092 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2093 { &hf_dcerpc_cn_assoc_group,
2094 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
2095 { &hf_dcerpc_cn_num_ctx_items,
2096 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2097 { &hf_dcerpc_cn_ctx_id,
2098 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2099 { &hf_dcerpc_cn_num_trans_items,
2100 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2101 { &hf_dcerpc_cn_bind_if_id,
2102 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2103 { &hf_dcerpc_cn_bind_if_ver,
2104 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2105 { &hf_dcerpc_cn_bind_if_ver_minor,
2106 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2107 { &hf_dcerpc_cn_bind_trans_id,
2108 { "Transfer Syntax", "dcerpc.cn_bind_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2109 { &hf_dcerpc_cn_bind_trans_ver,
2110 { "Syntax ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2111 { &hf_dcerpc_cn_alloc_hint,
2112 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2113 { &hf_dcerpc_cn_sec_addr_len,
2114 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2115 { &hf_dcerpc_cn_num_results,
2116 { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2117 { &hf_dcerpc_cn_ack_result,
2118 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2119 { &hf_dcerpc_cn_ack_reason,
2120 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2121 { &hf_dcerpc_cn_ack_trans_id,
2122 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2123 { &hf_dcerpc_cn_ack_trans_ver,
2124 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2125 { &hf_dcerpc_cn_cancel_count,
2126 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2127 { &hf_dcerpc_auth_type,
2128 { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2129 { &hf_dcerpc_auth_level,
2130 { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2131 { &hf_dcerpc_auth_pad_len,
2132 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2133 { &hf_dcerpc_auth_rsrvd,
2134 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2135 { &hf_dcerpc_auth_ctx_id,
2136 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2137 { &hf_dcerpc_dg_flags1,
2138 { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
2139 { &hf_dcerpc_dg_flags1_rsrvd_01,
2140 { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x01, "", HFILL }},
2141 { &hf_dcerpc_dg_flags1_last_frag,
2142 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x02, "", HFILL }},
2143 { &hf_dcerpc_dg_flags1_frag,
2144 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x04, "", HFILL }},
2145 { &hf_dcerpc_dg_flags1_nofack,
2146 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x08, "", HFILL }},
2147 { &hf_dcerpc_dg_flags1_maybe,
2148 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x10, "", HFILL }},
2149 { &hf_dcerpc_dg_flags1_idempotent,
2150 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x20, "", HFILL }},
2151 { &hf_dcerpc_dg_flags1_broadcast,
2152 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x40, "", HFILL }},
2153 { &hf_dcerpc_dg_flags1_rsrvd_80,
2154 { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x80, "", HFILL }},
2155 { &hf_dcerpc_dg_flags2,
2156 { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
2157 { &hf_dcerpc_dg_flags2_rsrvd_01,
2158 { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x01, "", HFILL }},
2159 { &hf_dcerpc_dg_flags2_cancel_pending,
2160 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x02, "", HFILL }},
2161 { &hf_dcerpc_dg_flags2_rsrvd_04,
2162 { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x04, "", HFILL }},
2163 { &hf_dcerpc_dg_flags2_rsrvd_08,
2164 { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x08, "", HFILL }},
2165 { &hf_dcerpc_dg_flags2_rsrvd_10,
2166 { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x10, "", HFILL }},
2167 { &hf_dcerpc_dg_flags2_rsrvd_20,
2168 { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x20, "", HFILL }},
2169 { &hf_dcerpc_dg_flags2_rsrvd_40,
2170 { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x40, "", HFILL }},
2171 { &hf_dcerpc_dg_flags2_rsrvd_80,
2172 { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x80, "", HFILL }},
2173 { &hf_dcerpc_dg_serial_lo,
2174 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
2175 { &hf_dcerpc_dg_serial_hi,
2176 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
2177 { &hf_dcerpc_dg_ahint,
2178 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
2179 { &hf_dcerpc_dg_ihint,
2180 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
2181 { &hf_dcerpc_dg_frag_len,
2182 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2183 { &hf_dcerpc_dg_frag_num,
2184 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2185 { &hf_dcerpc_dg_auth_proto,
2186 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
2187 { &hf_dcerpc_dg_seqnum,
2188 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
2189 { &hf_dcerpc_dg_server_boot,
2190 { "Server boot time", "dcerpc.dg_server_boot", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
2191 { &hf_dcerpc_dg_if_ver,
2192 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2193 { &hf_dcerpc_obj_id,
2194 { "Object", "dcerpc.obj_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2195 { &hf_dcerpc_dg_if_id,
2196 { "Interface", "dcerpc.dg_if_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2197 { &hf_dcerpc_dg_act_id,
2198 { "Activitiy", "dcerpc.dg_act_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2200 { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2201 { &hf_dcerpc_array_max_count,
2202 { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
2204 { &hf_dcerpc_array_offset,
2205 { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
2207 { &hf_dcerpc_array_actual_count,
2208 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
2212 static gint *ett[] = {
2214 &ett_dcerpc_cn_flags,
2216 &ett_dcerpc_dg_flags1,
2217 &ett_dcerpc_dg_flags2,
2218 &ett_dcerpc_pointer_data,
2221 proto_dcerpc = proto_register_protocol ("DCE RPC", "DCERPC", "dcerpc");
2222 proto_register_field_array (proto_dcerpc, hf, array_length (hf));
2223 proto_register_subtree_array (ett, array_length (ett));
2224 register_init_routine (dcerpc_init_protocol);
2226 prefs_register_bool_preference (prefs_register_protocol (proto_dcerpc,
2229 "Desegment all DCE/RPC over TCP",
2230 "Whether the DCE/RPC dissector should desegment all DCE/RPC over TCP",
2231 &dcerpc_cn_desegment);
2232 dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
2236 proto_reg_handoff_dcerpc (void)
2238 heur_dissector_add ("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
2239 heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
2240 heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
2241 heur_dissector_add ("smb_transact", dissect_dcerpc_cn_bs, proto_dcerpc);