2 * Routines for DCERPC packet disassembly
3 * Copyright 2001, Todd Sabin <tas@webspan.net>
5 * $Id: packet-dcerpc.c,v 1.53 2002/06/04 07:03:44 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>
42 #include "reassemble.h"
44 static const value_string pckt_vals[] = {
59 { 14, "Alter_context"},
60 { 15, "Alter_context_resp"},
68 static const value_string drep_byteorder_vals[] = {
70 { 1, "Little-endian" },
74 static const value_string drep_character_vals[] = {
80 static const value_string drep_fp_vals[] = {
88 static const true_false_string flags_set_truth = {
94 * Authentication services.
96 static const value_string authn_protocol_vals[] = {
105 #define DCE_C_AUTHN_LEVEL_NONE 1
106 #define DCE_C_AUTHN_LEVEL_CONNECT 2
107 #define DCE_C_AUTHN_LEVEL_CALL 3
108 #define DCE_C_AUTHN_LEVEL_PKT 4
109 #define DCE_C_AUTHN_LEVEL_PKT_INTEGRITY 5
110 #define DCE_C_AUTHN_LEVEL_PKT_PRIVACY 6
112 static const value_string authn_level_vals[] = {
113 { DCE_C_AUTHN_LEVEL_NONE, "None" },
114 { DCE_C_AUTHN_LEVEL_CONNECT, "Connect" },
115 { DCE_C_AUTHN_LEVEL_CALL, "Call" },
116 { DCE_C_AUTHN_LEVEL_PKT, "Packet" },
117 { DCE_C_AUTHN_LEVEL_PKT_INTEGRITY, "Packet integrity" },
118 { DCE_C_AUTHN_LEVEL_PKT_PRIVACY, "Packet privacy" },
122 static int proto_dcerpc = -1;
125 static int hf_dcerpc_request_in = -1;
126 static int hf_dcerpc_response_in = -1;
127 static int hf_dcerpc_ver = -1;
128 static int hf_dcerpc_ver_minor = -1;
129 static int hf_dcerpc_packet_type = -1;
130 static int hf_dcerpc_cn_flags = -1;
131 static int hf_dcerpc_cn_flags_first_frag = -1;
132 static int hf_dcerpc_cn_flags_last_frag = -1;
133 static int hf_dcerpc_cn_flags_cancel_pending = -1;
134 static int hf_dcerpc_cn_flags_reserved = -1;
135 static int hf_dcerpc_cn_flags_mpx = -1;
136 static int hf_dcerpc_cn_flags_dne = -1;
137 static int hf_dcerpc_cn_flags_maybe = -1;
138 static int hf_dcerpc_cn_flags_object = -1;
139 static int hf_dcerpc_drep = -1;
140 static int hf_dcerpc_drep_byteorder = -1;
141 static int hf_dcerpc_drep_character = -1;
142 static int hf_dcerpc_drep_fp = -1;
143 static int hf_dcerpc_cn_frag_len = -1;
144 static int hf_dcerpc_cn_auth_len = -1;
145 static int hf_dcerpc_cn_call_id = -1;
146 static int hf_dcerpc_cn_max_xmit = -1;
147 static int hf_dcerpc_cn_max_recv = -1;
148 static int hf_dcerpc_cn_assoc_group = -1;
149 static int hf_dcerpc_cn_num_ctx_items = -1;
150 static int hf_dcerpc_cn_ctx_id = -1;
151 static int hf_dcerpc_cn_num_trans_items = -1;
152 static int hf_dcerpc_cn_bind_if_id = -1;
153 static int hf_dcerpc_cn_bind_if_ver = -1;
154 static int hf_dcerpc_cn_bind_if_ver_minor = -1;
155 static int hf_dcerpc_cn_bind_trans_id = -1;
156 static int hf_dcerpc_cn_bind_trans_ver = -1;
157 static int hf_dcerpc_cn_alloc_hint = -1;
158 static int hf_dcerpc_cn_sec_addr_len = -1;
159 static int hf_dcerpc_cn_sec_addr = -1;
160 static int hf_dcerpc_cn_num_results = -1;
161 static int hf_dcerpc_cn_ack_result = -1;
162 static int hf_dcerpc_cn_ack_reason = -1;
163 static int hf_dcerpc_cn_ack_trans_id = -1;
164 static int hf_dcerpc_cn_ack_trans_ver = -1;
165 static int hf_dcerpc_cn_cancel_count = -1;
166 static int hf_dcerpc_auth_type = -1;
167 static int hf_dcerpc_auth_level = -1;
168 static int hf_dcerpc_auth_pad_len = -1;
169 static int hf_dcerpc_auth_rsrvd = -1;
170 static int hf_dcerpc_auth_ctx_id = -1;
171 static int hf_dcerpc_dg_flags1 = -1;
172 static int hf_dcerpc_dg_flags1_rsrvd_01 = -1;
173 static int hf_dcerpc_dg_flags1_last_frag = -1;
174 static int hf_dcerpc_dg_flags1_frag = -1;
175 static int hf_dcerpc_dg_flags1_nofack = -1;
176 static int hf_dcerpc_dg_flags1_maybe = -1;
177 static int hf_dcerpc_dg_flags1_idempotent = -1;
178 static int hf_dcerpc_dg_flags1_broadcast = -1;
179 static int hf_dcerpc_dg_flags1_rsrvd_80 = -1;
180 static int hf_dcerpc_dg_flags2 = -1;
181 static int hf_dcerpc_dg_flags2_rsrvd_01 = -1;
182 static int hf_dcerpc_dg_flags2_cancel_pending = -1;
183 static int hf_dcerpc_dg_flags2_rsrvd_04 = -1;
184 static int hf_dcerpc_dg_flags2_rsrvd_08 = -1;
185 static int hf_dcerpc_dg_flags2_rsrvd_10 = -1;
186 static int hf_dcerpc_dg_flags2_rsrvd_20 = -1;
187 static int hf_dcerpc_dg_flags2_rsrvd_40 = -1;
188 static int hf_dcerpc_dg_flags2_rsrvd_80 = -1;
189 static int hf_dcerpc_dg_serial_hi = -1;
190 static int hf_dcerpc_obj_id = -1;
191 static int hf_dcerpc_dg_if_id = -1;
192 static int hf_dcerpc_dg_act_id = -1;
193 static int hf_dcerpc_dg_serial_lo = -1;
194 static int hf_dcerpc_dg_ahint = -1;
195 static int hf_dcerpc_dg_ihint = -1;
196 static int hf_dcerpc_dg_frag_len = -1;
197 static int hf_dcerpc_dg_frag_num = -1;
198 static int hf_dcerpc_dg_auth_proto = -1;
199 static int hf_dcerpc_opnum = -1;
200 static int hf_dcerpc_dg_seqnum = -1;
201 static int hf_dcerpc_dg_server_boot = -1;
202 static int hf_dcerpc_dg_if_ver = -1;
203 static int hf_dcerpc_array_max_count = -1;
204 static int hf_dcerpc_array_offset = -1;
205 static int hf_dcerpc_array_actual_count = -1;
206 static int hf_dcerpc_op = -1;
207 static int hf_dcerpc_referent_id = -1;
208 static int hf_dcerpc_fragments = -1;
209 static int hf_dcerpc_fragment = -1;
210 static int hf_dcerpc_fragment_overlap = -1;
211 static int hf_dcerpc_fragment_overlap_conflict = -1;
212 static int hf_dcerpc_fragment_multiple_tails = -1;
213 static int hf_dcerpc_fragment_too_long_fragment = -1;
214 static int hf_dcerpc_fragment_error = -1;
216 static gint ett_dcerpc = -1;
217 static gint ett_dcerpc_cn_flags = -1;
218 static gint ett_dcerpc_drep = -1;
219 static gint ett_dcerpc_dg_flags1 = -1;
220 static gint ett_dcerpc_dg_flags2 = -1;
221 static gint ett_dcerpc_pointer_data = -1;
222 static gint ett_dcerpc_fragments = -1;
223 static gint ett_dcerpc_fragment = -1;
225 /* try to desegment big DCE/RPC packets over TCP? */
226 static gboolean dcerpc_cn_desegment = TRUE;
228 /* reassemble DCE/RPC fragments */
229 /* reassembly of dcerpc fragments will not work for the case where ONE frame
230 might contain multiple dcerpc fragments for different PDUs.
231 this case would be so unusual/weird so if you got captures like that:
234 static gboolean dcerpc_reassemble = FALSE;
235 static GHashTable *dcerpc_reassemble_table = NULL;
238 dcerpc_reassemble_init(void)
240 fragment_table_init(&dcerpc_reassemble_table);
247 /* the registered subdissectors */
248 static GHashTable *dcerpc_uuids;
250 typedef struct _dcerpc_uuid_key {
255 typedef struct _dcerpc_uuid_value {
259 dcerpc_sub_dissector *procs;
263 dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2)
265 dcerpc_uuid_key *key1 = (dcerpc_uuid_key *)k1;
266 dcerpc_uuid_key *key2 = (dcerpc_uuid_key *)k2;
267 return ((memcmp (&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
268 && (key1->ver == key2->ver));
272 dcerpc_uuid_hash (gconstpointer k)
274 dcerpc_uuid_key *key = (dcerpc_uuid_key *)k;
275 /* This isn't perfect, but the Data1 part of these is almost always
277 return key->uuid.Data1;
281 dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver,
282 dcerpc_sub_dissector *procs)
284 dcerpc_uuid_key *key = g_malloc (sizeof (*key));
285 dcerpc_uuid_value *value = g_malloc (sizeof (*value));
290 value->proto = proto;
292 value->name = proto_get_protocol_short_name (proto);
293 value->procs = procs;
295 g_hash_table_insert (dcerpc_uuids, key, value);
300 * To keep track of ctx_id mappings.
302 * Everytime we see a bind call we update this table.
303 * Note that we always specify a SMB FID. For non-SMB transports this
306 static GHashTable *dcerpc_binds=NULL;
308 typedef struct _dcerpc_bind_key {
309 conversation_t *conv;
314 typedef struct _dcerpc_bind_value {
319 static GMemChunk *dcerpc_bind_key_chunk=NULL;
320 static GMemChunk *dcerpc_bind_value_chunk=NULL;
323 dcerpc_bind_equal (gconstpointer k1, gconstpointer k2)
325 dcerpc_bind_key *key1 = (dcerpc_bind_key *)k1;
326 dcerpc_bind_key *key2 = (dcerpc_bind_key *)k2;
327 return (key1->conv == key2->conv
328 && key1->ctx_id == key2->ctx_id
329 && key1->smb_fid == key2->smb_fid);
333 dcerpc_bind_hash (gconstpointer k)
335 dcerpc_bind_key *key = (dcerpc_bind_key *)k;
336 return ((guint)key->conv) + key->ctx_id + key->smb_fid;
340 * To keep track of callid mappings. Should really use some generic
341 * conversation support instead.
343 static GHashTable *dcerpc_calls=NULL;
345 typedef struct _dcerpc_call_key {
346 conversation_t *conv;
351 static GMemChunk *dcerpc_call_key_chunk=NULL;
353 static GMemChunk *dcerpc_call_value_chunk=NULL;
356 dcerpc_call_equal (gconstpointer k1, gconstpointer k2)
358 dcerpc_call_key *key1 = (dcerpc_call_key *)k1;
359 dcerpc_call_key *key2 = (dcerpc_call_key *)k2;
360 return (key1->conv == key2->conv
361 && key1->call_id == key2->call_id
362 && key1->smb_fid == key2->smb_fid);
366 dcerpc_call_hash (gconstpointer k)
368 dcerpc_call_key *key = (dcerpc_call_key *)k;
369 return ((guint32)key->conv) + key->call_id + key->smb_fid;
373 /* to keep track of matched calls/responses
374 this one uses the same value struct as calls, but the key is the frame id
376 static GHashTable *dcerpc_matched=NULL;
378 dcerpc_matched_equal (gconstpointer k1, gconstpointer k2)
380 return (guint32)k1 == (guint32)k2;
384 dcerpc_matched_hash (gconstpointer k)
392 * Utility functions. Modeled after packet-rpc.c
396 dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
397 proto_tree *tree, char *drep,
398 int hfindex, guint8 *pdata)
402 data = tvb_get_guint8 (tvb, offset);
404 proto_tree_add_item (tree, hfindex, tvb, offset, 1, (drep[0] & 0x10));
412 dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
413 proto_tree *tree, char *drep,
414 int hfindex, guint16 *pdata)
418 data = ((drep[0] & 0x10)
419 ? tvb_get_letohs (tvb, offset)
420 : tvb_get_ntohs (tvb, offset));
423 proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10));
431 dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
432 proto_tree *tree, char *drep,
433 int hfindex, guint32 *pdata)
437 data = ((drep[0] & 0x10)
438 ? tvb_get_letohl (tvb, offset)
439 : tvb_get_ntohl (tvb, offset));
442 proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10));
450 dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
451 proto_tree *tree, char *drep,
452 int hfindex, unsigned char *pdata)
455 tvb_memcpy(tvb, pdata, offset, 8);
456 if(drep[0] & 0x10){/* XXX this might be the wrong way around */
458 data=pdata[0];pdata[0]=pdata[7];pdata[7]=data;
459 data=pdata[1];pdata[1]=pdata[6];pdata[6]=data;
460 data=pdata[2];pdata[2]=pdata[5];pdata[5]=data;
461 data=pdata[3];pdata[3]=pdata[4];pdata[4]=data;
466 proto_tree_add_item(tree, hfindex, tvb, offset, 8, (drep[0] & 0x10));
473 * a couple simpler things
476 dcerpc_tvb_get_ntohs (tvbuff_t *tvb, gint offset, char *drep)
478 if (drep[0] & 0x10) {
479 return tvb_get_letohs (tvb, offset);
481 return tvb_get_ntohs (tvb, offset);
486 dcerpc_tvb_get_ntohl (tvbuff_t *tvb, gint offset, char *drep)
488 if (drep[0] & 0x10) {
489 return tvb_get_letohl (tvb, offset);
491 return tvb_get_ntohl (tvb, offset);
496 dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, char *drep, e_uuid_t *uuid)
499 uuid->Data1 = dcerpc_tvb_get_ntohl (tvb, offset, drep);
500 uuid->Data2 = dcerpc_tvb_get_ntohs (tvb, offset+4, drep);
501 uuid->Data3 = dcerpc_tvb_get_ntohs (tvb, offset+6, drep);
503 for (i=0; i<sizeof (uuid->Data4); i++) {
504 uuid->Data4[i] = tvb_get_guint8 (tvb, offset+8+i);
511 /* function to dissect a unidimensional conformant array */
513 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
514 proto_tree *tree, char *drep,
515 dcerpc_dissect_fnct_t *fnct)
521 di=pinfo->private_data;
522 if(di->conformant_run){
523 /* conformant run, just dissect the max_count header */
525 di->conformant_run=0;
526 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
527 hf_dcerpc_array_max_count, &di->array_max_count);
528 di->array_max_count_offset=offset-4;
529 di->conformant_run=1;
530 di->conformant_eaten=offset-old_offset;
532 /* we dont dont remember where in the bytestream this fields was */
533 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
535 /* real run, dissect the elements */
536 for(i=0;i<di->array_max_count;i++){
537 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
543 /* function to dissect a unidimensional conformant and varying array */
545 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
546 proto_tree *tree, char *drep,
547 dcerpc_dissect_fnct_t *fnct)
553 di=pinfo->private_data;
554 if(di->conformant_run){
555 /* conformant run, just dissect the max_count header */
557 di->conformant_run=0;
558 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
559 hf_dcerpc_array_max_count, &di->array_max_count);
560 di->array_max_count_offset=offset-4;
561 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
562 hf_dcerpc_array_offset, &di->array_offset);
563 di->array_offset_offset=offset-4;
564 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
565 hf_dcerpc_array_actual_count, &di->array_actual_count);
566 di->array_actual_count_offset=offset-4;
567 di->conformant_run=1;
568 di->conformant_eaten=offset-old_offset;
570 /* we dont dont remember where in the bytestream these fields were */
571 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
572 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
573 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
575 /* real run, dissect the elements */
576 for(i=0;i<di->array_actual_count;i++){
577 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
585 /* ndr pointer handling */
586 /* list of pointers encountered so far */
587 static GSList *ndr_pointer_list = NULL;
589 /* position where in the list to insert newly encountered pointers */
590 static int ndr_pointer_list_pos=0;
592 /* boolean controlling whether pointers are top-level or embedded */
593 static gboolean pointers_are_top_level = TRUE;
595 /* as a kludge, we represent all embedded reference pointers as id==-1
596 hoping that his will not collide with any non-ref pointers */
597 typedef struct ndr_pointer_data {
600 dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
603 } ndr_pointer_data_t;
606 init_ndr_pointer_list(packet_info *pinfo)
610 di=pinfo->private_data;
611 di->conformant_run=0;
613 while(ndr_pointer_list){
614 ndr_pointer_data_t *npd;
616 npd=g_slist_nth_data(ndr_pointer_list, 0);
617 ndr_pointer_list=g_slist_remove(ndr_pointer_list, npd);
623 ndr_pointer_list=NULL;
624 ndr_pointer_list_pos=0;
625 pointers_are_top_level=TRUE;
629 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, char *drep)
631 int found_new_pointer;
635 di=pinfo->private_data;
640 len=g_slist_length(ndr_pointer_list);
642 ndr_pointer_data_t *tnpd;
643 tnpd=g_slist_nth_data(ndr_pointer_list, i);
645 dcerpc_dissect_fnct_t *fnct;
650 ndr_pointer_list_pos=i+1;
651 di->hf_index=tnpd->hf_index;
652 di->levels=tnpd->levels;
653 /* first a run to handle any conformant
655 di->conformant_run=1;
656 di->conformant_eaten=0;
658 offset = (*(fnct))(tvb, offset, pinfo, NULL, drep);
660 g_assert((offset-old_offset)==di->conformant_eaten);
661 /* This is to check for any bugs in the dissectors.
663 * Basically, the NDR representation will store all
664 * arrays in two blocks, one block with the dimension
665 * discreption, like size, number of elements and such,
666 * and another block that contains the actual data stored
668 * If the array is embedded directly inside another,
669 * encapsulating aggregate type, like a union or struct,
670 * then these two blocks will be stored at different places
671 * in the bytestream, with other data between the blocks.
673 * For this reason, all pointers to types (both aggregate
674 * and scalar, for simplicity no distinction is made)
675 * will have its dissector called twice.
676 * The dissector will first be called with conformant_run==1
677 * in which mode the dissector MUST NOT consume any data from
678 * the tvbuff (i.e. may not dissect anything) except the
679 * initial control block for arrays.
680 * The second time the dissector is called, with
681 * conformant_run==0, all other data for the type will be
684 * All dissect_ndr_<type> dissectors are already prepared
685 * for this and knows when it should eat data from the tvb
686 * and when not to, so implementors of dissectors will
687 * normally not need to worry about this or even know about
688 * it. However, if a dissector for an aggregate type calls
689 * a subdissector from outside packet-dcerpc.c, such as
690 * the dissector in packet-smb.c for NT Security Descriptors
691 * as an example, then it is VERY important to encapsulate
692 * this call to an external subdissector with the appropriate
693 * test for conformant_run, i.e. it will need something like
697 * di=pinfo->private_data;
698 * if(di->conformant_run){
702 * to make sure it makes the right thing.
703 * This assert will signal when someone has forgotten to
704 * make the dissector aware of this requirement.
707 /* now we dissect the actual pointer */
708 di->conformant_run=0;
709 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, drep);
713 } while(found_new_pointer);
720 add_pointer_to_list(packet_info *pinfo, proto_tree *tree,
721 dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index, int levels)
723 ndr_pointer_data_t *npd;
725 /* check if this pointer is valid */
728 dcerpc_call_value *value;
730 di=pinfo->private_data;
734 if(!(pinfo->fd->flags.visited)){
735 if(id>value->max_ptr){
740 /* if we havent seen the request bail out since we cant
741 know whether this is the first non-NULL instance
743 if(value->req_frame==0){
744 /* XXX THROW EXCEPTION */
747 /* We saw this one in the request frame, nothing to
749 if(id<=value->max_ptr){
755 npd=g_malloc(sizeof(ndr_pointer_data_t));
759 npd->hf_index=hf_index;
761 ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
762 ndr_pointer_list_pos);
763 ndr_pointer_list_pos++;
768 find_pointer_index(guint32 id)
770 ndr_pointer_data_t *npd;
773 len=g_slist_length(ndr_pointer_list);
775 npd=g_slist_nth_data(ndr_pointer_list, i);
786 /* This function dissects an NDR pointer and stores the callback for later
787 * deferred dissection.
789 * fnct is the callback function for when we have reached this object in
792 * type is what type of pointer.
794 * this is text is what text we should put in any created tree node.
796 * hf_index is what hf value we want to pass to the callback function when
797 * it is called, the callback can later pich this one up from di->hf_index.
799 * levels is a generic int we want to pass to teh callback function. the
800 * callback can later pick it up from di->levels
802 * See packet-dcerpc-samr.c for examples
805 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
806 proto_tree *tree, char *drep, dcerpc_dissect_fnct_t *fnct,
807 int type, char *text, int hf_index, int levels)
811 di=pinfo->private_data;
812 if(di->conformant_run){
813 /* this call was only for dissecting the header for any
814 embedded conformant array. we will not parse any
815 pointers in this mode.
820 /*TOP LEVEL REFERENCE POINTER*/
821 if( pointers_are_top_level
822 &&(type==NDR_POINTER_REF) ){
826 /* we must find out a nice way to do the length here */
827 item=proto_tree_add_text(tree, tvb, offset, 0,
829 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
831 add_pointer_to_list(pinfo, tr, fnct, 0xffffffff, hf_index, levels);
835 /*TOP LEVEL FULL POINTER*/
836 if( pointers_are_top_level
837 && (type==NDR_POINTER_PTR) ){
843 /* get the referent id */
844 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
846 /* we got a NULL pointer */
848 proto_tree_add_text(tree, tvb, offset-4, 4,
849 "(NULL pointer) %s",text);
853 /* see if we have seen this pointer before */
854 idx=find_pointer_index(id);
856 /* we have seen this pointer before */
858 proto_tree_add_text(tree, tvb, offset-4, 4,
859 "(duplicate PTR) %s",text);
864 item=proto_tree_add_text(tree, tvb, offset-4, 4,
866 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
867 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
868 add_pointer_to_list(pinfo, tr, fnct, id, hf_index, levels);
871 /*TOP LEVEL UNIQUE POINTER*/
872 if( pointers_are_top_level
873 && (type==NDR_POINTER_UNIQUE) ){
878 /* get the referent id */
879 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
881 /* we got a NULL pointer */
883 proto_tree_add_text(tree, tvb, offset-4, 4,
884 "(NULL pointer) %s",text);
889 item=proto_tree_add_text(tree, tvb, offset-4, 4,
891 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
892 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
893 add_pointer_to_list(pinfo, tr, fnct, 0xffffffff, hf_index, levels);
897 /*EMBEDDED REFERENCE POINTER*/
898 if( (!pointers_are_top_level)
899 && (type==NDR_POINTER_REF) ){
904 /* get the referent id */
905 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
908 item=proto_tree_add_text(tree, tvb, offset-4, 4,
910 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
911 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
912 add_pointer_to_list(pinfo, tr, fnct, 0xffffffff, hf_index, levels);
916 /*EMBEDDED UNIQUE POINTER*/
917 if( (!pointers_are_top_level)
918 && (type==NDR_POINTER_UNIQUE) ){
923 /* get the referent id */
924 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
926 /* we got a NULL pointer */
928 proto_tree_add_text(tree, tvb, offset-4, 4,
929 "(NULL pointer) %s", text);
934 item=proto_tree_add_text(tree, tvb, offset-4, 4,
936 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
937 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
938 add_pointer_to_list(pinfo, tr, fnct, 0xffffffff, hf_index, levels);
942 /*EMBEDDED FULL POINTER*/
943 if( (!pointers_are_top_level)
944 && (type==NDR_POINTER_PTR) ){
950 /* get the referent id */
951 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
953 /* we got a NULL pointer */
955 proto_tree_add_text(tree, tvb, offset-4, 4,
956 "(NULL pointer) %s",text);
960 /* see if we have seen this pointer before */
961 idx=find_pointer_index(id);
963 /* we have seen this pointer before */
965 proto_tree_add_text(tree, tvb, offset-4, 4,
966 "(duplicate PTR) %s",text);
971 item=proto_tree_add_text(tree, tvb, offset-4, 4,
973 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
974 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
975 add_pointer_to_list(pinfo, tr, fnct, id, hf_index, levels);
981 /* After each top level pointer we have dissected we have to
982 dissect all deferrals before we move on to the next top level
984 if(pointers_are_top_level==TRUE){
985 pointers_are_top_level=FALSE;
986 offset = dissect_deferred_pointers(pinfo, tvb, offset, drep);
987 pointers_are_top_level=TRUE;
996 dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
997 proto_tree *dcerpc_tree,
998 tvbuff_t *tvb, gint offset,
999 guint16 opnum, gboolean is_rqst,
1000 char *drep, dcerpc_info *info,
1003 dcerpc_uuid_key key;
1004 dcerpc_uuid_value *sub_proto;
1006 proto_tree *sub_tree = NULL;
1007 dcerpc_sub_dissector *proc;
1009 dcerpc_dissect_fnct_t *sub_dissect;
1010 const char *saved_proto;
1011 void *saved_private_data;
1013 key.uuid = info->call_data->uuid;
1014 key.ver = info->call_data->ver;
1017 if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == NULL
1018 || !proto_is_protocol_enabled(sub_proto->proto)) {
1020 * We don't have a dissector for this UUID, or the protocol
1021 * for that UUID is disabled.
1023 length = tvb_length_remaining (tvb, offset);
1025 proto_tree_add_text (dcerpc_tree, tvb, offset, length,
1026 "Stub data (%d byte%s)", length,
1027 plurality(length, "", "s"));
1032 for (proc = sub_proto->procs; proc->name; proc++) {
1033 if (proc->num == opnum) {
1042 if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
1043 col_set_str (pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
1046 if (check_col (pinfo->cinfo, COL_INFO)) {
1047 col_add_fstr (pinfo->cinfo, COL_INFO, "%s %s",
1048 name, is_rqst ? "request" : "reply");
1052 proto_item *sub_item;
1053 sub_item = proto_tree_add_item (tree, sub_proto->proto, tvb, offset,
1057 sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
1061 * Put the operation number into the tree along with
1062 * the operation's name.
1064 * XXX - the subdissectors should all have their own fields
1065 * for the opnum, so that you can filter on a particular
1066 * protocol and opnum value; the opnum value isn't, by itself,
1067 * very interesting, as its interpretation depends on the
1070 * That would also allow the field to have a value_string
1071 * table, giving names for operations, and letting you filter
1074 * ONC RPC should do the same thing with the version and
1075 * procedure fields it puts into the subprotocol's tree.
1077 proto_tree_add_uint_format (sub_tree, hf_dcerpc_op, tvb,
1079 "Operation: %s (%u)",
1084 * If the authentication level is DCE_C_AUTHN_LEVEL_PKT_PRIVACY,
1085 * the stub data is encrypted, and we can't dissect it.
1087 if (auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
1088 length = tvb_length_remaining (tvb, offset);
1090 proto_tree_add_text(sub_tree, tvb, offset, length,
1091 "Encrypted stub data (%d byte%s)",
1092 length, plurality(length, "", "s"));
1095 sub_dissect = is_rqst ? proc->dissect_rqst : proc->dissect_resp;
1097 saved_proto = pinfo->current_proto;
1098 saved_private_data = pinfo->private_data;
1099 pinfo->current_proto = sub_proto->name;
1100 pinfo->private_data = (void *)info;
1102 init_ndr_pointer_list(pinfo);
1103 offset = sub_dissect (tvb, offset, pinfo, sub_tree, drep);
1105 pinfo->current_proto = saved_proto;
1106 pinfo->private_data = saved_private_data;
1108 length = tvb_length_remaining (tvb, offset);
1110 proto_tree_add_text (sub_tree, tvb, offset, length,
1111 "Stub data (%d byte%s)", length,
1112 plurality(length, "", "s"));
1120 dissect_dcerpc_cn_auth (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1121 e_dce_cn_common_hdr_t *hdr, int *auth_level_p)
1124 guint8 auth_pad_len;
1128 * Initially set "*auth_level_p" to -1 to indicate that we haven't
1129 * yet seen any authentication level information.
1131 if (auth_level_p != NULL)
1135 * The authentication information is at the *end* of the PDU; in
1136 * request and response PDUs, the request and response stub data
1139 * If the full packet is here, and we've got an auth len, and it's
1140 * valid, then dissect the auth info.
1142 if (tvb_length (tvb) >= hdr->frag_len
1144 && (hdr->auth_len + 8 <= hdr->frag_len)) {
1146 offset = hdr->frag_len - (hdr->auth_len + 8);
1148 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1149 hf_dcerpc_auth_type, NULL);
1150 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1151 hf_dcerpc_auth_level, &auth_level);
1152 if (auth_level_p != NULL)
1153 *auth_level_p = auth_level;
1154 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1155 hf_dcerpc_auth_pad_len, &auth_pad_len);
1156 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1157 hf_dcerpc_auth_rsrvd, NULL);
1158 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1159 hf_dcerpc_auth_ctx_id, NULL);
1161 proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len, "Auth Data");
1163 /* figure out where the auth padding starts */
1164 offset = hdr->frag_len - (hdr->auth_len + 8 + auth_pad_len);
1165 if (offset > 0 && auth_pad_len) {
1166 proto_tree_add_text (dcerpc_tree, tvb, offset,
1167 auth_pad_len, "Auth padding");
1168 return hdr->auth_len + 8 + auth_pad_len;
1170 return hdr->auth_len + 8;
1178 /* We need to hash in the SMB fid number to generate a unique hash table
1179 key as DCERPC over SMB allows several pipes over the same TCP/IP
1182 static guint16 get_smb_fid (void *private_data)
1184 dcerpc_private_info *priv = (dcerpc_private_info *)private_data;
1187 return 0; /* Nothing to see here */
1189 /* DCERPC over smb */
1191 if (priv->transport_type == DCERPC_TRANSPORT_SMB)
1192 return priv->data.smb.fid;
1194 /* Some other transport... */
1200 * Connection oriented packet types
1204 dissect_dcerpc_cn_bind (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1205 e_dce_cn_common_hdr_t *hdr)
1207 conversation_t *conv = NULL;
1208 guint8 num_ctx_items;
1210 gboolean saw_ctx_item = FALSE;
1212 guint16 num_trans_items;
1217 guint16 if_ver, if_ver_minor;
1220 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1221 hf_dcerpc_cn_max_xmit, NULL);
1223 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1224 hf_dcerpc_cn_max_recv, NULL);
1226 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1227 hf_dcerpc_cn_assoc_group, NULL);
1229 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1230 hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
1235 for (i = 0; i < num_ctx_items; i++) {
1236 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1237 hf_dcerpc_cn_ctx_id, &ctx_id);
1239 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1240 hf_dcerpc_cn_num_trans_items, &num_trans_items);
1242 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
1244 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_if_id, tvb,
1246 "Interface UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1247 if_id.Data1, if_id.Data2, if_id.Data3,
1248 if_id.Data4[0], if_id.Data4[1],
1249 if_id.Data4[2], if_id.Data4[3],
1250 if_id.Data4[4], if_id.Data4[5],
1251 if_id.Data4[6], if_id.Data4[7]);
1255 if (hdr->drep[0] & 0x10) {
1256 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1257 hf_dcerpc_cn_bind_if_ver, &if_ver);
1258 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1259 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
1261 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1262 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
1263 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1264 hf_dcerpc_cn_bind_if_ver, &if_ver);
1267 if (!saw_ctx_item) {
1268 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
1269 pinfo->srcport, pinfo->destport, 0);
1271 conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
1272 pinfo->srcport, pinfo->destport, 0);
1275 /* if this is the first time we see this packet, we need to
1276 update the dcerpc_binds table so that any later calls can
1277 match to the interface.
1278 XXX We assume that BINDs will NEVER be fragmented.
1280 if(!(pinfo->fd->flags.visited)){
1281 dcerpc_bind_key *key;
1282 dcerpc_bind_value *value;
1284 key = g_mem_chunk_alloc (dcerpc_bind_key_chunk);
1286 key->ctx_id = ctx_id;
1287 key->smb_fid = get_smb_fid(pinfo->private_data);
1289 value = g_mem_chunk_alloc (dcerpc_bind_value_chunk);
1290 value->uuid = if_id;
1291 value->ver = if_ver;
1293 /* add this entry to the bind table, first removing any
1294 previous ones that are identical
1296 if(g_hash_table_lookup(dcerpc_binds, key)){
1297 g_hash_table_remove(dcerpc_binds, key);
1299 g_hash_table_insert (dcerpc_binds, key, value);
1302 if (check_col (pinfo->cinfo, COL_INFO)) {
1303 col_add_fstr (pinfo->cinfo, COL_INFO, "%s: UUID %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %d.%d",
1304 hdr->ptype == PDU_BIND ? "Bind" : "Alter Ctx",
1305 if_id.Data1, if_id.Data2, if_id.Data3,
1306 if_id.Data4[0], if_id.Data4[1],
1307 if_id.Data4[2], if_id.Data4[3],
1308 if_id.Data4[4], if_id.Data4[5],
1309 if_id.Data4[6], if_id.Data4[7],
1310 if_ver, if_ver_minor);
1312 saw_ctx_item = TRUE;
1315 for (j = 0; j < num_trans_items; j++) {
1316 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
1318 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_trans_id, tvb,
1320 "Transfer Syntax: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1321 trans_id.Data1, trans_id.Data2, trans_id.Data3,
1322 trans_id.Data4[0], trans_id.Data4[1],
1323 trans_id.Data4[2], trans_id.Data4[3],
1324 trans_id.Data4[4], trans_id.Data4[5],
1325 trans_id.Data4[6], trans_id.Data4[7]);
1329 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1330 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
1335 * XXX - we should save the authentication type *if* we have
1336 * an authentication header, and associate it with an authentication
1337 * context, so subsequent PDUs can use that context.
1339 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, NULL);
1343 dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1344 e_dce_cn_common_hdr_t *hdr)
1346 guint16 max_xmit, max_recv;
1347 guint16 sec_addr_len;
1357 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1358 hf_dcerpc_cn_max_xmit, &max_xmit);
1360 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1361 hf_dcerpc_cn_max_recv, &max_recv);
1363 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1364 hf_dcerpc_cn_assoc_group, NULL);
1366 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1367 hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
1368 if (sec_addr_len != 0) {
1369 proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
1370 sec_addr_len, FALSE);
1371 offset += sec_addr_len;
1375 offset += 4 - offset % 4;
1378 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1379 hf_dcerpc_cn_num_results, &num_results);
1384 for (i = 0; i < num_results; i++) {
1385 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
1386 hdr->drep, hf_dcerpc_cn_ack_result,
1388 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
1389 hdr->drep, hf_dcerpc_cn_ack_reason,
1392 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
1394 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_ack_trans_id, tvb,
1396 "Transfer Syntax: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1397 trans_id.Data1, trans_id.Data2, trans_id.Data3,
1398 trans_id.Data4[0], trans_id.Data4[1],
1399 trans_id.Data4[2], trans_id.Data4[3],
1400 trans_id.Data4[4], trans_id.Data4[5],
1401 trans_id.Data4[6], trans_id.Data4[7]);
1405 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1406 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
1410 * XXX - do we need to do anything with the authentication level
1411 * we get back from this?
1413 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, NULL);
1415 if (check_col (pinfo->cinfo, COL_INFO)) {
1416 if (num_results != 0 && result == 0) {
1417 col_add_fstr (pinfo->cinfo, COL_INFO, "%s ack: accept max_xmit: %d max_recv: %d",
1418 hdr->ptype == PDU_BIND_ACK ? "Bind" : "Alter ctx",
1419 max_xmit, max_recv);
1421 /* FIXME: should put in reason */
1422 col_add_fstr (pinfo->cinfo, COL_INFO, "%s ack: %s",
1423 hdr->ptype == PDU_BIND_ACK ? "Bind" : "Alter ctx",
1424 result == 1 ? "User reject" :
1425 result == 2 ? "Provider reject" :
1432 dissect_dcerpc_cn_rqst (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1433 proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
1435 conversation_t *conv;
1444 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1445 hf_dcerpc_cn_alloc_hint, &alloc_hint);
1447 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1448 hf_dcerpc_cn_ctx_id, &ctx_id);
1450 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1451 hf_dcerpc_opnum, &opnum);
1453 if (check_col (pinfo->cinfo, COL_INFO)) {
1454 col_add_fstr (pinfo->cinfo, COL_INFO, "Request: opnum: %d ctx_id:%d",
1458 if (hdr->flags & 0x80) {
1459 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id);
1461 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
1463 "Object UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1464 obj_id.Data1, obj_id.Data2, obj_id.Data3,
1478 * XXX - what if this was set when the connection was set up,
1479 * and we just have a security context?
1481 auth_sz = dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr,
1484 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
1485 pinfo->srcport, pinfo->destport, 0);
1489 dcerpc_call_value *value;
1490 int length, reported_length, stub_length;
1493 /* !!! we can NOT check flags.visited here since this will interact
1494 badly with when SMB handles (i.e. calls the subdissector)
1495 and desegmented pdu's .
1496 Instead we check if this pdu is already in the matched table or not
1498 if(!g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num)){
1499 dcerpc_bind_key bind_key;
1500 dcerpc_bind_value *bind_value;
1503 bind_key.ctx_id=ctx_id;
1504 bind_key.smb_fid=get_smb_fid(pinfo->private_data);
1506 if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key))){
1507 dcerpc_call_key *call_key;
1508 dcerpc_call_value *call_value;
1510 /* We found the binding so just add the call
1511 to both the call table and the matched table
1513 call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
1514 call_key->conv=conv;
1515 call_key->call_id=hdr->call_id;
1516 call_key->smb_fid=get_smb_fid(pinfo->private_data);
1518 /* if there is already a matching call in the table
1519 remove it so it is replaced with the new one */
1520 if(g_hash_table_lookup(dcerpc_calls, call_key)){
1521 g_hash_table_remove(dcerpc_calls, call_key);
1524 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
1525 call_value->uuid = bind_value->uuid;
1526 call_value->ver = bind_value->ver;
1527 call_value->opnum = opnum;
1528 call_value->req_frame=pinfo->fd->num;
1529 call_value->rep_frame=0;
1530 call_value->max_ptr=0;
1531 call_value->private_data = NULL;
1532 g_hash_table_insert (dcerpc_calls, call_key, call_value);
1534 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
1538 value=g_hash_table_lookup (dcerpc_matched, (void *)pinfo->fd->num);
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 if(value->rep_frame!=0){
1558 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
1559 tvb, 0, 0, value->rep_frame);
1562 /* If we dont have reassembly enabled, or this packet contains the
1563 entire PDU, just call the handoff directly */
1564 if( (!dcerpc_reassemble)
1565 || ((hdr->flags&0x03)==0x03) ){
1566 if(hdr->flags&0x01){
1567 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
1568 tvb_new_subset (tvb, offset, length,
1570 0, opnum, TRUE, hdr->drep, &di, auth_level);
1572 if (check_col(pinfo->cinfo, COL_INFO)) {
1573 col_add_fstr(pinfo->cinfo, COL_INFO, "[DCE/RPC fragment]");
1576 } else if(dcerpc_reassemble){
1577 /*OK we need to do reassembly */
1578 /* handle first fragment */
1579 if((hdr->flags&0x03)==0x01){ /* FIRST fragment */
1580 if( (!pinfo->fd->flags.visited) && value->req_frame ){
1581 fragment_add(tvb, offset, pinfo, value->req_frame,
1582 dcerpc_reassemble_table,
1586 fragment_set_tot_len(pinfo, value->req_frame,
1587 dcerpc_reassemble_table, alloc_hint);
1589 if (check_col(pinfo->cinfo, COL_INFO)) {
1590 col_add_fstr(pinfo->cinfo, COL_INFO, "[DCE/RPC fragment]");
1593 if((hdr->flags&0x03)==0x00){ /* MIDDLE fragment(s) */
1594 if( (!pinfo->fd->flags.visited) && value->req_frame ){
1596 tot_len = fragment_get_tot_len(pinfo, value->req_frame,
1597 dcerpc_reassemble_table);
1598 fragment_add(tvb, offset, pinfo, value->req_frame,
1599 dcerpc_reassemble_table,
1604 if (check_col(pinfo->cinfo, COL_INFO)) {
1605 col_add_fstr(pinfo->cinfo, COL_INFO, "[DCE/RPC fragment]");
1608 if((hdr->flags&0x03)==0x02){ /* LAST fragment */
1609 if( value->req_frame ){
1610 fragment_data *ipfd_head;
1612 tot_len = fragment_get_tot_len(pinfo, value->req_frame,
1613 dcerpc_reassemble_table);
1614 ipfd_head = fragment_add(tvb, offset, pinfo,
1616 dcerpc_reassemble_table,
1622 fragment_data *ipfd;
1623 proto_tree *ft=NULL;
1624 proto_item *fi=NULL;
1627 next_tvb = tvb_new_real_data(ipfd_head->data, ipfd_head->datalen, ipfd_head->datalen);
1628 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
1629 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
1630 pinfo->fragmented=FALSE;
1631 fi = proto_tree_add_item(dcerpc_tree, hf_dcerpc_fragments, next_tvb, 0, -1, FALSE);
1632 ft = proto_item_add_subtree(fi, ett_dcerpc_fragments);
1633 for (ipfd=ipfd_head->next; ipfd; ipfd=ipfd->next){
1634 if (ipfd->flags & (FD_OVERLAP|FD_OVERLAPCONFLICT|FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
1635 proto_tree *fet=NULL;
1636 proto_item *fei=NULL;
1639 if (ipfd->flags & (FD_OVERLAPCONFLICT|FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
1640 hf = hf_dcerpc_fragment_error;
1642 hf = hf_dcerpc_fragment;
1644 fei = proto_tree_add_none_format(ft, hf,
1645 next_tvb, ipfd->offset, ipfd->len,
1646 "Frame:%u payload:%u-%u",
1649 ipfd->offset+ipfd->len-1);
1650 fet = proto_item_add_subtree(fei, ett_dcerpc_fragment);
1651 if (ipfd->flags&FD_OVERLAP) {
1652 proto_tree_add_boolean(fet, hf_dcerpc_fragment_overlap, next_tvb, 0, 0, TRUE);
1654 if (ipfd->flags&FD_OVERLAPCONFLICT) {
1655 proto_tree_add_boolean(fet, hf_dcerpc_fragment_overlap_conflict, next_tvb, 0, 0, TRUE);
1657 if (ipfd->flags&FD_MULTIPLETAILS) {
1658 proto_tree_add_boolean(fet, hf_dcerpc_fragment_multiple_tails, next_tvb, 0, 0, TRUE);
1660 if (ipfd->flags&FD_TOOLONGFRAGMENT) {
1661 proto_tree_add_boolean(fet, hf_dcerpc_fragment_too_long_fragment, next_tvb, 0, 0, TRUE);
1664 proto_tree_add_none_format(ft, hf_dcerpc_fragment,
1665 next_tvb, ipfd->offset, ipfd->len,
1666 "Frame:%u payload:%u-%u",
1669 ipfd->offset+ipfd->len-1
1673 if (ipfd_head->flags & (FD_OVERLAPCONFLICT|FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
1674 if (check_col(pinfo->cinfo, COL_INFO)) {
1675 col_set_str(pinfo->cinfo, COL_INFO, "[Illegal fragments]");
1678 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
1680 0, opnum, TRUE, hdr->drep, &di,
1683 if (check_col(pinfo->cinfo, COL_INFO)) {
1684 col_add_fstr(pinfo->cinfo, COL_INFO, "[DCE/RPC fragment]");
1696 dissect_dcerpc_cn_resp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1697 proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
1699 dcerpc_call_value *value = NULL;
1700 conversation_t *conv;
1707 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1708 hf_dcerpc_cn_alloc_hint, &alloc_hint);
1710 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1711 hf_dcerpc_cn_ctx_id, &ctx_id);
1713 if (check_col (pinfo->cinfo, COL_INFO)) {
1714 col_add_fstr (pinfo->cinfo, COL_INFO, "Response: call_id: %d ctx_id:%d",
1715 hdr->call_id, ctx_id);
1718 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1719 hf_dcerpc_cn_cancel_count, NULL);
1724 * XXX - what if this was set when the connection was set up,
1725 * and we just have a security context?
1727 auth_sz = dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr,
1730 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
1731 pinfo->srcport, pinfo->destport, 0);
1733 /* no point in creating one here, really */
1736 /* !!! we can NOT check flags.visited here since this will interact
1737 badly with when SMB handles (i.e. calls the subdissector)
1738 and desegmented pdu's .
1739 Instead we check if this pdu is already in the matched table or not
1741 if(!g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num)){
1742 dcerpc_call_key call_key;
1743 dcerpc_call_value *call_value;
1746 call_key.call_id=hdr->call_id;
1747 call_key.smb_fid=get_smb_fid(pinfo->private_data);
1749 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
1750 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
1751 if(call_value->rep_frame==0){
1752 call_value->rep_frame=pinfo->fd->num;
1758 value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
1761 int length, reported_length, stub_length;
1764 /* handoff this call */
1765 length = tvb_length_remaining(tvb, offset);
1766 reported_length = tvb_reported_length_remaining(tvb, offset);
1767 stub_length = hdr->frag_len - offset - auth_sz;
1768 if (length > stub_length)
1769 length = stub_length;
1770 if (reported_length > stub_length)
1771 reported_length = stub_length;
1773 di.call_id = hdr->call_id;
1774 di.smb_fid = get_smb_fid(pinfo->private_data);
1776 di.call_data = value;
1778 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
1779 if(value->req_frame!=0){
1780 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
1781 tvb, 0, 0, value->req_frame);
1784 /* If we dont have reassembly enabled, or this packet contains the
1785 entire PDU, just call the handoff directly */
1786 if( (!dcerpc_reassemble)
1787 || ((hdr->flags&0x03)==0x03) ){
1788 if(hdr->flags&0x01){
1789 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
1790 tvb_new_subset (tvb, offset, length,
1792 0, value->opnum, FALSE, hdr->drep, &di,
1795 if (check_col(pinfo->cinfo, COL_INFO)) {
1796 col_add_fstr(pinfo->cinfo, COL_INFO, "[DCE/RPC fragment]");
1799 } else if(dcerpc_reassemble){
1800 /*OK we need to do reassembly */
1801 /* handle first fragment */
1802 if((hdr->flags&0x03)==0x01){ /* FIRST fragment */
1803 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
1804 fragment_add(tvb, offset, pinfo, value->rep_frame,
1805 dcerpc_reassemble_table,
1809 fragment_set_tot_len(pinfo, value->rep_frame,
1810 dcerpc_reassemble_table, alloc_hint);
1812 if (check_col(pinfo->cinfo, COL_INFO)) {
1813 col_add_fstr(pinfo->cinfo, COL_INFO, "[DCE/RPC fragment]");
1816 if((hdr->flags&0x03)==0x00){ /* MIDDLE fragment(s) */
1817 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
1819 tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
1820 dcerpc_reassemble_table);
1821 fragment_add(tvb, offset, pinfo, value->rep_frame,
1822 dcerpc_reassemble_table,
1827 if (check_col(pinfo->cinfo, COL_INFO)) {
1828 col_add_fstr(pinfo->cinfo, COL_INFO, "[DCE/RPC fragment]");
1831 if((hdr->flags&0x03)==0x02){ /* LAST fragment */
1832 if( value->rep_frame ){
1833 fragment_data *ipfd_head;
1835 tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
1836 dcerpc_reassemble_table);
1837 ipfd_head = fragment_add(tvb, offset, pinfo,
1839 dcerpc_reassemble_table,
1845 fragment_data *ipfd;
1846 proto_tree *ft=NULL;
1847 proto_item *fi=NULL;
1850 next_tvb = tvb_new_real_data(ipfd_head->data, ipfd_head->datalen, ipfd_head->datalen);
1851 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
1852 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
1853 pinfo->fragmented=FALSE;
1854 fi = proto_tree_add_item(dcerpc_tree, hf_dcerpc_fragments, next_tvb, 0, -1, FALSE);
1855 ft = proto_item_add_subtree(fi, ett_dcerpc_fragments);
1856 for (ipfd=ipfd_head->next; ipfd; ipfd=ipfd->next){
1857 if (ipfd->flags & (FD_OVERLAP|FD_OVERLAPCONFLICT|FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
1858 proto_tree *fet=NULL;
1859 proto_item *fei=NULL;
1862 if (ipfd->flags & (FD_OVERLAPCONFLICT|FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
1863 hf = hf_dcerpc_fragment_error;
1865 hf = hf_dcerpc_fragment;
1867 fei = proto_tree_add_none_format(ft, hf,
1868 next_tvb, ipfd->offset, ipfd->len,
1869 "Frame:%u payload:%u-%u",
1872 ipfd->offset+ipfd->len-1);
1873 fet = proto_item_add_subtree(fei, ett_dcerpc_fragment);
1874 if (ipfd->flags&FD_OVERLAP) {
1875 proto_tree_add_boolean(fet, hf_dcerpc_fragment_overlap, next_tvb, 0, 0, TRUE);
1877 if (ipfd->flags&FD_OVERLAPCONFLICT) {
1878 proto_tree_add_boolean(fet, hf_dcerpc_fragment_overlap_conflict, next_tvb, 0, 0, TRUE);
1880 if (ipfd->flags&FD_MULTIPLETAILS) {
1881 proto_tree_add_boolean(fet, hf_dcerpc_fragment_multiple_tails, next_tvb, 0, 0, TRUE);
1883 if (ipfd->flags&FD_TOOLONGFRAGMENT) {
1884 proto_tree_add_boolean(fet, hf_dcerpc_fragment_too_long_fragment, next_tvb, 0, 0, TRUE);
1887 proto_tree_add_none_format(ft, hf_dcerpc_fragment,
1888 next_tvb, ipfd->offset, ipfd->len,
1889 "Frame:%u payload:%u-%u",
1892 ipfd->offset+ipfd->len-1
1896 if (ipfd_head->flags & (FD_OVERLAPCONFLICT|FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
1897 if (check_col(pinfo->cinfo, COL_INFO)) {
1898 col_set_str(pinfo->cinfo, COL_INFO, "[Illegal fragments]");
1901 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
1903 0, value->opnum, FALSE, hdr->drep, &di,
1906 if (check_col(pinfo->cinfo, COL_INFO)) {
1907 col_add_fstr(pinfo->cinfo, COL_INFO, "[DCE/RPC fragment]");
1919 * DCERPC dissector for connection oriented calls
1922 dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
1923 proto_tree *tree, gboolean can_desegment)
1925 static char nulls[4] = { 0 };
1928 proto_item *ti = NULL;
1929 proto_item *tf = NULL;
1930 proto_tree *dcerpc_tree = NULL;
1931 proto_tree *cn_flags_tree = NULL;
1932 proto_tree *drep_tree = NULL;
1933 e_dce_cn_common_hdr_t hdr;
1936 * when done over nbt, dcerpc requests are padded with 4 bytes of null
1937 * data for some reason.
1939 * XXX - if that's always the case, the right way to do this would
1940 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
1941 * the 4 bytes of null padding, and make that the dissector
1942 * used for "netbios".
1944 if (tvb_bytes_exist (tvb, offset, 4) &&
1945 tvb_memeql (tvb, offset, nulls, 4) == 0) {
1955 * Check if this looks like a C/O DCERPC call
1957 if (!tvb_bytes_exist (tvb, offset, sizeof (hdr))) {
1960 start_offset = offset;
1961 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
1962 if (hdr.rpc_ver != 5)
1964 hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
1965 if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
1967 hdr.ptype = tvb_get_guint8 (tvb, offset++);
1971 if (check_col (pinfo->cinfo, COL_PROTOCOL))
1972 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
1973 if (check_col (pinfo->cinfo, COL_INFO))
1974 col_set_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
1976 hdr.flags = tvb_get_guint8 (tvb, offset++);
1977 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
1978 offset += sizeof (hdr.drep);
1980 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1982 hdr.auth_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
1984 hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
1987 offset = start_offset;
1988 if (can_desegment && pinfo->can_desegment
1989 && hdr.frag_len > tvb_length_remaining (tvb, offset)) {
1990 pinfo->desegment_offset = offset;
1991 pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, offset);
1992 return 0; /* desegmentation required */
1996 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE);
1998 dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
2000 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver);
2001 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset++, 1, hdr.rpc_ver_minor);
2002 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype);
2003 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
2004 cn_flags_tree = proto_item_add_subtree (tf, ett_dcerpc_cn_flags);
2005 if (cn_flags_tree) {
2006 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
2007 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
2008 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
2009 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
2010 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
2011 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
2012 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
2013 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
2017 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
2018 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
2020 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
2021 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
2022 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
2024 offset += sizeof (hdr.drep);
2026 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
2029 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
2032 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
2038 * Packet type specific stuff is next.
2040 switch (hdr.ptype) {
2043 dissect_dcerpc_cn_bind (tvb, pinfo, dcerpc_tree, &hdr);
2048 dissect_dcerpc_cn_bind_ack (tvb, pinfo, dcerpc_tree, &hdr);
2052 dissect_dcerpc_cn_rqst (tvb, pinfo, dcerpc_tree, tree, &hdr);
2056 dissect_dcerpc_cn_resp (tvb, pinfo, dcerpc_tree, tree, &hdr);
2060 /* might as well dissect the auth info */
2061 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, NULL);
2064 return hdr.frag_len + padding;
2068 * DCERPC dissector for connection oriented calls over packet-oriented
2072 dissect_dcerpc_cn_pk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2075 * Only one PDU per transport packet, and only one transport
2078 if (dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE) == -1) {
2080 * It wasn't a DCERPC PDU.
2092 * DCERPC dissector for connection oriented calls over byte-stream
2096 dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2100 gboolean ret = FALSE;
2103 * There may be multiple PDUs per transport packet; keep
2106 while (tvb_reported_length_remaining(tvb, offset) != 0) {
2107 pdu_len = dissect_dcerpc_cn (tvb, offset, pinfo, tree,
2108 dcerpc_cn_desegment);
2109 if (pdu_len == -1) {
2117 * Well, we've seen at least one DCERPC PDU.
2123 * Desegmentation required - bail now.
2129 * Step to the next PDU.
2137 dissect_dcerpc_dg_auth (tvbuff_t *tvb, proto_tree *dcerpc_tree,
2138 e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
2143 * Initially set "*auth_level_p" to -1 to indicate that we haven't
2144 * yet seen any authentication level information.
2146 if (auth_level_p != NULL)
2150 * The authentication information is at the *end* of the PDU; in
2151 * request and response PDUs, the request and response stub data
2154 * If the full packet is here, and there's data past the end of the
2155 * packet body, then dissect the auth info.
2157 if (tvb_length (tvb) >= hdr->frag_len) {
2158 offset = hdr->frag_len;
2160 proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Auth data");
2165 * DCERPC dissector for connectionless calls
2168 dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2170 proto_item *ti = NULL;
2171 proto_item *tf = NULL;
2172 proto_tree *dcerpc_tree = NULL;
2173 proto_tree *dg_flags1_tree = NULL;
2174 proto_tree *dg_flags2_tree = NULL;
2175 proto_tree *drep_tree = NULL;
2176 e_dce_dg_common_hdr_t hdr;
2178 conversation_t *conv;
2181 * Check if this looks like a CL DCERPC call. All dg packets
2182 * have an 80 byte header on them. Which starts with
2183 * version (4), pkt_type.
2185 if (!tvb_bytes_exist (tvb, 0, sizeof (hdr))) {
2188 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
2189 if (hdr.rpc_ver != 4)
2191 hdr.ptype = tvb_get_guint8 (tvb, offset++);
2195 if (check_col (pinfo->cinfo, COL_PROTOCOL))
2196 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
2197 if (check_col (pinfo->cinfo, COL_INFO))
2198 col_set_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
2200 hdr.flags1 = tvb_get_guint8 (tvb, offset++);
2201 hdr.flags2 = tvb_get_guint8 (tvb, offset++);
2202 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
2203 offset += sizeof (hdr.drep);
2204 hdr.serial_hi = tvb_get_guint8 (tvb, offset++);
2205 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.obj_id);
2207 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.if_id);
2209 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.act_id);
2211 hdr.server_boot = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
2213 hdr.if_ver = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
2215 hdr.seqnum = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
2217 hdr.opnum = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
2219 hdr.ihint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
2221 hdr.ahint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
2223 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
2225 hdr.frag_num = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
2227 hdr.auth_proto = tvb_get_guint8 (tvb, offset++);
2228 hdr.serial_lo = tvb_get_guint8 (tvb, offset++);
2231 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, -1, FALSE);
2233 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
2236 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver);
2238 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype);
2240 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
2241 dg_flags1_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags1);
2242 if (dg_flags1_tree) {
2243 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
2244 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
2245 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
2246 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
2247 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
2248 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
2249 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
2250 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
2254 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
2255 dg_flags2_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags2);
2256 if (dg_flags2_tree) {
2257 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
2258 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
2259 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
2260 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
2261 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
2262 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
2263 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
2264 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
2268 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
2269 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
2271 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
2272 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
2273 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
2275 offset += sizeof (hdr.drep);
2277 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset++, 1, hdr.serial_hi);
2279 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
2281 "Object: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2282 hdr.obj_id.Data1, hdr.obj_id.Data2, hdr.obj_id.Data3,
2283 hdr.obj_id.Data4[0],
2284 hdr.obj_id.Data4[1],
2285 hdr.obj_id.Data4[2],
2286 hdr.obj_id.Data4[3],
2287 hdr.obj_id.Data4[4],
2288 hdr.obj_id.Data4[5],
2289 hdr.obj_id.Data4[6],
2290 hdr.obj_id.Data4[7]);
2293 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
2295 "Interface: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2296 hdr.if_id.Data1, hdr.if_id.Data2, hdr.if_id.Data3,
2304 hdr.if_id.Data4[7]);
2307 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
2309 "Activity: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2310 hdr.act_id.Data1, hdr.act_id.Data2, hdr.act_id.Data3,
2311 hdr.act_id.Data4[0],
2312 hdr.act_id.Data4[1],
2313 hdr.act_id.Data4[2],
2314 hdr.act_id.Data4[3],
2315 hdr.act_id.Data4[4],
2316 hdr.act_id.Data4[5],
2317 hdr.act_id.Data4[6],
2318 hdr.act_id.Data4[7]);
2321 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_server_boot, tvb, offset, 4, hdr.server_boot);
2324 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
2327 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
2330 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
2333 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
2336 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
2339 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
2342 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
2345 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
2348 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
2352 * XXX - for Kerberos, we can get a protection level; if it's
2353 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
2356 dissect_dcerpc_dg_auth (tvb, dcerpc_tree, &hdr, NULL);
2359 * keeping track of the conversation shouldn't really be necessary
2360 * for connectionless packets, because everything we need to know
2361 * to dissect is in the header for each packet. Unfortunately,
2362 * Microsoft's implementation is buggy and often puts the
2363 * completely wrong if_id in the header. go figure. So, keep
2364 * track of the seqnum and use that if possible. Note: that's not
2365 * completely correct. It should really be done based on both the
2366 * activity_id and seqnum. I haven't seen anywhere that it would
2367 * make a difference, but for future reference...
2369 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2370 pinfo->srcport, pinfo->destport, 0);
2372 conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
2373 pinfo->srcport, pinfo->destport, 0);
2377 * Packet type specific stuff is next.
2380 switch (hdr.ptype) {
2381 int length, reported_length, stub_length;
2383 dcerpc_call_value *value, v;
2387 if(!(pinfo->fd->flags.visited)){
2388 dcerpc_call_value *call_value;
2389 dcerpc_call_key *call_key;
2391 call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
2392 call_key->conv=conv;
2393 call_key->call_id=hdr.seqnum;
2394 call_key->smb_fid=get_smb_fid(pinfo->private_data);
2396 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
2397 call_value->uuid = hdr.if_id;
2398 call_value->ver = hdr.if_ver;
2399 call_value->opnum = hdr.opnum;
2400 call_value->req_frame=pinfo->fd->num;
2401 call_value->rep_frame=0;
2402 call_value->max_ptr=0;
2403 call_value->private_data = NULL;
2404 g_hash_table_insert (dcerpc_calls, call_key, call_value);
2406 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
2409 value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
2413 v.opnum = hdr.opnum;
2414 v.req_frame = pinfo->fd->num;
2417 v.private_data=NULL;
2421 length = tvb_length_remaining (tvb, offset);
2422 reported_length = tvb_reported_length_remaining (tvb, offset);
2423 stub_length = hdr.frag_len;
2424 if (length > stub_length)
2425 length = stub_length;
2426 if (reported_length > stub_length)
2427 reported_length = stub_length;
2430 di.call_id = hdr.seqnum;
2433 di.call_data = value;
2436 * XXX - authentication level?
2438 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
2439 tvb_new_subset (tvb, offset, length,
2441 0, hdr.opnum, TRUE, hdr.drep, &di, 0);
2444 if(!(pinfo->fd->flags.visited)){
2445 dcerpc_call_value *call_value;
2446 dcerpc_call_key call_key;
2449 call_key.call_id=hdr.seqnum;
2450 call_key.smb_fid=get_smb_fid(pinfo->private_data);
2452 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
2453 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
2454 if(call_value->rep_frame==0){
2455 call_value->rep_frame=pinfo->fd->num;
2460 value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
2464 v.opnum = hdr.opnum;
2466 v.rep_frame=pinfo->fd->num;
2467 v.private_data=NULL;
2471 length = tvb_length_remaining (tvb, offset);
2472 reported_length = tvb_reported_length_remaining (tvb, offset);
2473 stub_length = hdr.frag_len;
2474 if (length > stub_length)
2475 length = stub_length;
2476 if (reported_length > stub_length)
2477 reported_length = stub_length;
2483 di.call_data = value;
2486 * XXX - authentication level?
2488 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
2489 tvb_new_subset (tvb, offset, length,
2491 0, value->opnum, FALSE, hdr.drep, &di, 0);
2499 dcerpc_init_protocol (void)
2501 /* structures and data for BIND */
2503 g_hash_table_destroy (dcerpc_binds);
2505 dcerpc_binds = g_hash_table_new (dcerpc_bind_hash, dcerpc_bind_equal);
2507 if (dcerpc_bind_key_chunk){
2508 g_mem_chunk_destroy (dcerpc_bind_key_chunk);
2510 dcerpc_bind_key_chunk = g_mem_chunk_new ("dcerpc_bind_key_chunk",
2511 sizeof (dcerpc_bind_key),
2512 200 * sizeof (dcerpc_bind_key),
2514 if (dcerpc_bind_value_chunk){
2515 g_mem_chunk_destroy (dcerpc_bind_value_chunk);
2517 dcerpc_bind_value_chunk = g_mem_chunk_new ("dcerpc_bind_value_chunk",
2518 sizeof (dcerpc_bind_value),
2519 200 * sizeof (dcerpc_bind_value),
2521 /* structures and data for CALL */
2523 g_hash_table_destroy (dcerpc_calls);
2525 dcerpc_calls = g_hash_table_new (dcerpc_call_hash, dcerpc_call_equal);
2526 if (dcerpc_call_key_chunk){
2527 g_mem_chunk_destroy (dcerpc_call_key_chunk);
2529 dcerpc_call_key_chunk = g_mem_chunk_new ("dcerpc_call_key_chunk",
2530 sizeof (dcerpc_call_key),
2531 200 * sizeof (dcerpc_call_key),
2533 if (dcerpc_call_value_chunk){
2534 g_mem_chunk_destroy (dcerpc_call_value_chunk);
2536 dcerpc_call_value_chunk = g_mem_chunk_new ("dcerpc_call_value_chunk",
2537 sizeof (dcerpc_call_value),
2538 200 * sizeof (dcerpc_call_value),
2541 /* structure and data for MATCHED */
2542 if (dcerpc_matched){
2543 g_hash_table_destroy (dcerpc_matched);
2545 dcerpc_matched = g_hash_table_new (dcerpc_matched_hash, dcerpc_matched_equal);
2550 proto_register_dcerpc (void)
2552 static hf_register_info hf[] = {
2553 { &hf_dcerpc_request_in,
2554 { "Request in", "dcerpc.request_in", FT_UINT32, BASE_DEC,
2555 NULL, 0, "This packet is a response to the packet in this frame", HFILL }},
2556 { &hf_dcerpc_response_in,
2557 { "Response in", "dcerpc.response_in", FT_UINT32, BASE_DEC,
2558 NULL, 0, "The response to this packet is in this packet", HFILL }},
2559 { &hf_dcerpc_referent_id,
2560 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
2561 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
2563 { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2564 { &hf_dcerpc_ver_minor,
2565 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2566 { &hf_dcerpc_packet_type,
2567 { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_HEX, VALS (pckt_vals), 0x0, "", HFILL }},
2568 { &hf_dcerpc_cn_flags,
2569 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
2570 { &hf_dcerpc_cn_flags_first_frag,
2571 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x1, "", HFILL }},
2572 { &hf_dcerpc_cn_flags_last_frag,
2573 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x2, "", HFILL }},
2574 { &hf_dcerpc_cn_flags_cancel_pending,
2575 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x4, "", HFILL }},
2576 { &hf_dcerpc_cn_flags_reserved,
2577 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x8, "", HFILL }},
2578 { &hf_dcerpc_cn_flags_mpx,
2579 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x10, "", HFILL }},
2580 { &hf_dcerpc_cn_flags_dne,
2581 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x20, "", HFILL }},
2582 { &hf_dcerpc_cn_flags_maybe,
2583 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x40, "", HFILL }},
2584 { &hf_dcerpc_cn_flags_object,
2585 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x80, "", HFILL }},
2587 { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
2588 { &hf_dcerpc_drep_byteorder,
2589 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS (drep_byteorder_vals), 0x0, "", HFILL }},
2590 { &hf_dcerpc_drep_character,
2591 { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS (drep_character_vals), 0x0, "", HFILL }},
2592 { &hf_dcerpc_drep_fp,
2593 { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS (drep_fp_vals), 0x0, "", HFILL }},
2594 { &hf_dcerpc_cn_frag_len,
2595 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2596 { &hf_dcerpc_cn_auth_len,
2597 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2598 { &hf_dcerpc_cn_call_id,
2599 { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2600 { &hf_dcerpc_cn_max_xmit,
2601 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2602 { &hf_dcerpc_cn_max_recv,
2603 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2604 { &hf_dcerpc_cn_assoc_group,
2605 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
2606 { &hf_dcerpc_cn_num_ctx_items,
2607 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2608 { &hf_dcerpc_cn_ctx_id,
2609 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2610 { &hf_dcerpc_cn_num_trans_items,
2611 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2612 { &hf_dcerpc_cn_bind_if_id,
2613 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2614 { &hf_dcerpc_cn_bind_if_ver,
2615 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2616 { &hf_dcerpc_cn_bind_if_ver_minor,
2617 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2618 { &hf_dcerpc_cn_bind_trans_id,
2619 { "Transfer Syntax", "dcerpc.cn_bind_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2620 { &hf_dcerpc_cn_bind_trans_ver,
2621 { "Syntax ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2622 { &hf_dcerpc_cn_alloc_hint,
2623 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2624 { &hf_dcerpc_cn_sec_addr_len,
2625 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2626 { &hf_dcerpc_cn_sec_addr,
2627 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, "", HFILL }},
2628 { &hf_dcerpc_cn_num_results,
2629 { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2630 { &hf_dcerpc_cn_ack_result,
2631 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2632 { &hf_dcerpc_cn_ack_reason,
2633 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2634 { &hf_dcerpc_cn_ack_trans_id,
2635 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2636 { &hf_dcerpc_cn_ack_trans_ver,
2637 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2638 { &hf_dcerpc_cn_cancel_count,
2639 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2640 { &hf_dcerpc_auth_type,
2641 { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
2642 { &hf_dcerpc_auth_level,
2643 { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS (authn_level_vals), 0x0, "", HFILL }},
2644 { &hf_dcerpc_auth_pad_len,
2645 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2646 { &hf_dcerpc_auth_rsrvd,
2647 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
2648 { &hf_dcerpc_auth_ctx_id,
2649 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2650 { &hf_dcerpc_dg_flags1,
2651 { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
2652 { &hf_dcerpc_dg_flags1_rsrvd_01,
2653 { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x01, "", HFILL }},
2654 { &hf_dcerpc_dg_flags1_last_frag,
2655 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x02, "", HFILL }},
2656 { &hf_dcerpc_dg_flags1_frag,
2657 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x04, "", HFILL }},
2658 { &hf_dcerpc_dg_flags1_nofack,
2659 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x08, "", HFILL }},
2660 { &hf_dcerpc_dg_flags1_maybe,
2661 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x10, "", HFILL }},
2662 { &hf_dcerpc_dg_flags1_idempotent,
2663 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x20, "", HFILL }},
2664 { &hf_dcerpc_dg_flags1_broadcast,
2665 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x40, "", HFILL }},
2666 { &hf_dcerpc_dg_flags1_rsrvd_80,
2667 { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x80, "", HFILL }},
2668 { &hf_dcerpc_dg_flags2,
2669 { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
2670 { &hf_dcerpc_dg_flags2_rsrvd_01,
2671 { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x01, "", HFILL }},
2672 { &hf_dcerpc_dg_flags2_cancel_pending,
2673 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x02, "", HFILL }},
2674 { &hf_dcerpc_dg_flags2_rsrvd_04,
2675 { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x04, "", HFILL }},
2676 { &hf_dcerpc_dg_flags2_rsrvd_08,
2677 { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x08, "", HFILL }},
2678 { &hf_dcerpc_dg_flags2_rsrvd_10,
2679 { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x10, "", HFILL }},
2680 { &hf_dcerpc_dg_flags2_rsrvd_20,
2681 { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x20, "", HFILL }},
2682 { &hf_dcerpc_dg_flags2_rsrvd_40,
2683 { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x40, "", HFILL }},
2684 { &hf_dcerpc_dg_flags2_rsrvd_80,
2685 { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x80, "", HFILL }},
2686 { &hf_dcerpc_dg_serial_lo,
2687 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
2688 { &hf_dcerpc_dg_serial_hi,
2689 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
2690 { &hf_dcerpc_dg_ahint,
2691 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
2692 { &hf_dcerpc_dg_ihint,
2693 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
2694 { &hf_dcerpc_dg_frag_len,
2695 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2696 { &hf_dcerpc_dg_frag_num,
2697 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2698 { &hf_dcerpc_dg_auth_proto,
2699 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
2700 { &hf_dcerpc_dg_seqnum,
2701 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
2702 { &hf_dcerpc_dg_server_boot,
2703 { "Server boot time", "dcerpc.dg_server_boot", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
2704 { &hf_dcerpc_dg_if_ver,
2705 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
2706 { &hf_dcerpc_obj_id,
2707 { "Object", "dcerpc.obj_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2708 { &hf_dcerpc_dg_if_id,
2709 { "Interface", "dcerpc.dg_if_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2710 { &hf_dcerpc_dg_act_id,
2711 { "Activitiy", "dcerpc.dg_act_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2713 { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2714 { &hf_dcerpc_array_max_count,
2715 { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
2717 { &hf_dcerpc_array_offset,
2718 { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
2720 { &hf_dcerpc_array_actual_count,
2721 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
2724 { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
2726 { &hf_dcerpc_fragments,
2727 { "DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
2728 NULL, 0x0, "DCE/RPC Fragments", HFILL }},
2730 { &hf_dcerpc_fragment,
2731 { "DCE/RPC Fragment", "dcerpc.fragment", FT_NONE, BASE_NONE,
2732 NULL, 0x0, "DCE/RPC Fragment", HFILL }},
2734 { &hf_dcerpc_fragment_overlap,
2735 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
2737 { &hf_dcerpc_fragment_overlap_conflict,
2738 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
2740 { &hf_dcerpc_fragment_multiple_tails,
2741 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
2743 { &hf_dcerpc_fragment_too_long_fragment,
2744 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
2746 { &hf_dcerpc_fragment_error,
2747 { "Defragmentation error", "dcerpc.fragment.error", FT_NONE, BASE_NONE, NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
2750 static gint *ett[] = {
2752 &ett_dcerpc_cn_flags,
2754 &ett_dcerpc_dg_flags1,
2755 &ett_dcerpc_dg_flags2,
2756 &ett_dcerpc_pointer_data,
2757 &ett_dcerpc_fragments,
2758 &ett_dcerpc_fragment,
2760 module_t *dcerpc_module;
2762 proto_dcerpc = proto_register_protocol ("DCE RPC", "DCERPC", "dcerpc");
2763 proto_register_field_array (proto_dcerpc, hf, array_length (hf));
2764 proto_register_subtree_array (ett, array_length (ett));
2765 register_init_routine (dcerpc_init_protocol);
2766 dcerpc_module = prefs_register_protocol (proto_dcerpc, NULL);
2767 prefs_register_bool_preference (dcerpc_module,
2769 "Desegment all DCE/RPC over TCP",
2770 "Whether the DCE/RPC dissector should desegment all DCE/RPC over TCP",
2771 &dcerpc_cn_desegment);
2772 prefs_register_bool_preference (dcerpc_module,
2773 "reassemble_dcerpc",
2774 "Reassemble DCE/RPC fragments",
2775 "Whether the DCE/RPC dissector should reassemble all fragmented PDUs",
2776 &dcerpc_reassemble);
2777 register_init_routine(dcerpc_reassemble_init);
2778 dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
2782 proto_reg_handoff_dcerpc (void)
2784 heur_dissector_add ("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
2785 heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
2786 heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
2787 heur_dissector_add ("smb_transact", dissect_dcerpc_cn_bs, proto_dcerpc);