2 * Routines for DCERPC packet disassembly
3 * Copyright 2001, Todd Sabin <tas@webspan.net>
5 * $Id: packet-dcerpc.c,v 1.44 2002/04/22 09:43:03 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 = {
93 * Authentication services.
95 static const value_string authn_protocol_vals[] = {
104 #define DCE_C_AUTHN_LEVEL_NONE 1
105 #define DCE_C_AUTHN_LEVEL_CONNECT 2
106 #define DCE_C_AUTHN_LEVEL_CALL 3
107 #define DCE_C_AUTHN_LEVEL_PKT 4
108 #define DCE_C_AUTHN_LEVEL_PKT_INTEGRITY 5
109 #define DCE_C_AUTHN_LEVEL_PKT_PRIVACY 6
111 static const value_string authn_level_vals[] = {
112 { DCE_C_AUTHN_LEVEL_NONE, "None" },
113 { DCE_C_AUTHN_LEVEL_CONNECT, "Connect" },
114 { DCE_C_AUTHN_LEVEL_CALL, "Call" },
115 { DCE_C_AUTHN_LEVEL_PKT, "Packet" },
116 { DCE_C_AUTHN_LEVEL_PKT_INTEGRITY, "Packet integrity" },
117 { DCE_C_AUTHN_LEVEL_PKT_PRIVACY, "Packet privacy" },
121 static int proto_dcerpc = -1;
124 static int hf_dcerpc_request_in = -1;
125 static int hf_dcerpc_response_in = -1;
126 static int hf_dcerpc_ver = -1;
127 static int hf_dcerpc_ver_minor = -1;
128 static int hf_dcerpc_packet_type = -1;
129 static int hf_dcerpc_cn_flags = -1;
130 static int hf_dcerpc_cn_flags_first_frag = -1;
131 static int hf_dcerpc_cn_flags_last_frag = -1;
132 static int hf_dcerpc_cn_flags_cancel_pending = -1;
133 static int hf_dcerpc_cn_flags_reserved = -1;
134 static int hf_dcerpc_cn_flags_mpx = -1;
135 static int hf_dcerpc_cn_flags_dne = -1;
136 static int hf_dcerpc_cn_flags_maybe = -1;
137 static int hf_dcerpc_cn_flags_object = -1;
138 static int hf_dcerpc_drep = -1;
139 static int hf_dcerpc_drep_byteorder = -1;
140 static int hf_dcerpc_drep_character = -1;
141 static int hf_dcerpc_drep_fp = -1;
142 static int hf_dcerpc_cn_frag_len = -1;
143 static int hf_dcerpc_cn_auth_len = -1;
144 static int hf_dcerpc_cn_call_id = -1;
145 static int hf_dcerpc_cn_max_xmit = -1;
146 static int hf_dcerpc_cn_max_recv = -1;
147 static int hf_dcerpc_cn_assoc_group = -1;
148 static int hf_dcerpc_cn_num_ctx_items = -1;
149 static int hf_dcerpc_cn_ctx_id = -1;
150 static int hf_dcerpc_cn_num_trans_items = -1;
151 static int hf_dcerpc_cn_bind_if_id = -1;
152 static int hf_dcerpc_cn_bind_if_ver = -1;
153 static int hf_dcerpc_cn_bind_if_ver_minor = -1;
154 static int hf_dcerpc_cn_bind_trans_id = -1;
155 static int hf_dcerpc_cn_bind_trans_ver = -1;
156 static int hf_dcerpc_cn_alloc_hint = -1;
157 static int hf_dcerpc_cn_sec_addr_len = -1;
158 static int hf_dcerpc_cn_sec_addr = -1;
159 static int hf_dcerpc_cn_num_results = -1;
160 static int hf_dcerpc_cn_ack_result = -1;
161 static int hf_dcerpc_cn_ack_reason = -1;
162 static int hf_dcerpc_cn_ack_trans_id = -1;
163 static int hf_dcerpc_cn_ack_trans_ver = -1;
164 static int hf_dcerpc_cn_cancel_count = -1;
165 static int hf_dcerpc_auth_type = -1;
166 static int hf_dcerpc_auth_level = -1;
167 static int hf_dcerpc_auth_pad_len = -1;
168 static int hf_dcerpc_auth_rsrvd = -1;
169 static int hf_dcerpc_auth_ctx_id = -1;
170 static int hf_dcerpc_dg_flags1 = -1;
171 static int hf_dcerpc_dg_flags1_rsrvd_01 = -1;
172 static int hf_dcerpc_dg_flags1_last_frag = -1;
173 static int hf_dcerpc_dg_flags1_frag = -1;
174 static int hf_dcerpc_dg_flags1_nofack = -1;
175 static int hf_dcerpc_dg_flags1_maybe = -1;
176 static int hf_dcerpc_dg_flags1_idempotent = -1;
177 static int hf_dcerpc_dg_flags1_broadcast = -1;
178 static int hf_dcerpc_dg_flags1_rsrvd_80 = -1;
179 static int hf_dcerpc_dg_flags2 = -1;
180 static int hf_dcerpc_dg_flags2_rsrvd_01 = -1;
181 static int hf_dcerpc_dg_flags2_cancel_pending = -1;
182 static int hf_dcerpc_dg_flags2_rsrvd_04 = -1;
183 static int hf_dcerpc_dg_flags2_rsrvd_08 = -1;
184 static int hf_dcerpc_dg_flags2_rsrvd_10 = -1;
185 static int hf_dcerpc_dg_flags2_rsrvd_20 = -1;
186 static int hf_dcerpc_dg_flags2_rsrvd_40 = -1;
187 static int hf_dcerpc_dg_flags2_rsrvd_80 = -1;
188 static int hf_dcerpc_dg_serial_hi = -1;
189 static int hf_dcerpc_obj_id = -1;
190 static int hf_dcerpc_dg_if_id = -1;
191 static int hf_dcerpc_dg_act_id = -1;
192 static int hf_dcerpc_dg_serial_lo = -1;
193 static int hf_dcerpc_dg_ahint = -1;
194 static int hf_dcerpc_dg_ihint = -1;
195 static int hf_dcerpc_dg_frag_len = -1;
196 static int hf_dcerpc_dg_frag_num = -1;
197 static int hf_dcerpc_dg_auth_proto = -1;
198 static int hf_dcerpc_opnum = -1;
199 static int hf_dcerpc_dg_seqnum = -1;
200 static int hf_dcerpc_dg_server_boot = -1;
201 static int hf_dcerpc_dg_if_ver = -1;
202 static int hf_dcerpc_array_max_count = -1;
203 static int hf_dcerpc_array_offset = -1;
204 static int hf_dcerpc_array_actual_count = -1;
205 static int hf_dcerpc_op = -1;
206 static int hf_dcerpc_referent_id = -1;
208 static gint ett_dcerpc = -1;
209 static gint ett_dcerpc_cn_flags = -1;
210 static gint ett_dcerpc_drep = -1;
211 static gint ett_dcerpc_dg_flags1 = -1;
212 static gint ett_dcerpc_dg_flags2 = -1;
213 static gint ett_dcerpc_pointer_data = -1;
215 /* try to desegment big DCE/RPC packets over TCP? */
216 static gboolean dcerpc_cn_desegment = TRUE;
223 /* the registered subdissectors */
224 static GHashTable *dcerpc_uuids;
226 typedef struct _dcerpc_uuid_key {
231 typedef struct _dcerpc_uuid_value {
235 dcerpc_sub_dissector *procs;
239 dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2)
241 dcerpc_uuid_key *key1 = (dcerpc_uuid_key *)k1;
242 dcerpc_uuid_key *key2 = (dcerpc_uuid_key *)k2;
243 return ((memcmp (&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
244 && (key1->ver == key2->ver));
248 dcerpc_uuid_hash (gconstpointer k)
250 dcerpc_uuid_key *key = (dcerpc_uuid_key *)k;
251 /* This isn't perfect, but the Data1 part of these is almost always
253 return key->uuid.Data1;
257 dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver,
258 dcerpc_sub_dissector *procs)
260 dcerpc_uuid_key *key = g_malloc (sizeof (*key));
261 dcerpc_uuid_value *value = g_malloc (sizeof (*value));
266 value->proto = proto;
268 value->name = proto_get_protocol_short_name (proto);
269 value->procs = procs;
271 g_hash_table_insert (dcerpc_uuids, key, value);
276 * To keep track of ctx_id mappings.
278 * Everytime we see a bind call we update this table.
279 * Note that we always specify a SMB FID. For non-SMB transports this
282 static GHashTable *dcerpc_binds=NULL;
284 typedef struct _dcerpc_bind_key {
285 conversation_t *conv;
290 typedef struct _dcerpc_bind_value {
295 static GMemChunk *dcerpc_bind_key_chunk=NULL;
296 static GMemChunk *dcerpc_bind_value_chunk=NULL;
299 dcerpc_bind_equal (gconstpointer k1, gconstpointer k2)
301 dcerpc_bind_key *key1 = (dcerpc_bind_key *)k1;
302 dcerpc_bind_key *key2 = (dcerpc_bind_key *)k2;
303 return (key1->conv == key2->conv
304 && key1->ctx_id == key2->ctx_id
305 && key1->smb_fid == key2->smb_fid);
309 dcerpc_bind_hash (gconstpointer k)
311 dcerpc_bind_key *key = (dcerpc_bind_key *)k;
312 return ((guint)key->conv) + key->ctx_id + key->smb_fid;
316 * To keep track of callid mappings. Should really use some generic
317 * conversation support instead.
319 static GHashTable *dcerpc_calls=NULL;
321 typedef struct _dcerpc_call_key {
322 conversation_t *conv;
327 static GMemChunk *dcerpc_call_key_chunk=NULL;
329 static GMemChunk *dcerpc_call_value_chunk=NULL;
332 dcerpc_call_equal (gconstpointer k1, gconstpointer k2)
334 dcerpc_call_key *key1 = (dcerpc_call_key *)k1;
335 dcerpc_call_key *key2 = (dcerpc_call_key *)k2;
336 return (key1->conv == key2->conv
337 && key1->call_id == key2->call_id
338 && key1->smb_fid == key2->smb_fid);
342 dcerpc_call_hash (gconstpointer k)
344 dcerpc_call_key *key = (dcerpc_call_key *)k;
345 return ((guint32)key->conv) + key->call_id + key->smb_fid;
349 /* to keep track of matched calls/responses
350 this one uses the same value struct as calls, but the key is the frame id
352 static GHashTable *dcerpc_matched=NULL;
354 dcerpc_matched_equal (gconstpointer k1, gconstpointer k2)
356 return (guint32)k1 == (guint32)k2;
360 dcerpc_matched_hash (gconstpointer k)
368 * Utility functions. Modeled after packet-rpc.c
372 dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo,
373 proto_tree *tree, char *drep,
374 int hfindex, guint8 *pdata)
378 data = tvb_get_guint8 (tvb, offset);
380 proto_tree_add_item (tree, hfindex, tvb, offset, 1, (drep[0] & 0x10));
388 dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo,
389 proto_tree *tree, char *drep,
390 int hfindex, guint16 *pdata)
394 data = ((drep[0] & 0x10)
395 ? tvb_get_letohs (tvb, offset)
396 : tvb_get_ntohs (tvb, offset));
399 proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10));
407 dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo,
408 proto_tree *tree, char *drep,
409 int hfindex, guint32 *pdata)
413 data = ((drep[0] & 0x10)
414 ? tvb_get_letohl (tvb, offset)
415 : tvb_get_ntohl (tvb, offset));
418 proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10));
426 dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo,
427 proto_tree *tree, char *drep,
428 int hfindex, unsigned char *pdata)
431 tvb_memcpy(tvb, pdata, offset, 8);
432 if(drep[0] & 0x10){/* XXX this might be the wrong way around */
434 data=pdata[0];pdata[0]=pdata[7];pdata[7]=data;
435 data=pdata[1];pdata[1]=pdata[6];pdata[6]=data;
436 data=pdata[2];pdata[2]=pdata[5];pdata[5]=data;
437 data=pdata[3];pdata[3]=pdata[4];pdata[4]=data;
442 proto_tree_add_item(tree, hfindex, tvb, offset, 8, (drep[0] & 0x10));
449 * a couple simpler things
452 dcerpc_tvb_get_ntohs (tvbuff_t *tvb, gint offset, char *drep)
454 if (drep[0] & 0x10) {
455 return tvb_get_letohs (tvb, offset);
457 return tvb_get_ntohs (tvb, offset);
462 dcerpc_tvb_get_ntohl (tvbuff_t *tvb, gint offset, char *drep)
464 if (drep[0] & 0x10) {
465 return tvb_get_letohl (tvb, offset);
467 return tvb_get_ntohl (tvb, offset);
472 dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, char *drep, e_uuid_t *uuid)
475 uuid->Data1 = dcerpc_tvb_get_ntohl (tvb, offset, drep);
476 uuid->Data2 = dcerpc_tvb_get_ntohs (tvb, offset+4, drep);
477 uuid->Data3 = dcerpc_tvb_get_ntohs (tvb, offset+6, drep);
479 for (i=0; i<sizeof (uuid->Data4); i++) {
480 uuid->Data4[i] = tvb_get_guint8 (tvb, offset+8+i);
487 /* function to dissect a unidimensional conformant array */
489 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
490 proto_tree *tree, char *drep,
491 dcerpc_dissect_fnct_t *fnct)
496 di=pinfo->private_data;
497 if(di->conformant_run){
498 /* conformant run, just dissect the max_count header */
499 di->conformant_run=0;
500 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
501 hf_dcerpc_array_max_count, &di->array_max_count);
502 di->array_max_count_offset=offset-4;
503 di->conformant_run=1;
505 /* we dont dont remember where in the bytestream this fields was */
506 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
508 /* real run, dissect the elements */
509 for(i=0;i<di->array_max_count;i++){
510 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
516 /* function to dissect a unidimensional conformant and varying array */
518 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
519 proto_tree *tree, char *drep,
520 dcerpc_dissect_fnct_t *fnct)
525 di=pinfo->private_data;
526 if(di->conformant_run){
527 /* conformant run, just dissect the max_count header */
528 di->conformant_run=0;
529 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
530 hf_dcerpc_array_max_count, &di->array_max_count);
531 di->array_max_count_offset=offset-4;
532 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
533 hf_dcerpc_array_offset, &di->array_offset);
534 di->array_offset_offset=offset-4;
535 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
536 hf_dcerpc_array_actual_count, &di->array_actual_count);
537 di->array_actual_count_offset=offset-4;
538 di->conformant_run=1;
540 /* we dont dont remember where in the bytestream these fields were */
541 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
542 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
543 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
545 /* real run, dissect the elements */
546 for(i=0;i<di->array_actual_count;i++){
547 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
555 /* ndr pointer handling */
556 /* list of pointers encountered so far */
557 static GSList *ndr_pointer_list = NULL;
559 /* position where in the list to insert newly encountered pointers */
560 static int ndr_pointer_list_pos=0;
562 /* boolean controlling whether pointers are top-level or embedded */
563 static gboolean pointers_are_top_level = TRUE;
565 /* as a kludge, we represent all embedded reference pointers as id==-1
566 hoping that his will not collide with any non-ref pointers */
567 typedef struct ndr_pointer_data {
570 dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
573 } ndr_pointer_data_t;
576 init_ndr_pointer_list(packet_info *pinfo)
580 di=pinfo->private_data;
581 di->conformant_run=0;
583 while(ndr_pointer_list){
584 ndr_pointer_data_t *npd;
586 npd=g_slist_nth_data(ndr_pointer_list, 0);
587 ndr_pointer_list=g_slist_remove(ndr_pointer_list, npd);
593 ndr_pointer_list=NULL;
594 ndr_pointer_list_pos=0;
595 pointers_are_top_level=TRUE;
599 dissect_deferred_pointers(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, char *drep)
601 int found_new_pointer;
604 di=pinfo->private_data;
609 len=g_slist_length(ndr_pointer_list);
611 ndr_pointer_data_t *tnpd;
612 tnpd=g_slist_nth_data(ndr_pointer_list, i);
614 dcerpc_dissect_fnct_t *fnct;
619 ndr_pointer_list_pos=i+1;
620 di->hf_index=tnpd->hf_index;
621 di->levels=tnpd->levels;
622 /* first a run to handle any conformant
624 di->conformant_run=1;
625 offset = (*(fnct))(tvb, offset, pinfo, NULL, drep);
626 /* now we dissect the actual pointer */
627 di->conformant_run=0;
628 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, drep);
632 } while(found_new_pointer);
639 add_pointer_to_list(packet_info *pinfo, proto_tree *tree,
640 dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index, int levels)
642 ndr_pointer_data_t *npd;
644 /* check if this pointer is valid */
647 dcerpc_call_value *value;
649 di=pinfo->private_data;
653 if(!(pinfo->fd->flags.visited)){
654 if(id>value->max_ptr){
659 /* if we havent seen the request bail out since we cant
660 know whether this is the first non-NULL instance
662 if(value->req_frame==0){
663 /* XXX THROW EXCEPTION */
666 /* We saw this one in the request frame, nothing to
668 if(id<=value->max_ptr){
674 npd=g_malloc(sizeof(ndr_pointer_data_t));
678 npd->hf_index=hf_index;
680 ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
681 ndr_pointer_list_pos);
682 ndr_pointer_list_pos++;
687 find_pointer_index(guint32 id)
689 ndr_pointer_data_t *npd;
692 len=g_slist_length(ndr_pointer_list);
694 npd=g_slist_nth_data(ndr_pointer_list, i);
705 /* this function dissects an NDR pointer and stores the callback for later deferred dissection.
706 * fnct is the callback function for when we have reached this object in the bytestream.
707 * type is what type of pointer this is
708 * text is what text we should put in any created tree node
709 * hf_index is what hf value we want to pass to the callback function when it is called,
710 * the callback can later pich this one up from di->hf_index.
711 * levels is a generic int we want to pass to teh callback function.
712 * the callback can later pick it up from di->levels
714 * See packet-dcerpc-samr.c for examples
717 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
718 proto_tree *tree, char *drep,
719 dcerpc_dissect_fnct_t *fnct, int type, char *text, int hf_index, int levels)
723 di=pinfo->private_data;
724 if(di->conformant_run){
725 /* this call was only for dissecting the header for any
726 embedded conformant array. we will not parse any
727 pointers in this mode.
732 /*TOP LEVEL REFERENCE POINTER*/
733 if( pointers_are_top_level
734 && (type==NDR_POINTER_REF) ){
735 add_pointer_to_list(pinfo, tree, fnct, 0xffffffff, hf_index, levels);
739 /*TOP LEVEL FULL POINTER*/
740 if( pointers_are_top_level
741 && (type==NDR_POINTER_PTR) ){
747 /* get the referent id */
748 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
750 /* we got a NULL pointer */
752 proto_tree_add_text(tree, tvb, offset-4, 4,
753 "(NULL pointer) %s",text);
757 /* see if we have seen this pointer before */
758 idx=find_pointer_index(id);
760 /* we have seen this pointer before */
762 proto_tree_add_text(tree, tvb, offset-4, 4,
763 "(duplicate PTR) %s",text);
768 item=proto_tree_add_text(tree, tvb, offset-4, 4,
770 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
771 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
772 add_pointer_to_list(pinfo, tr, fnct, id, hf_index, levels);
775 /*TOP LEVEL UNIQUE POINTER*/
776 if( pointers_are_top_level
777 && (type==NDR_POINTER_UNIQUE) ){
783 /* get the referent id */
784 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
786 /* we got a NULL pointer */
788 proto_tree_add_text(tree, tvb, offset-4, 4,
789 "(NULL pointer) %s",text);
794 item=proto_tree_add_text(tree, tvb, offset-4, 4,
796 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
797 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
798 add_pointer_to_list(pinfo, tr, fnct, 0xffffffff, hf_index, levels);
802 /*EMBEDDED REFERENCE POINTER*/
803 if( (!pointers_are_top_level)
804 && (type==NDR_POINTER_REF) ){
809 /* get the referent id */
810 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
813 item=proto_tree_add_text(tree, tvb, offset-4, 4,
815 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
816 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
817 add_pointer_to_list(pinfo, tr, fnct, 0xffffffff, hf_index, levels);
821 /*EMBEDDED UNIQUE POINTER*/
822 if( (!pointers_are_top_level)
823 && (type==NDR_POINTER_UNIQUE) ){
829 /* get the referent id */
830 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
832 /* we got a NULL pointer */
834 proto_tree_add_text(tree, tvb, offset-4, 4,
835 "(NULL pointer) %s", text);
840 item=proto_tree_add_text(tree, tvb, offset-4, 4,
842 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
843 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
844 add_pointer_to_list(pinfo, tr, fnct, 0xffffffff, hf_index, levels);
848 /*EMBEDDED FULL POINTER*/
849 if( (!pointers_are_top_level)
850 && (type==NDR_POINTER_PTR) ){
856 /* get the referent id */
857 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
859 /* we got a NULL pointer */
861 proto_tree_add_text(tree, tvb, offset-4, 4,
862 "(NULL pointer) %s",text);
866 /* see if we have seen this pointer before */
867 idx=find_pointer_index(id);
869 /* we have seen this pointer before */
871 proto_tree_add_text(tree, tvb, offset-4, 4,
872 "(duplicate PTR) %s",text);
877 item=proto_tree_add_text(tree, tvb, offset-4, 4,
879 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
880 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
881 add_pointer_to_list(pinfo, tr, fnct, id, hf_index, levels);
887 /* After each top level pointer we have dissected we have to
888 dissect all deferrals before we move on to the next top level
890 if(pointers_are_top_level==TRUE){
891 pointers_are_top_level=FALSE;
892 offset = dissect_deferred_pointers(pinfo, tree, tvb, offset, drep);
893 pointers_are_top_level=TRUE;
902 dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
903 proto_tree *dcerpc_tree,
904 tvbuff_t *tvb, gint offset,
905 guint16 opnum, gboolean is_rqst,
906 char *drep, dcerpc_info *info,
910 dcerpc_uuid_value *sub_proto;
912 proto_tree *sub_tree = NULL;
913 dcerpc_sub_dissector *proc;
915 dcerpc_dissect_fnct_t *sub_dissect;
916 const char *saved_proto;
917 void *saved_private_data;
919 key.uuid = info->call_data->uuid;
920 key.ver = info->call_data->ver;
923 if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == NULL
924 || !proto_is_protocol_enabled(sub_proto->proto)) {
926 * We don't have a dissector for this UUID, or the protocol
927 * for that UUID is disabled.
929 length = tvb_length_remaining (tvb, offset);
931 proto_tree_add_text (dcerpc_tree, tvb, offset, length,
932 "Stub data (%d byte%s)", length,
933 plurality(length, "", "s"));
938 for (proc = sub_proto->procs; proc->name; proc++) {
939 if (proc->num == opnum) {
948 if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
949 col_set_str (pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
952 if (check_col (pinfo->cinfo, COL_INFO)) {
953 col_add_fstr (pinfo->cinfo, COL_INFO, "%s %s(...)",
954 is_rqst ? "rqst" : "rply", name);
958 proto_item *sub_item;
959 sub_item = proto_tree_add_item (tree, sub_proto->proto, tvb, offset,
963 sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
967 * Put the operation number into the tree along with
968 * the operation's name.
970 * XXX - the subdissectors should all have their own fields
971 * for the opnum, so that you can filter on a particular
972 * protocol and opnum value; the opnum value isn't, by itself,
973 * very interesting, as its interpretation depends on the
976 * That would also allow the field to have a value_string
977 * table, giving names for operations, and letting you filter
980 * ONC RPC should do the same thing with the version and
981 * procedure fields it puts into the subprotocol's tree.
983 proto_tree_add_uint_format (sub_tree, hf_dcerpc_op, tvb,
985 "Operation: %s (%u)",
990 * If the authentication level is DCE_C_AUTHN_LEVEL_PKT_PRIVACY,
991 * the stub data is encrypted, and we can't dissect it.
993 if (auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
994 length = tvb_length_remaining (tvb, offset);
996 proto_tree_add_text(sub_tree, tvb, offset, length,
997 "Encrypted stub data (%d byte%s)",
998 length, plurality(length, "", "s"));
1001 sub_dissect = is_rqst ? proc->dissect_rqst : proc->dissect_resp;
1003 saved_proto = pinfo->current_proto;
1004 saved_private_data = pinfo->private_data;
1005 pinfo->current_proto = sub_proto->name;
1006 pinfo->private_data = (void *)info;
1008 init_ndr_pointer_list(pinfo);
1009 offset = sub_dissect (tvb, offset, pinfo, sub_tree, drep);
1011 pinfo->current_proto = saved_proto;
1012 pinfo->private_data = saved_private_data;
1014 length = tvb_length_remaining (tvb, offset);
1016 proto_tree_add_text (sub_tree, tvb, offset, length,
1017 "Stub data (%d byte%s)", length,
1018 plurality(length, "", "s"));
1026 dissect_dcerpc_cn_auth (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1027 e_dce_cn_common_hdr_t *hdr, int *auth_level_p)
1030 guint8 auth_pad_len;
1034 * Initially set "*auth_level_p" to -1 to indicate that we haven't
1035 * yet seen any authentication level information.
1037 if (auth_level_p != NULL)
1041 * The authentication information is at the *end* of the PDU; in
1042 * request and response PDUs, the request and response stub data
1045 * If the full packet is here, and we've got an auth len, and it's
1046 * valid, then dissect the auth info.
1048 if (tvb_length (tvb) >= hdr->frag_len
1050 && (hdr->auth_len + 8 <= hdr->frag_len)) {
1052 offset = hdr->frag_len - (hdr->auth_len + 8);
1054 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1055 hf_dcerpc_auth_type, NULL);
1056 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1057 hf_dcerpc_auth_level, &auth_level);
1058 if (auth_level_p != NULL)
1059 *auth_level_p = auth_level;
1060 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1061 hf_dcerpc_auth_pad_len, &auth_pad_len);
1062 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1063 hf_dcerpc_auth_rsrvd, NULL);
1064 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1065 hf_dcerpc_auth_ctx_id, NULL);
1067 proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len, "Auth Data");
1069 /* figure out where the auth padding starts */
1070 offset = hdr->frag_len - (hdr->auth_len + 8 + auth_pad_len);
1071 if (offset > 0 && auth_pad_len) {
1072 proto_tree_add_text (dcerpc_tree, tvb, offset,
1073 auth_pad_len, "Auth padding");
1074 return hdr->auth_len + 8 + auth_pad_len;
1076 return hdr->auth_len + 8;
1084 /* We need to hash in the SMB fid number to generate a unique hash table
1085 key as DCERPC over SMB allows several pipes over the same TCP/IP
1088 static guint16 get_smb_fid (void *private_data)
1090 dcerpc_private_info *priv = (dcerpc_private_info *)private_data;
1093 return 0; /* Nothing to see here */
1095 /* DCERPC over smb */
1097 if (priv->transport_type == DCERPC_TRANSPORT_SMB)
1098 return priv->data.smb.fid;
1100 /* Some other transport... */
1106 * Connection oriented packet types
1110 dissect_dcerpc_cn_bind (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1111 e_dce_cn_common_hdr_t *hdr)
1113 conversation_t *conv = NULL;
1114 guint8 num_ctx_items;
1116 gboolean saw_ctx_item = FALSE;
1118 guint16 num_trans_items;
1123 guint16 if_ver, if_ver_minor;
1126 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1127 hf_dcerpc_cn_max_xmit, NULL);
1129 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1130 hf_dcerpc_cn_max_recv, NULL);
1132 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1133 hf_dcerpc_cn_assoc_group, NULL);
1135 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1136 hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
1141 for (i = 0; i < num_ctx_items; i++) {
1142 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1143 hf_dcerpc_cn_ctx_id, &ctx_id);
1145 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1146 hf_dcerpc_cn_num_trans_items, &num_trans_items);
1148 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
1150 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_if_id, tvb,
1152 "Interface UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1153 if_id.Data1, if_id.Data2, if_id.Data3,
1154 if_id.Data4[0], if_id.Data4[1],
1155 if_id.Data4[2], if_id.Data4[3],
1156 if_id.Data4[4], if_id.Data4[5],
1157 if_id.Data4[6], if_id.Data4[7]);
1161 if (hdr->drep[0] & 0x10) {
1162 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1163 hf_dcerpc_cn_bind_if_ver, &if_ver);
1164 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1165 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
1167 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1168 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
1169 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1170 hf_dcerpc_cn_bind_if_ver, &if_ver);
1173 if (!saw_ctx_item) {
1174 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
1175 pinfo->srcport, pinfo->destport, 0);
1177 conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
1178 pinfo->srcport, pinfo->destport, 0);
1181 /* if this is the first time we see this packet, we need to
1182 update the dcerpc_binds table so that any later calls can
1183 match to the interface.
1184 XXX We assume that BINDs will NEVER be fragmented.
1186 if(!(pinfo->fd->flags.visited)){
1187 dcerpc_bind_key *key;
1188 dcerpc_bind_value *value;
1190 key = g_mem_chunk_alloc (dcerpc_bind_key_chunk);
1192 key->ctx_id = ctx_id;
1193 key->smb_fid = get_smb_fid(pinfo->private_data);
1195 value = g_mem_chunk_alloc (dcerpc_bind_value_chunk);
1196 value->uuid = if_id;
1197 value->ver = if_ver;
1199 /* add this entry to the bind table, first removing any
1200 previous ones that are identical
1202 if(g_hash_table_lookup(dcerpc_binds, key)){
1203 g_hash_table_remove(dcerpc_binds, key);
1205 g_hash_table_insert (dcerpc_binds, key, value);
1208 if (check_col (pinfo->cinfo, COL_INFO)) {
1209 col_add_fstr (pinfo->cinfo, COL_INFO, "%s: UUID %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %d.%d",
1210 hdr->ptype == PDU_BIND ? "Bind" : "Alter Ctx",
1211 if_id.Data1, if_id.Data2, if_id.Data3,
1212 if_id.Data4[0], if_id.Data4[1],
1213 if_id.Data4[2], if_id.Data4[3],
1214 if_id.Data4[4], if_id.Data4[5],
1215 if_id.Data4[6], if_id.Data4[7],
1216 if_ver, if_ver_minor);
1218 saw_ctx_item = TRUE;
1221 for (j = 0; j < num_trans_items; j++) {
1222 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
1224 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_trans_id, tvb,
1226 "Transfer Syntax: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1227 trans_id.Data1, trans_id.Data2, trans_id.Data3,
1228 trans_id.Data4[0], trans_id.Data4[1],
1229 trans_id.Data4[2], trans_id.Data4[3],
1230 trans_id.Data4[4], trans_id.Data4[5],
1231 trans_id.Data4[6], trans_id.Data4[7]);
1235 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1236 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
1241 * XXX - we should save the authentication type *if* we have
1242 * an authentication header, and associate it with an authentication
1243 * context, so subsequent PDUs can use that context.
1245 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, NULL);
1249 dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1250 e_dce_cn_common_hdr_t *hdr)
1252 guint16 max_xmit, max_recv;
1253 guint16 sec_addr_len;
1263 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1264 hf_dcerpc_cn_max_xmit, &max_xmit);
1266 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1267 hf_dcerpc_cn_max_recv, &max_recv);
1269 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1270 hf_dcerpc_cn_assoc_group, NULL);
1272 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1273 hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
1274 if (sec_addr_len != 0) {
1275 proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
1276 sec_addr_len, FALSE);
1277 offset += sec_addr_len;
1281 offset += 4 - offset % 4;
1284 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1285 hf_dcerpc_cn_num_results, &num_results);
1290 for (i = 0; i < num_results; i++) {
1291 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
1292 hdr->drep, hf_dcerpc_cn_ack_result,
1294 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
1295 hdr->drep, hf_dcerpc_cn_ack_reason,
1298 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
1300 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_ack_trans_id, tvb,
1302 "Transfer Syntax: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1303 trans_id.Data1, trans_id.Data2, trans_id.Data3,
1304 trans_id.Data4[0], trans_id.Data4[1],
1305 trans_id.Data4[2], trans_id.Data4[3],
1306 trans_id.Data4[4], trans_id.Data4[5],
1307 trans_id.Data4[6], trans_id.Data4[7]);
1311 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1312 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
1316 * XXX - do we need to do anything with the authentication level
1317 * we get back from this?
1319 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, NULL);
1321 if (check_col (pinfo->cinfo, COL_INFO)) {
1322 if (num_results != 0 && result == 0) {
1323 col_add_fstr (pinfo->cinfo, COL_INFO, "%s ack: accept max_xmit: %d max_recv: %d",
1324 hdr->ptype == PDU_BIND_ACK ? "Bind" : "Alter ctx",
1325 max_xmit, max_recv);
1327 /* FIXME: should put in reason */
1328 col_add_fstr (pinfo->cinfo, COL_INFO, "%s ack: %s",
1329 hdr->ptype == PDU_BIND_ACK ? "Bind" : "Alter ctx",
1330 result == 1 ? "User reject" :
1331 result == 2 ? "Provider reject" :
1338 dissect_dcerpc_cn_rqst (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1339 proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
1341 conversation_t *conv;
1349 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1350 hf_dcerpc_cn_alloc_hint, NULL);
1352 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1353 hf_dcerpc_cn_ctx_id, &ctx_id);
1355 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1356 hf_dcerpc_opnum, &opnum);
1358 if (check_col (pinfo->cinfo, COL_INFO)) {
1359 col_add_fstr (pinfo->cinfo, COL_INFO, "Request: opnum: %d ctx_id:%d",
1363 if (hdr->flags & 0x80) {
1364 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id);
1366 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
1368 "Object UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1369 obj_id.Data1, obj_id.Data2, obj_id.Data3,
1383 * XXX - what if this was set when the connection was set up,
1384 * and we just have a security context?
1386 auth_sz = dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr,
1389 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
1390 pinfo->srcport, pinfo->destport, 0);
1394 dcerpc_call_value *value;
1395 int length, reported_length, stub_length;
1398 /* !!! we can NOT check flags.visited here since this will interact
1399 badly with when SMB handles (i.e. calls the subdissector)
1400 and desegmented pdu's .
1401 Instead we check if this pdu is already in the matched table or not
1403 if(!g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num)){
1404 dcerpc_bind_key bind_key;
1405 dcerpc_bind_value *bind_value;
1408 bind_key.ctx_id=ctx_id;
1409 bind_key.smb_fid=get_smb_fid(pinfo->private_data);
1411 if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key))){
1412 dcerpc_call_key *call_key;
1413 dcerpc_call_value *call_value;
1415 /* We found the binding so just add the call
1416 to both the call table and the matched table
1418 call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
1419 call_key->conv=conv;
1420 call_key->call_id=hdr->call_id;
1421 call_key->smb_fid=get_smb_fid(pinfo->private_data);
1423 /* if there is already a matching call in the table
1424 remove it so it is replaced with the new one */
1425 if(g_hash_table_lookup(dcerpc_calls, call_key)){
1426 g_hash_table_remove(dcerpc_calls, call_key);
1429 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
1430 call_value->uuid = bind_value->uuid;
1431 call_value->ver = bind_value->ver;
1432 call_value->opnum = opnum;
1433 call_value->req_frame=pinfo->fd->num;
1434 call_value->rep_frame=0;
1435 call_value->max_ptr=0;
1436 call_value->private_data = NULL;
1437 g_hash_table_insert (dcerpc_calls, call_key, call_value);
1439 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
1443 value=g_hash_table_lookup (dcerpc_matched, (void *)pinfo->fd->num);
1448 /* handoff this call */
1449 length = tvb_length_remaining(tvb, offset);
1450 reported_length = tvb_reported_length_remaining(tvb, offset);
1451 stub_length = hdr->frag_len - offset - auth_sz;
1452 if (length > stub_length)
1453 length = stub_length;
1454 if (reported_length > stub_length)
1455 reported_length = stub_length;
1457 di.call_id = hdr->call_id;
1458 di.smb_fid = get_smb_fid(pinfo->private_data);
1460 di.call_data = value;
1462 if(value->rep_frame!=0){
1463 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
1464 tvb, 0, 0, value->rep_frame);
1467 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
1468 tvb_new_subset (tvb, offset, length,
1470 0, opnum, TRUE, hdr->drep, &di, auth_level);
1476 dissect_dcerpc_cn_resp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1477 proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
1479 dcerpc_call_value *value = NULL;
1480 conversation_t *conv;
1486 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1487 hf_dcerpc_cn_alloc_hint, NULL);
1489 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1490 hf_dcerpc_cn_ctx_id, &ctx_id);
1492 if (check_col (pinfo->cinfo, COL_INFO)) {
1493 col_add_fstr (pinfo->cinfo, COL_INFO, "Response: call_id: %d ctx_id:%d",
1494 hdr->call_id, ctx_id);
1497 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1498 hf_dcerpc_cn_cancel_count, NULL);
1503 * XXX - what if this was set when the connection was set up,
1504 * and we just have a security context?
1506 auth_sz = dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr,
1509 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
1510 pinfo->srcport, pinfo->destport, 0);
1512 /* no point in creating one here, really */
1515 /* !!! we can NOT check flags.visited here since this will interact
1516 badly with when SMB handles (i.e. calls the subdissector)
1517 and desegmented pdu's .
1518 Instead we check if this pdu is already in the matched table or not
1520 if(!g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num)){
1521 dcerpc_call_key call_key;
1522 dcerpc_call_value *call_value;
1525 call_key.call_id=hdr->call_id;
1526 call_key.smb_fid=get_smb_fid(pinfo->private_data);
1528 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
1529 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
1530 if(call_value->rep_frame==0){
1531 call_value->rep_frame=pinfo->fd->num;
1537 value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
1540 int length, reported_length, stub_length;
1543 /* handoff this call */
1544 length = tvb_length_remaining(tvb, offset);
1545 reported_length = tvb_reported_length_remaining(tvb, offset);
1546 stub_length = hdr->frag_len - offset - auth_sz;
1547 if (length > stub_length)
1548 length = stub_length;
1549 if (reported_length > stub_length)
1550 reported_length = stub_length;
1552 di.call_id = hdr->call_id;
1553 di.smb_fid = get_smb_fid(pinfo->private_data);
1555 di.call_data = value;
1557 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
1558 if(value->req_frame!=0){
1559 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
1560 tvb, 0, 0, value->req_frame);
1563 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
1564 tvb_new_subset (tvb, offset, length,
1566 0, value->opnum, FALSE, hdr->drep, &di,
1573 * DCERPC dissector for connection oriented calls
1576 dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
1577 proto_tree *tree, gboolean can_desegment)
1579 static char nulls[4] = { 0 };
1582 proto_item *ti = NULL;
1583 proto_item *tf = NULL;
1584 proto_tree *dcerpc_tree = NULL;
1585 proto_tree *cn_flags_tree = NULL;
1586 proto_tree *drep_tree = NULL;
1587 e_dce_cn_common_hdr_t hdr;
1590 * when done over nbt, dcerpc requests are padded with 4 bytes of null
1591 * data for some reason.
1593 * XXX - if that's always the case, the right way to do this would
1594 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
1595 * the 4 bytes of null padding, and make that the dissector
1596 * used for "netbios".
1598 if (tvb_bytes_exist (tvb, offset, 4) &&
1599 tvb_memeql (tvb, offset, nulls, 4) == 0) {
1609 * Check if this looks like a C/O DCERPC call
1611 if (!tvb_bytes_exist (tvb, offset, sizeof (hdr))) {
1614 start_offset = offset;
1615 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
1616 if (hdr.rpc_ver != 5)
1618 hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
1619 if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
1621 hdr.ptype = tvb_get_guint8 (tvb, offset++);
1625 if (check_col (pinfo->cinfo, COL_PROTOCOL))
1626 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
1627 if (check_col (pinfo->cinfo, COL_INFO))
1628 col_set_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
1630 hdr.flags = tvb_get_guint8 (tvb, offset++);
1631 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
1632 offset += sizeof (hdr.drep);
1634 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1636 hdr.auth_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1638 hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
1641 offset = start_offset;
1642 if (can_desegment && pinfo->can_desegment
1643 && hdr.frag_len > tvb_length_remaining (tvb, offset)) {
1644 pinfo->desegment_offset = offset;
1645 pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, offset);
1646 return 0; /* desegmentation required */
1650 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE);
1652 dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
1654 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver);
1655 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset++, 1, hdr.rpc_ver_minor);
1656 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype);
1657 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
1658 cn_flags_tree = proto_item_add_subtree (tf, ett_dcerpc_cn_flags);
1659 if (cn_flags_tree) {
1660 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
1661 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
1662 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
1663 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
1664 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
1665 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
1666 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
1667 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
1671 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
1672 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
1674 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
1675 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
1676 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
1678 offset += sizeof (hdr.drep);
1680 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
1683 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
1686 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
1692 * Packet type specific stuff is next.
1694 switch (hdr.ptype) {
1697 dissect_dcerpc_cn_bind (tvb, pinfo, dcerpc_tree, &hdr);
1702 dissect_dcerpc_cn_bind_ack (tvb, pinfo, dcerpc_tree, &hdr);
1706 dissect_dcerpc_cn_rqst (tvb, pinfo, dcerpc_tree, tree, &hdr);
1710 dissect_dcerpc_cn_resp (tvb, pinfo, dcerpc_tree, tree, &hdr);
1714 /* might as well dissect the auth info */
1715 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, NULL);
1718 return hdr.frag_len + padding;
1722 * DCERPC dissector for connection oriented calls over packet-oriented
1726 dissect_dcerpc_cn_pk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1729 * Only one PDU per transport packet, and only one transport
1732 if (dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE) == -1) {
1734 * It wasn't a DCERPC PDU.
1746 * DCERPC dissector for connection oriented calls over byte-stream
1750 dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1754 gboolean ret = FALSE;
1757 * There may be multiple PDUs per transport packet; keep
1760 while (tvb_reported_length_remaining(tvb, offset) != 0) {
1761 pdu_len = dissect_dcerpc_cn (tvb, offset, pinfo, tree,
1762 dcerpc_cn_desegment);
1763 if (pdu_len == -1) {
1771 * Well, we've seen at least one DCERPC PDU.
1777 * Desegmentation required - bail now.
1783 * Step to the next PDU.
1791 dissect_dcerpc_dg_auth (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1792 e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
1797 * Initially set "*auth_level_p" to -1 to indicate that we haven't
1798 * yet seen any authentication level information.
1800 if (auth_level_p != NULL)
1804 * The authentication information is at the *end* of the PDU; in
1805 * request and response PDUs, the request and response stub data
1808 * If the full packet is here, and there's data past the end of the
1809 * packet body, then dissect the auth info.
1811 if (tvb_length (tvb) >= hdr->frag_len) {
1812 offset = hdr->frag_len;
1814 proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Auth data");
1819 * DCERPC dissector for connectionless calls
1822 dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1824 proto_item *ti = NULL;
1825 proto_item *tf = NULL;
1826 proto_tree *dcerpc_tree = NULL;
1827 proto_tree *dg_flags1_tree = NULL;
1828 proto_tree *dg_flags2_tree = NULL;
1829 proto_tree *drep_tree = NULL;
1830 e_dce_dg_common_hdr_t hdr;
1832 conversation_t *conv;
1835 * Check if this looks like a CL DCERPC call. All dg packets
1836 * have an 80 byte header on them. Which starts with
1837 * version (4), pkt_type.
1839 if (!tvb_bytes_exist (tvb, 0, sizeof (hdr))) {
1842 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
1843 if (hdr.rpc_ver != 4)
1845 hdr.ptype = tvb_get_guint8 (tvb, offset++);
1849 if (check_col (pinfo->cinfo, COL_PROTOCOL))
1850 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
1851 if (check_col (pinfo->cinfo, COL_INFO))
1852 col_set_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
1854 hdr.flags1 = tvb_get_guint8 (tvb, offset++);
1855 hdr.flags2 = tvb_get_guint8 (tvb, offset++);
1856 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
1857 offset += sizeof (hdr.drep);
1858 hdr.serial_hi = tvb_get_guint8 (tvb, offset++);
1859 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.obj_id);
1861 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.if_id);
1863 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.act_id);
1865 hdr.server_boot = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
1867 hdr.if_ver = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
1869 hdr.seqnum = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
1871 hdr.opnum = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1873 hdr.ihint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1875 hdr.ahint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1877 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1879 hdr.frag_num = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1881 hdr.auth_proto = tvb_get_guint8 (tvb, offset++);
1882 hdr.serial_lo = tvb_get_guint8 (tvb, offset++);
1885 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, -1, FALSE);
1887 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
1890 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver);
1892 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype);
1894 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
1895 dg_flags1_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags1);
1896 if (dg_flags1_tree) {
1897 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
1898 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
1899 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
1900 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
1901 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
1902 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
1903 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
1904 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
1908 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
1909 dg_flags2_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags2);
1910 if (dg_flags2_tree) {
1911 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
1912 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
1913 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
1914 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
1915 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
1916 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
1917 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
1918 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
1922 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
1923 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
1925 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
1926 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
1927 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
1929 offset += sizeof (hdr.drep);
1931 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset++, 1, hdr.serial_hi);
1933 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
1935 "Object: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1936 hdr.obj_id.Data1, hdr.obj_id.Data2, hdr.obj_id.Data3,
1937 hdr.obj_id.Data4[0],
1938 hdr.obj_id.Data4[1],
1939 hdr.obj_id.Data4[2],
1940 hdr.obj_id.Data4[3],
1941 hdr.obj_id.Data4[4],
1942 hdr.obj_id.Data4[5],
1943 hdr.obj_id.Data4[6],
1944 hdr.obj_id.Data4[7]);
1947 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
1949 "Interface: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1950 hdr.if_id.Data1, hdr.if_id.Data2, hdr.if_id.Data3,
1958 hdr.if_id.Data4[7]);
1961 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
1963 "Activity: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1964 hdr.act_id.Data1, hdr.act_id.Data2, hdr.act_id.Data3,
1965 hdr.act_id.Data4[0],
1966 hdr.act_id.Data4[1],
1967 hdr.act_id.Data4[2],
1968 hdr.act_id.Data4[3],
1969 hdr.act_id.Data4[4],
1970 hdr.act_id.Data4[5],
1971 hdr.act_id.Data4[6],
1972 hdr.act_id.Data4[7]);
1975 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_server_boot, tvb, offset, 4, hdr.server_boot);
1978 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
1981 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
1984 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
1987 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
1990 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
1993 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
1996 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
1999 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
2002 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
2006 * XXX - for Kerberos, we can get a protection level; if it's
2007 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
2010 dissect_dcerpc_dg_auth (tvb, pinfo, dcerpc_tree, &hdr, NULL);
2013 * keeping track of the conversation shouldn't really be necessary
2014 * for connectionless packets, because everything we need to know
2015 * to dissect is in the header for each packet. Unfortunately,
2016 * Microsoft's implementation is buggy and often puts the
2017 * completely wrong if_id in the header. go figure. So, keep
2018 * track of the seqnum and use that if possible. Note: that's not
2019 * completely correct. It should really be done based on both the
2020 * activity_id and seqnum. I haven't seen anywhere that it would
2021 * make a difference, but for future reference...
2023 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2024 pinfo->srcport, pinfo->destport, 0);
2026 conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
2027 pinfo->srcport, pinfo->destport, 0);
2031 * Packet type specific stuff is next.
2034 switch (hdr.ptype) {
2035 int length, reported_length, stub_length;
2037 dcerpc_call_value *value, v;
2041 if(!(pinfo->fd->flags.visited)){
2042 dcerpc_call_value *call_value;
2043 dcerpc_call_key *call_key;
2045 call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
2046 call_key->conv=conv;
2047 call_key->call_id=hdr.seqnum;
2048 call_key->smb_fid=get_smb_fid(pinfo->private_data);
2050 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
2051 call_value->uuid = hdr.if_id;
2052 call_value->ver = hdr.if_ver;
2053 call_value->opnum = hdr.opnum;
2054 call_value->req_frame=pinfo->fd->num;
2055 call_value->rep_frame=0;
2056 call_value->max_ptr=0;
2057 call_value->private_data = NULL;
2058 g_hash_table_insert (dcerpc_calls, call_key, call_value);
2060 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
2063 value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
2067 v.opnum = hdr.opnum;
2068 v.req_frame = pinfo->fd->num;
2071 v.private_data=NULL;
2075 length = tvb_length_remaining (tvb, offset);
2076 reported_length = tvb_reported_length_remaining (tvb, offset);
2077 stub_length = hdr.frag_len;
2078 if (length > stub_length)
2079 length = stub_length;
2080 if (reported_length > stub_length)
2081 reported_length = stub_length;
2084 di.call_id = hdr.seqnum;
2087 di.call_data = value;
2090 * XXX - authentication level?
2092 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
2093 tvb_new_subset (tvb, offset, length,
2095 0, hdr.opnum, TRUE, hdr.drep, &di, 0);
2098 if(!(pinfo->fd->flags.visited)){
2099 dcerpc_call_value *call_value;
2100 dcerpc_call_key call_key;
2103 call_key.call_id=hdr.seqnum;
2104 call_key.smb_fid=get_smb_fid(pinfo->private_data);
2106 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
2107 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
2108 if(call_value->rep_frame==0){
2109 call_value->rep_frame=pinfo->fd->num;
2114 value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
2118 v.opnum = hdr.opnum;
2120 v.rep_frame=pinfo->fd->num;
2121 v.private_data=NULL;
2125 length = tvb_length_remaining (tvb, offset);
2126 reported_length = tvb_reported_length_remaining (tvb, offset);
2127 stub_length = hdr.frag_len;
2128 if (length > stub_length)
2129 length = stub_length;
2130 if (reported_length > stub_length)
2131 reported_length = stub_length;
2137 di.call_data = value;
2140 * XXX - authentication level?
2142 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
2143 tvb_new_subset (tvb, offset, length,
2145 0, value->opnum, FALSE, hdr.drep, &di, 0);
2153 dcerpc_init_protocol (void)
2155 /* structures and data for BIND */
2157 g_hash_table_destroy (dcerpc_binds);
2159 dcerpc_binds = g_hash_table_new (dcerpc_bind_hash, dcerpc_bind_equal);
2161 if (dcerpc_bind_key_chunk){
2162 g_mem_chunk_destroy (dcerpc_bind_key_chunk);
2164 dcerpc_bind_key_chunk = g_mem_chunk_new ("dcerpc_bind_key_chunk",
2165 sizeof (dcerpc_bind_key),
2166 200 * sizeof (dcerpc_bind_key),
2168 if (dcerpc_bind_value_chunk){
2169 g_mem_chunk_destroy (dcerpc_bind_value_chunk);
2171 dcerpc_bind_value_chunk = g_mem_chunk_new ("dcerpc_bind_value_chunk",
2172 sizeof (dcerpc_bind_value),
2173 200 * sizeof (dcerpc_bind_value),
2175 /* structures and data for CALL */
2177 g_hash_table_destroy (dcerpc_calls);
2179 dcerpc_calls = g_hash_table_new (dcerpc_call_hash, dcerpc_call_equal);
2180 if (dcerpc_call_key_chunk){
2181 g_mem_chunk_destroy (dcerpc_call_key_chunk);
2183 dcerpc_call_key_chunk = g_mem_chunk_new ("dcerpc_call_key_chunk",
2184 sizeof (dcerpc_call_key),
2185 200 * sizeof (dcerpc_call_key),
2187 if (dcerpc_call_value_chunk){
2188 g_mem_chunk_destroy (dcerpc_call_value_chunk);
2190 dcerpc_call_value_chunk = g_mem_chunk_new ("dcerpc_call_value_chunk",
2191 sizeof (dcerpc_call_value),
2192 200 * sizeof (dcerpc_call_value),
2195 /* structure and data for MATCHED */
2196 if (dcerpc_matched){
2197 g_hash_table_destroy (dcerpc_matched);
2199 dcerpc_matched = g_hash_table_new (dcerpc_matched_hash, dcerpc_matched_equal);
2204 proto_register_dcerpc (void)
2206 static hf_register_info hf[] = {
2207 { &hf_dcerpc_request_in,
2208 { "Request in", "dcerpc.request_in", FT_UINT32, BASE_DEC,
2209 NULL, 0, "This packet is a response to the packet in this frame", HFILL }},
2210 { &hf_dcerpc_response_in,
2211 { "Response in", "dcerpc.response_in", FT_UINT32, BASE_DEC,
2212 NULL, 0, "The response to this packet is in this packet", HFILL }},
2213 { &hf_dcerpc_referent_id,
2214 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
2215 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
2217 { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2218 { &hf_dcerpc_ver_minor,
2219 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2220 { &hf_dcerpc_packet_type,
2221 { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_HEX, VALS (pckt_vals), 0x0, "", HFILL }},
2222 { &hf_dcerpc_cn_flags,
2223 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
2224 { &hf_dcerpc_cn_flags_first_frag,
2225 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x1, "", HFILL }},
2226 { &hf_dcerpc_cn_flags_last_frag,
2227 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x2, "", HFILL }},
2228 { &hf_dcerpc_cn_flags_cancel_pending,
2229 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x4, "", HFILL }},
2230 { &hf_dcerpc_cn_flags_reserved,
2231 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x8, "", HFILL }},
2232 { &hf_dcerpc_cn_flags_mpx,
2233 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x10, "", HFILL }},
2234 { &hf_dcerpc_cn_flags_dne,
2235 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x20, "", HFILL }},
2236 { &hf_dcerpc_cn_flags_maybe,
2237 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x40, "", HFILL }},
2238 { &hf_dcerpc_cn_flags_object,
2239 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x80, "", HFILL }},
2241 { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
2242 { &hf_dcerpc_drep_byteorder,
2243 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS (drep_byteorder_vals), 0x0, "", HFILL }},
2244 { &hf_dcerpc_drep_character,
2245 { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS (drep_character_vals), 0x0, "", HFILL }},
2246 { &hf_dcerpc_drep_fp,
2247 { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS (drep_fp_vals), 0x0, "", HFILL }},
2248 { &hf_dcerpc_cn_frag_len,
2249 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2250 { &hf_dcerpc_cn_auth_len,
2251 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2252 { &hf_dcerpc_cn_call_id,
2253 { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2254 { &hf_dcerpc_cn_max_xmit,
2255 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2256 { &hf_dcerpc_cn_max_recv,
2257 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2258 { &hf_dcerpc_cn_assoc_group,
2259 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
2260 { &hf_dcerpc_cn_num_ctx_items,
2261 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2262 { &hf_dcerpc_cn_ctx_id,
2263 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2264 { &hf_dcerpc_cn_num_trans_items,
2265 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2266 { &hf_dcerpc_cn_bind_if_id,
2267 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2268 { &hf_dcerpc_cn_bind_if_ver,
2269 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2270 { &hf_dcerpc_cn_bind_if_ver_minor,
2271 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2272 { &hf_dcerpc_cn_bind_trans_id,
2273 { "Transfer Syntax", "dcerpc.cn_bind_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2274 { &hf_dcerpc_cn_bind_trans_ver,
2275 { "Syntax ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2276 { &hf_dcerpc_cn_alloc_hint,
2277 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2278 { &hf_dcerpc_cn_sec_addr_len,
2279 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2280 { &hf_dcerpc_cn_sec_addr,
2281 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, "", HFILL }},
2282 { &hf_dcerpc_cn_num_results,
2283 { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2284 { &hf_dcerpc_cn_ack_result,
2285 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2286 { &hf_dcerpc_cn_ack_reason,
2287 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2288 { &hf_dcerpc_cn_ack_trans_id,
2289 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2290 { &hf_dcerpc_cn_ack_trans_ver,
2291 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2292 { &hf_dcerpc_cn_cancel_count,
2293 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2294 { &hf_dcerpc_auth_type,
2295 { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
2296 { &hf_dcerpc_auth_level,
2297 { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS (authn_level_vals), 0x0, "", HFILL }},
2298 { &hf_dcerpc_auth_pad_len,
2299 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2300 { &hf_dcerpc_auth_rsrvd,
2301 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2302 { &hf_dcerpc_auth_ctx_id,
2303 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2304 { &hf_dcerpc_dg_flags1,
2305 { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
2306 { &hf_dcerpc_dg_flags1_rsrvd_01,
2307 { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x01, "", HFILL }},
2308 { &hf_dcerpc_dg_flags1_last_frag,
2309 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x02, "", HFILL }},
2310 { &hf_dcerpc_dg_flags1_frag,
2311 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x04, "", HFILL }},
2312 { &hf_dcerpc_dg_flags1_nofack,
2313 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x08, "", HFILL }},
2314 { &hf_dcerpc_dg_flags1_maybe,
2315 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x10, "", HFILL }},
2316 { &hf_dcerpc_dg_flags1_idempotent,
2317 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x20, "", HFILL }},
2318 { &hf_dcerpc_dg_flags1_broadcast,
2319 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x40, "", HFILL }},
2320 { &hf_dcerpc_dg_flags1_rsrvd_80,
2321 { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x80, "", HFILL }},
2322 { &hf_dcerpc_dg_flags2,
2323 { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
2324 { &hf_dcerpc_dg_flags2_rsrvd_01,
2325 { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x01, "", HFILL }},
2326 { &hf_dcerpc_dg_flags2_cancel_pending,
2327 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x02, "", HFILL }},
2328 { &hf_dcerpc_dg_flags2_rsrvd_04,
2329 { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x04, "", HFILL }},
2330 { &hf_dcerpc_dg_flags2_rsrvd_08,
2331 { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x08, "", HFILL }},
2332 { &hf_dcerpc_dg_flags2_rsrvd_10,
2333 { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x10, "", HFILL }},
2334 { &hf_dcerpc_dg_flags2_rsrvd_20,
2335 { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x20, "", HFILL }},
2336 { &hf_dcerpc_dg_flags2_rsrvd_40,
2337 { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x40, "", HFILL }},
2338 { &hf_dcerpc_dg_flags2_rsrvd_80,
2339 { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x80, "", HFILL }},
2340 { &hf_dcerpc_dg_serial_lo,
2341 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
2342 { &hf_dcerpc_dg_serial_hi,
2343 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
2344 { &hf_dcerpc_dg_ahint,
2345 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
2346 { &hf_dcerpc_dg_ihint,
2347 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
2348 { &hf_dcerpc_dg_frag_len,
2349 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2350 { &hf_dcerpc_dg_frag_num,
2351 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2352 { &hf_dcerpc_dg_auth_proto,
2353 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
2354 { &hf_dcerpc_dg_seqnum,
2355 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
2356 { &hf_dcerpc_dg_server_boot,
2357 { "Server boot time", "dcerpc.dg_server_boot", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
2358 { &hf_dcerpc_dg_if_ver,
2359 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2360 { &hf_dcerpc_obj_id,
2361 { "Object", "dcerpc.obj_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2362 { &hf_dcerpc_dg_if_id,
2363 { "Interface", "dcerpc.dg_if_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2364 { &hf_dcerpc_dg_act_id,
2365 { "Activitiy", "dcerpc.dg_act_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2367 { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2368 { &hf_dcerpc_array_max_count,
2369 { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
2371 { &hf_dcerpc_array_offset,
2372 { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
2374 { &hf_dcerpc_array_actual_count,
2375 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
2378 { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2381 static gint *ett[] = {
2383 &ett_dcerpc_cn_flags,
2385 &ett_dcerpc_dg_flags1,
2386 &ett_dcerpc_dg_flags2,
2387 &ett_dcerpc_pointer_data,
2390 proto_dcerpc = proto_register_protocol ("DCE RPC", "DCERPC", "dcerpc");
2391 proto_register_field_array (proto_dcerpc, hf, array_length (hf));
2392 proto_register_subtree_array (ett, array_length (ett));
2393 register_init_routine (dcerpc_init_protocol);
2395 prefs_register_bool_preference (prefs_register_protocol (proto_dcerpc,
2398 "Desegment all DCE/RPC over TCP",
2399 "Whether the DCE/RPC dissector should desegment all DCE/RPC over TCP",
2400 &dcerpc_cn_desegment);
2401 dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
2405 proto_reg_handoff_dcerpc (void)
2407 heur_dissector_add ("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
2408 heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
2409 heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
2410 heur_dissector_add ("smb_transact", dissect_dcerpc_cn_bs, proto_dcerpc);