The PDU length is 3 bytes long in SLPv2.
[obnox/wireshark/wip.git] / packet-dcerpc.c
1 /* packet-dcerpc.c
2  * Routines for DCERPC packet disassembly
3  * Copyright 2001, Todd Sabin <tas@webspan.net>
4  * Copyright 2003, Tim Potter <tpot@samba.org>
5  *
6  * $Id: packet-dcerpc.c,v 1.142 2003/09/26 06:30:13 tpot Exp $
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@ethereal.com>
10  * Copyright 1998 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include <string.h>
32 #include <ctype.h>
33
34 #include <glib.h>
35 #include <epan/packet.h>
36 #include "packet-dcerpc.h"
37 #include <epan/conversation.h>
38 #include "prefs.h"
39 #include "reassemble.h"
40 #include "tap.h"
41 #include "packet-frame.h"
42 #include "packet-dcerpc-nt.h"
43
44 static int dcerpc_tap = -1;
45
46
47 static const value_string pckt_vals[] = {
48     { PDU_REQ,        "Request"},
49     { PDU_PING,       "Ping"},
50     { PDU_RESP,       "Response"},
51     { PDU_FAULT,      "Fault"},
52     { PDU_WORKING,    "Working"},
53     { PDU_NOCALL,     "Nocall"},
54     { PDU_REJECT,     "Reject"},
55     { PDU_ACK,        "Ack"},
56     { PDU_CL_CANCEL,  "Cl_cancel"},
57     { PDU_FACK,       "Fack"},
58     { PDU_CANCEL_ACK, "Cancel_ack"},
59     { PDU_BIND,       "Bind"},
60     { PDU_BIND_ACK,   "Bind_ack"},
61     { PDU_BIND_NAK,   "Bind_nak"},
62     { PDU_ALTER,      "Alter_context"},
63     { PDU_ALTER_ACK,  "Alter_context_resp"},
64     { PDU_AUTH3,      "AUTH3"},
65     { PDU_SHUTDOWN,   "Shutdown"},
66     { PDU_CO_CANCEL,  "Co_cancel"},
67     { PDU_ORPHANED,   "Orphaned"},
68     { 0,              NULL }
69 };
70
71 static const value_string drep_byteorder_vals[] = {
72     { 0, "Big-endian" },
73     { 1, "Little-endian" },
74     { 0,  NULL }
75 };
76
77 static const value_string drep_character_vals[] = {
78     { 0, "ASCII" },
79     { 1, "EBCDIC" },
80     { 0,  NULL }
81 };
82
83 #define DCE_RPC_DREP_FP_IEEE 0
84 #define DCE_RPC_DREP_FP_VAX  1
85 #define DCE_RPC_DREP_FP_CRAY 2
86 #define DCE_RPC_DREP_FP_IBM  3
87
88 static const value_string drep_fp_vals[] = {
89     { DCE_RPC_DREP_FP_IEEE, "IEEE" },
90     { DCE_RPC_DREP_FP_VAX,  "VAX"  },
91     { DCE_RPC_DREP_FP_CRAY, "Cray" },
92     { DCE_RPC_DREP_FP_IBM,  "IBM"  },
93     { 0,  NULL }
94 };
95
96 /*
97  * Authentication services.
98  */
99 static const value_string authn_protocol_vals[] = {
100         { DCE_C_RPC_AUTHN_PROTOCOL_NONE,    "None" },
101         { DCE_C_RPC_AUTHN_PROTOCOL_KRB5,    "Kerberos 5" },
102         { DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO,  "SPNEGO" },
103         { DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP, "NTLMSSP" },
104         { DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN,"NETLOGON Secure Channel" },
105         { 0, NULL }
106 };
107
108 /*
109  * Protection levels.
110  */
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" },
118         { 0,                               NULL }
119 };
120
121 /*
122  * Flag bits in first flag field in connectionless PDU header.
123  */
124 #define PFCL1_RESERVED_01       0x01    /* Reserved for use by implementations */
125 #define PFCL1_LASTFRAG          0x02    /* If set, the PDU is the last
126                                          * fragment of a multi-PDU
127                                          * transmission */
128 #define PFCL1_FRAG              0x04    /* If set, the PDU is a fragment of
129                                            a multi-PDU transmission */
130 #define PFCL1_NOFACK            0x08    /* If set, the receiver is not
131                                          * requested to send a `fack' PDU
132                                          * for the fragment */
133 #define PFCL1_MAYBE             0x10    /* If set, the PDU is for a `maybe'
134                                          * request */
135 #define PFCL1_IDEMPOTENT        0x20    /* If set, the PDU is for an idempotent
136                                          * request */
137 #define PFCL1_BROADCAST         0x40    /* If set, the PDU is for a broadcast
138                                          * request */
139 #define PFCL1_RESERVED_80       0x80    /* Reserved for use by implementations */
140
141 /*
142  * Flag bits in second flag field in connectionless PDU header.
143  */
144 #define PFCL2_RESERVED_01       0x01    /* Reserved for use by implementations */
145 #define PFCL2_CANCEL_PENDING    0x02    /* Cancel pending at the call end */
146 #define PFCL2_RESERVED_04       0x04    /* Reserved for future use */
147 #define PFCL2_RESERVED_08       0x08    /* Reserved for future use */
148 #define PFCL2_RESERVED_10       0x10    /* Reserved for future use */
149 #define PFCL2_RESERVED_20       0x20    /* Reserved for future use */
150 #define PFCL2_RESERVED_40       0x40    /* Reserved for future use */
151 #define PFCL2_RESERVED_80       0x80    /* Reserved for future use */
152
153 /*
154  * Flag bits in connection-oriented PDU header.
155  */
156 #define PFC_FIRST_FRAG          0x01    /* First fragment */
157 #define PFC_LAST_FRAG           0x02    /* Last fragment */
158 #define PFC_PENDING_CANCEL      0x04    /* Cancel was pending at sender */
159 #define PFC_RESERVED_1          0x08
160 #define PFC_CONC_MPX            0x10    /* suports concurrent multiplexing
161                                          * of a single connection. */
162 #define PFC_DID_NOT_EXECUTE     0x20    /* only meaningful on `fault' packet;
163                                          * if true, guaranteed call did not
164                                          * execute. */
165 #define PFC_MAYBE               0x40    /* `maybe' call semantics requested */
166 #define PFC_OBJECT_UUID         0x80    /* if true, a non-nil object UUID
167                                          * was specified in the handle, and
168                                          * is present in the optional object
169                                          * field. If false, the object field
170                                          * is omitted. */
171
172 /*
173  * Tests whether a connection-oriented PDU is fragmented; returns TRUE if
174  * it's not fragmented (i.e., this is both the first *and* last fragment),
175  * and FALSE otherwise.
176  */
177 #define PFC_NOT_FRAGMENTED(hdr) \
178   ((hdr->flags&(PFC_FIRST_FRAG|PFC_LAST_FRAG))==(PFC_FIRST_FRAG|PFC_LAST_FRAG))
179
180 /*
181  * Presentation context negotiation result.
182  */
183 static const value_string p_cont_result_vals[] = {
184         { 0, "Acceptance" },
185         { 1, "User rejection" },
186         { 2, "Provider rejection" },
187         { 0, NULL }
188 };
189
190 /*
191  * Presentation context negotiation rejection reasons.
192  */
193 static const value_string p_provider_reason_vals[] = {
194         { 0, "Reason not specified" },
195         { 1, "Abstract syntax not supported" },
196         { 2, "Proposed transfer syntaxes not supported" },
197         { 3, "Local limit exceeded" },
198         { 0, NULL }
199 };
200
201 /*
202  * Reject reasons.
203  */
204 #define REASON_NOT_SPECIFIED            0
205 #define TEMPORARY_CONGESTION            1
206 #define LOCAL_LIMIT_EXCEEDED            2
207 #define CALLED_PADDR_UNKNOWN            3 /* not used */
208 #define PROTOCOL_VERSION_NOT_SUPPORTED  4
209 #define DEFAULT_CONTEXT_NOT_SUPPORTED   5 /* not used */
210 #define USER_DATA_NOT_READABLE          6 /* not used */
211 #define NO_PSAP_AVAILABLE               7 /* not used */
212
213 static const value_string reject_reason_vals[] = {
214         { REASON_NOT_SPECIFIED,           "Reason not specified" },
215         { TEMPORARY_CONGESTION,           "Temporary congestion" },
216         { LOCAL_LIMIT_EXCEEDED,           "Local limit exceeded" },
217         { CALLED_PADDR_UNKNOWN,           "Called paddr unknown" },
218         { PROTOCOL_VERSION_NOT_SUPPORTED, "Protocol version not supported" },
219         { DEFAULT_CONTEXT_NOT_SUPPORTED,  "Default context not supported" },
220         { USER_DATA_NOT_READABLE,         "User data not readable" },
221         { NO_PSAP_AVAILABLE,              "No PSAP available" },
222         { 0,                              NULL }
223 };
224
225 /*
226  * Reject status codes.
227  */
228 static const value_string reject_status_vals[] = {
229         { 0,          "Stub-defined exception" },
230         { 0x1c000001, "nca_s_fault_int_div_by_zero" },
231         { 0x1c000002, "nca_s_fault_addr_error" },
232         { 0x1c000003, "nca_s_fault_fp_div_zero" },
233         { 0x1c000004, "nca_s_fault_fp_underflow" },
234         { 0x1c000005, "nca_s_fault_fp_overflow" },
235         { 0x1c000006, "nca_s_fault_invalid_tag" },
236         { 0x1c000007, "nca_s_fault_invalid_bound" },
237         { 0x1c000008, "nca_rpc_version_mismatch" },
238         { 0x1c000009, "nca_unspec_reject" },
239         { 0x1c00000a, "nca_s_bad_actid" },
240         { 0x1c00000b, "nca_who_are_you_failed" },
241         { 0x1c00000c, "nca_manager_not_entered" },
242         { 0x1c00000d, "nca_s_fault_cancel" },
243         { 0x1c00000e, "nca_s_fault_ill_inst" },
244         { 0x1c00000f, "nca_s_fault_fp_error" },
245         { 0x1c000010, "nca_s_fault_int_overflow" },
246         { 0x1c000014, "nca_s_fault_pipe_empty" },
247         { 0x1c000015, "nca_s_fault_pipe_closed" },
248         { 0x1c000016, "nca_s_fault_pipe_order" },
249         { 0x1c000017, "nca_s_fault_pipe_discipline" },
250         { 0x1c000018, "nca_s_fault_pipe_comm_error" },
251         { 0x1c000019, "nca_s_fault_pipe_memory" },
252         { 0x1c00001a, "nca_s_fault_context_mismatch" },
253         { 0x1c00001b, "nca_s_fault_remote_no_memory" },
254         { 0x1c00001c, "nca_invalid_pres_context_id" },
255         { 0x1c00001d, "nca_unsupported_authn_level" },
256         { 0x1c00001f, "nca_invalid_checksum" },
257         { 0x1c000020, "nca_invalid_crc" },
258         { 0x1c000021, "ncs_s_fault_user_defined" },
259         { 0x1c000022, "nca_s_fault_tx_open_failed" },
260         { 0x1c000023, "nca_s_fault_codeset_conv_error" },
261         { 0x1c000024, "nca_s_fault_object_not_found" },
262         { 0x1c000025, "nca_s_fault_no_client_stub" },
263         { 0x1c010002, "nca_op_rng_error" },
264         { 0x1c010003, "nca_unk_if"},
265         { 0x1c010006, "nca_wrong_boot_time" },
266         { 0x1c010009, "nca_s_you_crashed" },
267         { 0x1c01000b, "nca_proto_error" },
268         { 0x1c010013, "nca_out_args_too_big" },
269         { 0x1c010014, "nca_server_too_busy" },
270         { 0x1c010017, "nca_unsupported_type" },
271         { 0,          NULL }
272 };
273
274 static int proto_dcerpc = -1;
275
276 /* field defines */
277 static int hf_dcerpc_request_in = -1;
278 static int hf_dcerpc_time = -1;
279 static int hf_dcerpc_response_in = -1;
280 static int hf_dcerpc_ver = -1;
281 static int hf_dcerpc_ver_minor = -1;
282 static int hf_dcerpc_packet_type = -1;
283 static int hf_dcerpc_cn_flags = -1;
284 static int hf_dcerpc_cn_flags_first_frag = -1;
285 static int hf_dcerpc_cn_flags_last_frag = -1;
286 static int hf_dcerpc_cn_flags_cancel_pending = -1;
287 static int hf_dcerpc_cn_flags_reserved = -1;
288 static int hf_dcerpc_cn_flags_mpx = -1;
289 static int hf_dcerpc_cn_flags_dne = -1;
290 static int hf_dcerpc_cn_flags_maybe = -1;
291 static int hf_dcerpc_cn_flags_object = -1;
292 static int hf_dcerpc_drep = -1;
293 static int hf_dcerpc_drep_byteorder = -1;
294 static int hf_dcerpc_drep_character = -1;
295 static int hf_dcerpc_drep_fp = -1;
296 static int hf_dcerpc_cn_frag_len = -1;
297 static int hf_dcerpc_cn_auth_len = -1;
298 static int hf_dcerpc_cn_call_id = -1;
299 static int hf_dcerpc_cn_max_xmit = -1;
300 static int hf_dcerpc_cn_max_recv = -1;
301 static int hf_dcerpc_cn_assoc_group = -1;
302 static int hf_dcerpc_cn_num_ctx_items = -1;
303 static int hf_dcerpc_cn_ctx_id = -1;
304 static int hf_dcerpc_cn_num_trans_items = -1;
305 static int hf_dcerpc_cn_bind_if_id = -1;
306 static int hf_dcerpc_cn_bind_if_ver = -1;
307 static int hf_dcerpc_cn_bind_if_ver_minor = -1;
308 static int hf_dcerpc_cn_bind_trans_id = -1;
309 static int hf_dcerpc_cn_bind_trans_ver = -1;
310 static int hf_dcerpc_cn_alloc_hint = -1;
311 static int hf_dcerpc_cn_sec_addr_len = -1;
312 static int hf_dcerpc_cn_sec_addr = -1;
313 static int hf_dcerpc_cn_num_results = -1;
314 static int hf_dcerpc_cn_ack_result = -1;
315 static int hf_dcerpc_cn_ack_reason = -1;
316 static int hf_dcerpc_cn_ack_trans_id = -1;
317 static int hf_dcerpc_cn_ack_trans_ver = -1;
318 static int hf_dcerpc_cn_reject_reason = -1;
319 static int hf_dcerpc_cn_num_protocols = -1;
320 static int hf_dcerpc_cn_protocol_ver_major = -1;
321 static int hf_dcerpc_cn_protocol_ver_minor = -1;
322 static int hf_dcerpc_cn_cancel_count = -1;
323 static int hf_dcerpc_cn_status = -1;
324 static int hf_dcerpc_auth_type = -1;
325 static int hf_dcerpc_auth_level = -1;
326 static int hf_dcerpc_auth_pad_len = -1;
327 static int hf_dcerpc_auth_rsrvd = -1;
328 static int hf_dcerpc_auth_ctx_id = -1;
329 static int hf_dcerpc_dg_flags1 = -1;
330 static int hf_dcerpc_dg_flags1_rsrvd_01 = -1;
331 static int hf_dcerpc_dg_flags1_last_frag = -1;
332 static int hf_dcerpc_dg_flags1_frag = -1;
333 static int hf_dcerpc_dg_flags1_nofack = -1;
334 static int hf_dcerpc_dg_flags1_maybe = -1;
335 static int hf_dcerpc_dg_flags1_idempotent = -1;
336 static int hf_dcerpc_dg_flags1_broadcast = -1;
337 static int hf_dcerpc_dg_flags1_rsrvd_80 = -1;
338 static int hf_dcerpc_dg_flags2 = -1;
339 static int hf_dcerpc_dg_flags2_rsrvd_01 = -1;
340 static int hf_dcerpc_dg_flags2_cancel_pending = -1;
341 static int hf_dcerpc_dg_flags2_rsrvd_04 = -1;
342 static int hf_dcerpc_dg_flags2_rsrvd_08 = -1;
343 static int hf_dcerpc_dg_flags2_rsrvd_10 = -1;
344 static int hf_dcerpc_dg_flags2_rsrvd_20 = -1;
345 static int hf_dcerpc_dg_flags2_rsrvd_40 = -1;
346 static int hf_dcerpc_dg_flags2_rsrvd_80 = -1;
347 static int hf_dcerpc_dg_serial_hi = -1;
348 static int hf_dcerpc_obj_id = -1;
349 static int hf_dcerpc_dg_if_id = -1;
350 static int hf_dcerpc_dg_act_id = -1;
351 static int hf_dcerpc_dg_serial_lo = -1;
352 static int hf_dcerpc_dg_ahint = -1;
353 static int hf_dcerpc_dg_ihint = -1;
354 static int hf_dcerpc_dg_frag_len = -1;
355 static int hf_dcerpc_dg_frag_num = -1;
356 static int hf_dcerpc_dg_auth_proto = -1;
357 static int hf_dcerpc_opnum = -1;
358 static int hf_dcerpc_dg_seqnum = -1;
359 static int hf_dcerpc_dg_server_boot = -1;
360 static int hf_dcerpc_dg_if_ver = -1;
361 static int hf_dcerpc_krb5_av_prot_level = -1;
362 static int hf_dcerpc_krb5_av_key_vers_num = -1;
363 static int hf_dcerpc_krb5_av_key_auth_verifier = -1;
364 static int hf_dcerpc_dg_cancel_vers = -1;
365 static int hf_dcerpc_dg_cancel_id = -1;
366 static int hf_dcerpc_dg_server_accepting_cancels = -1;
367 static int hf_dcerpc_dg_fack_vers = -1;
368 static int hf_dcerpc_dg_fack_window_size = -1;
369 static int hf_dcerpc_dg_fack_max_tsdu = -1;
370 static int hf_dcerpc_dg_fack_max_frag_size = -1;
371 static int hf_dcerpc_dg_fack_serial_num = -1;
372 static int hf_dcerpc_dg_fack_selack_len = -1;
373 static int hf_dcerpc_dg_fack_selack = -1;
374 static int hf_dcerpc_dg_status = -1;
375 static int hf_dcerpc_array_max_count = -1;
376 static int hf_dcerpc_array_offset = -1;
377 static int hf_dcerpc_array_actual_count = -1;
378 static int hf_dcerpc_array_buffer = -1;
379 static int hf_dcerpc_op = -1;
380 static int hf_dcerpc_referent_id = -1;
381 static int hf_dcerpc_fragments = -1;
382 static int hf_dcerpc_fragment = -1;
383 static int hf_dcerpc_fragment_overlap = -1;
384 static int hf_dcerpc_fragment_overlap_conflict = -1;
385 static int hf_dcerpc_fragment_multiple_tails = -1;
386 static int hf_dcerpc_fragment_too_long_fragment = -1;
387 static int hf_dcerpc_fragment_error = -1;
388 static int hf_dcerpc_reassembled_in = -1;
389
390 static gint ett_dcerpc = -1;
391 static gint ett_dcerpc_cn_flags = -1;
392 static gint ett_dcerpc_cn_ctx = -1;
393 static gint ett_dcerpc_cn_iface = -1;
394 static gint ett_dcerpc_drep = -1;
395 static gint ett_dcerpc_dg_flags1 = -1;
396 static gint ett_dcerpc_dg_flags2 = -1;
397 static gint ett_dcerpc_pointer_data = -1;
398 static gint ett_dcerpc_string = -1;
399 static gint ett_dcerpc_fragments = -1;
400 static gint ett_dcerpc_fragment = -1;
401 static gint ett_dcerpc_krb5_auth_verf = -1;
402
403 static const fragment_items dcerpc_frag_items = {
404         &ett_dcerpc_fragments,
405         &ett_dcerpc_fragment,
406
407         &hf_dcerpc_fragments,
408         &hf_dcerpc_fragment,
409         &hf_dcerpc_fragment_overlap,
410         &hf_dcerpc_fragment_overlap_conflict,
411         &hf_dcerpc_fragment_multiple_tails,
412         &hf_dcerpc_fragment_too_long_fragment,
413         &hf_dcerpc_fragment_error,
414         NULL,
415
416         "fragments"
417 };
418
419
420
421 static dcerpc_info *
422 get_next_di(void)
423 {
424         static dcerpc_info di[20];
425         static int di_counter=0;
426
427         di_counter++;
428         if(di_counter>=20){
429                 di_counter=0;
430         }
431         return &di[di_counter];
432 }
433
434 /* try to desegment big DCE/RPC packets over TCP? */
435 static gboolean dcerpc_cn_desegment = TRUE;
436
437 /* reassemble DCE/RPC fragments */
438 /* reassembly of dcerpc fragments will not work for the case where ONE frame
439    might contain multiple dcerpc fragments for different PDUs.
440    this case would be so unusual/weird so if you got captures like that:
441         too bad
442 */
443 static gboolean dcerpc_reassemble = FALSE;
444 static GHashTable *dcerpc_co_reassemble_table = NULL;
445 static GHashTable *dcerpc_cl_reassemble_table = NULL;
446
447 static void
448 dcerpc_reassemble_init(void)
449 {
450   fragment_table_init(&dcerpc_co_reassemble_table);
451   fragment_table_init(&dcerpc_cl_reassemble_table);
452 }
453
454 /*
455  * Authentication subdissectors.  Used to dissect authentication blobs in
456  * DCERPC binds, requests and responses.
457  */
458
459 typedef struct _dcerpc_auth_subdissector {
460         guint8 auth_level;
461         guint8 auth_type;
462         dcerpc_auth_subdissector_fns auth_fns;
463 } dcerpc_auth_subdissector;
464
465 static GSList *dcerpc_auth_subdissector_list;
466
467 static dcerpc_auth_subdissector_fns *get_auth_subdissector_fns(
468         guint8 auth_level, guint8 auth_type)
469 {
470         gpointer data;
471         int i;
472
473         for (i = 0; (data = g_slist_nth_data(dcerpc_auth_subdissector_list, i)); i++) {
474                 dcerpc_auth_subdissector *asd = (dcerpc_auth_subdissector *)data;
475
476                 if (asd->auth_level == auth_level && 
477                     asd->auth_type == auth_type)
478                         return &asd->auth_fns;
479         }
480
481         return NULL;
482 }
483
484 void register_dcerpc_auth_subdissector(guint8 auth_level, guint8 auth_type,
485                                        dcerpc_auth_subdissector_fns *fns)
486 {
487         dcerpc_auth_subdissector *d;
488
489         if (get_auth_subdissector_fns(auth_level, auth_type))
490                 return;
491
492         d = (dcerpc_auth_subdissector *)g_malloc(sizeof(dcerpc_auth_subdissector));
493
494         d->auth_level = auth_level;
495         d->auth_type = auth_type;
496         memcpy(&d->auth_fns, fns, sizeof(dcerpc_auth_subdissector_fns));
497
498         dcerpc_auth_subdissector_list = g_slist_append(dcerpc_auth_subdissector_list, d);
499 }
500
501 /* Hand off verifier data to a registered dissector */
502
503 static void dissect_auth_verf(tvbuff_t *auth_tvb, packet_info *pinfo,
504                               proto_tree *tree, 
505                               dcerpc_auth_subdissector_fns *auth_fns,
506                               e_dce_cn_common_hdr_t *hdr, 
507                               dcerpc_auth_info *auth_info)
508 {
509         dcerpc_dissect_fnct_t *fn = NULL;
510
511         switch (hdr->ptype) {
512         case PDU_BIND:
513         case PDU_ALTER:
514                 fn = auth_fns->bind_fn;
515                 break;
516         case PDU_BIND_ACK:
517         case PDU_ALTER_ACK:
518                 fn = auth_fns->bind_ack_fn;
519                 break;
520         case PDU_AUTH3:
521                 fn = auth_fns->auth3_fn;
522                 break;
523         case PDU_REQ:
524                 fn = auth_fns->req_verf_fn;
525                 break;
526         case PDU_RESP:
527                 fn = auth_fns->resp_verf_fn;
528                 break;
529
530                 /* Don't know how to handle authentication data in this 
531                    pdu type. */
532
533         default:
534                 g_warning("attempt to dissect %s pdu authentication data",
535                           val_to_str(hdr->ptype, pckt_vals, "Unknown (%u)"));
536                 break;
537         }
538
539         if (fn)
540                 fn(auth_tvb, 0, pinfo, tree, hdr->drep);
541         else
542                 proto_tree_add_text(tree, auth_tvb, 0, hdr->auth_len,
543                                     "%s Verifier", 
544                                     val_to_str(auth_info->auth_type, 
545                                                authn_protocol_vals,
546                                                "Unknown (%u)"));
547 }
548
549 /* Hand off payload data to a registered dissector */
550
551 static tvbuff_t *decode_encrypted_data(tvbuff_t *enc_tvb, 
552                                        packet_info *pinfo,
553                                        dcerpc_auth_subdissector_fns *auth_fns,
554                                        gboolean is_request, 
555                                        dcerpc_auth_info *auth_info)
556 {
557         dcerpc_decode_data_fnct_t *fn;
558
559         if (is_request)
560                 fn = auth_fns->req_data_fn;
561         else
562                 fn = auth_fns->resp_data_fn;
563
564         if (fn)
565                 return fn(enc_tvb, 0, pinfo, auth_info);
566
567         return NULL;
568 }
569
570 /*
571  * Subdissectors
572  */
573
574 /* the registered subdissectors */
575 GHashTable *dcerpc_uuids=NULL;
576
577 static gint
578 dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2)
579 {
580     const dcerpc_uuid_key *key1 = (const dcerpc_uuid_key *)k1;
581     const dcerpc_uuid_key *key2 = (const dcerpc_uuid_key *)k2;
582     return ((memcmp (&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
583             && (key1->ver == key2->ver));
584 }
585
586 static guint
587 dcerpc_uuid_hash (gconstpointer k)
588 {
589     const dcerpc_uuid_key *key = (const dcerpc_uuid_key *)k;
590     /* This isn't perfect, but the Data1 part of these is almost always
591        unique. */
592     return key->uuid.Data1;
593 }
594
595 void
596 dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver,
597                   dcerpc_sub_dissector *procs, int opnum_hf)
598 {
599     dcerpc_uuid_key *key = g_malloc (sizeof (*key));
600     dcerpc_uuid_value *value = g_malloc (sizeof (*value));
601     header_field_info *hf_info;
602
603     key->uuid = *uuid;
604     key->ver = ver;
605
606     value->proto = proto;
607     value->ett = ett;
608     value->name = proto_get_protocol_short_name (proto);
609     value->procs = procs;
610     value->opnum_hf = opnum_hf;
611
612     g_hash_table_insert (dcerpc_uuids, key, value);
613
614     hf_info = proto_registrar_get_nth(opnum_hf);
615     hf_info->strings = value_string_from_subdissectors(procs);
616 }
617
618 /* Function to find the name of a registered protocol
619  * or NULL if the protocol/version is not known to ethereal.
620  */
621 char *
622 dcerpc_get_proto_name(e_uuid_t *uuid, guint16 ver)
623 {
624     dcerpc_uuid_key key;
625     dcerpc_uuid_value *sub_proto;
626
627     key.uuid = *uuid;
628     key.ver = ver;
629     if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
630         return NULL;
631     }
632     return sub_proto->name;
633 }
634
635 /* Create a value_string consisting of DCERPC opnum and name from a
636    subdissector array. */
637
638 value_string *value_string_from_subdissectors(dcerpc_sub_dissector *sd)
639 {
640         value_string *vs = NULL;
641         int i, num_sd = 0;
642
643  again:
644         for (i = 0; sd[i].name; i++) {
645                 if (vs) {
646                         vs[i].value = sd[i].num;
647                         vs[i].strptr = sd[i].name;
648                 } else
649                         num_sd++;
650         }
651
652         if (!vs) {
653                 vs = g_malloc((num_sd + 1) * sizeof(value_string));
654                 goto again;
655         }
656
657         vs[num_sd].value = 0;
658         vs[num_sd].strptr = NULL;
659
660         return vs;
661 }
662
663 /* Function to find the subdissector table of a registered protocol
664  * or NULL if the protocol/version is not known to ethereal.
665  */
666 dcerpc_sub_dissector *
667 dcerpc_get_proto_sub_dissector(e_uuid_t *uuid, guint16 ver)
668 {
669     dcerpc_uuid_key key;
670     dcerpc_uuid_value *sub_proto;
671
672     key.uuid = *uuid;
673     key.ver = ver;
674     if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
675         return NULL;
676     }
677     return sub_proto->procs;
678 }
679
680
681 /*
682  * To keep track of ctx_id mappings.
683  *
684  * Everytime we see a bind call we update this table.
685  * Note that we always specify a SMB FID. For non-SMB transports this
686  * value is 0.
687  */
688 static GHashTable *dcerpc_binds=NULL;
689
690 typedef struct _dcerpc_bind_key {
691     conversation_t *conv;
692     guint16 ctx_id;
693     guint16 smb_fid;
694 } dcerpc_bind_key;
695
696 typedef struct _dcerpc_bind_value {
697         e_uuid_t uuid;
698         guint16 ver;
699 } dcerpc_bind_value;
700
701 static GMemChunk *dcerpc_bind_key_chunk=NULL;
702 static GMemChunk *dcerpc_bind_value_chunk=NULL;
703
704 static gint
705 dcerpc_bind_equal (gconstpointer k1, gconstpointer k2)
706 {
707     const dcerpc_bind_key *key1 = (const dcerpc_bind_key *)k1;
708     const dcerpc_bind_key *key2 = (const dcerpc_bind_key *)k2;
709     return (key1->conv == key2->conv
710             && key1->ctx_id == key2->ctx_id
711             && key1->smb_fid == key2->smb_fid);
712 }
713
714 static guint
715 dcerpc_bind_hash (gconstpointer k)
716 {
717     const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
718     return GPOINTER_TO_UINT(key->conv) + key->ctx_id + key->smb_fid;
719
720 }
721
722 /*
723  * To keep track of callid mappings.  Should really use some generic
724  * conversation support instead.
725  */
726 static GHashTable *dcerpc_calls=NULL;
727
728 typedef struct _dcerpc_call_key {
729     conversation_t *conv;
730     guint32 call_id;
731     guint16 smb_fid;
732 } dcerpc_call_key;
733
734 static GMemChunk *dcerpc_call_key_chunk=NULL;
735
736 static GMemChunk *dcerpc_call_value_chunk=NULL;
737
738 static gint
739 dcerpc_call_equal (gconstpointer k1, gconstpointer k2)
740 {
741     const dcerpc_call_key *key1 = (const dcerpc_call_key *)k1;
742     const dcerpc_call_key *key2 = (const dcerpc_call_key *)k2;
743     return (key1->conv == key2->conv
744             && key1->call_id == key2->call_id
745             && key1->smb_fid == key2->smb_fid);
746 }
747
748 static guint
749 dcerpc_call_hash (gconstpointer k)
750 {
751     const dcerpc_call_key *key = (const dcerpc_call_key *)k;
752     return ((guint32)key->conv) + key->call_id + key->smb_fid;
753 }
754
755
756 /* to keep track of matched calls/responses
757    this one uses the same value struct as calls, but the key is the frame id
758    and call id; there can be more than one call in a frame.
759
760    XXX - why not just use the same keys as are used for calls?
761 */
762
763 static GHashTable *dcerpc_matched=NULL;
764
765 typedef struct _dcerpc_matched_key {
766     guint32 frame;
767     guint32 call_id;
768 } dcerpc_matched_key;
769
770 static GMemChunk *dcerpc_matched_key_chunk=NULL;
771
772 static gint
773 dcerpc_matched_equal (gconstpointer k1, gconstpointer k2)
774 {
775     const dcerpc_matched_key *key1 = (const dcerpc_matched_key *)k1;
776     const dcerpc_matched_key *key2 = (const dcerpc_matched_key *)k2;
777     return (key1->frame == key2->frame
778             && key1->call_id == key2->call_id);
779 }
780
781 static guint
782 dcerpc_matched_hash (gconstpointer k)
783 {
784     const dcerpc_matched_key *key = (const dcerpc_matched_key *)k;
785     return key->frame;
786 }
787
788
789
790 /*
791  * Utility functions.  Modeled after packet-rpc.c
792  */
793
794 int
795 dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
796                       proto_tree *tree, char *drep,
797                       int hfindex, guint8 *pdata)
798 {
799     guint8 data;
800
801     data = tvb_get_guint8 (tvb, offset);
802     if (tree) {
803         proto_tree_add_item (tree, hfindex, tvb, offset, 1, (drep[0] & 0x10));
804     }
805     if (pdata)
806         *pdata = data;
807     return offset + 1;
808 }
809
810 int
811 dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
812                        proto_tree *tree, char *drep,
813                        int hfindex, guint16 *pdata)
814 {
815     guint16 data;
816
817     data = ((drep[0] & 0x10)
818             ? tvb_get_letohs (tvb, offset)
819             : tvb_get_ntohs (tvb, offset));
820
821     if (tree) {
822         proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10));
823     }
824     if (pdata)
825         *pdata = data;
826     return offset + 2;
827 }
828
829 int
830 dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
831                        proto_tree *tree, char *drep,
832                        int hfindex, guint32 *pdata)
833 {
834     guint32 data;
835
836     data = ((drep[0] & 0x10)
837             ? tvb_get_letohl (tvb, offset)
838             : tvb_get_ntohl (tvb, offset));
839
840     if (tree) {
841         proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10));
842     }
843     if (pdata)
844         *pdata = data;
845     return offset+4;
846 }
847
848 /* handles 32 bit unix time_t */
849 int
850 dissect_dcerpc_time_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
851                        proto_tree *tree, char *drep,
852                        int hfindex, guint32 *pdata)
853 {
854     guint32 data;
855     nstime_t tv;
856
857     data = ((drep[0] & 0x10)
858             ? tvb_get_letohl (tvb, offset)
859             : tvb_get_ntohl (tvb, offset));
860
861     tv.secs=data;
862     tv.nsecs=0;
863     if (tree) {
864         proto_tree_add_time (tree, hfindex, tvb, offset, 4, &tv);
865     }
866     if (pdata)
867         *pdata = data;
868
869     return offset+4;
870 }
871
872 int
873 dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
874                        proto_tree *tree, char *drep,
875                        int hfindex, unsigned char *pdata)
876 {
877     if(pdata){
878       tvb_memcpy(tvb, pdata, offset, 8);
879       if(drep[0] & 0x10){/* XXX this might be the wrong way around */
880         unsigned char data;
881         data=pdata[0];pdata[0]=pdata[7];pdata[7]=data;
882         data=pdata[1];pdata[1]=pdata[6];pdata[6]=data;
883         data=pdata[2];pdata[2]=pdata[5];pdata[5]=data;
884         data=pdata[3];pdata[3]=pdata[4];pdata[4]=data;
885       }
886     }
887
888     if (tree) {
889         proto_tree_add_item(tree, hfindex, tvb, offset, 8, (drep[0] & 0x10));
890     }
891
892     return offset+8;
893 }
894
895
896 int
897 dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
898                     proto_tree *tree, char *drep, 
899                     int hfindex, gfloat *pdata)
900 {
901         gfloat data;
902
903
904         switch(drep[1]) {
905                 case(DCE_RPC_DREP_FP_IEEE):
906                         data = ((drep[0] & 0x10)
907                                         ? tvb_get_letohieee_float(tvb, offset)
908                                         : tvb_get_ntohieee_float(tvb, offset));
909                         if (tree) {
910                                 proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
911                         }
912                         break;
913                 case(DCE_RPC_DREP_FP_VAX):  /* (fall trough) */
914                 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
915                 case(DCE_RPC_DREP_FP_IBM):  /* (fall trough) */
916                 default:
917                         /* ToBeDone: non IEEE floating formats */
918                         /* Set data to a negative infinity value */
919                         data = -1.0 * 1e100 * 1e100;
920                         if (tree) {
921                                 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep[1]);
922                         }
923         }
924     if (pdata)
925         *pdata = data;
926     return offset + 4;
927 }
928
929
930 int
931 dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
932                     proto_tree *tree, char *drep, 
933                     int hfindex, gdouble *pdata)
934 {
935     gdouble data;
936
937
938         switch(drep[1]) {
939                 case(DCE_RPC_DREP_FP_IEEE):
940                         data = ((drep[0] & 0x10)
941                                         ? tvb_get_letohieee_double(tvb, offset)
942                                         : tvb_get_ntohieee_double(tvb, offset));
943                         if (tree) {
944                                 proto_tree_add_double(tree, hfindex, tvb, offset, 8, data);
945                         }
946                         break;
947                 case(DCE_RPC_DREP_FP_VAX):  /* (fall trough) */
948                 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
949                 case(DCE_RPC_DREP_FP_IBM):  /* (fall trough) */
950                 default:
951                         /* ToBeDone: non IEEE double formats */
952                         /* Set data to a negative infinity value */
953                         data = -1.0 * 1e100 * 1e100;
954                         if (tree) {
955                                 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep[1]);
956                         }
957         }
958     if (pdata)
959         *pdata = data;
960     return offset + 8;
961 }
962
963
964 /*
965  * a couple simpler things
966  */
967 guint16
968 dcerpc_tvb_get_ntohs (tvbuff_t *tvb, gint offset, char *drep)
969 {
970     if (drep[0] & 0x10) {
971         return tvb_get_letohs (tvb, offset);
972     } else {
973         return tvb_get_ntohs (tvb, offset);
974     }
975 }
976
977 guint32
978 dcerpc_tvb_get_ntohl (tvbuff_t *tvb, gint offset, char *drep)
979 {
980     if (drep[0] & 0x10) {
981         return tvb_get_letohl (tvb, offset);
982     } else {
983         return tvb_get_ntohl (tvb, offset);
984     }
985 }
986
987 void
988 dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, char *drep, e_uuid_t *uuid)
989 {
990     unsigned int i;
991     uuid->Data1 = dcerpc_tvb_get_ntohl (tvb, offset, drep);
992     uuid->Data2 = dcerpc_tvb_get_ntohs (tvb, offset+4, drep);
993     uuid->Data3 = dcerpc_tvb_get_ntohs (tvb, offset+6, drep);
994
995     for (i=0; i<sizeof (uuid->Data4); i++) {
996         uuid->Data4[i] = tvb_get_guint8 (tvb, offset+8+i);
997     }
998 }
999
1000
1001
1002 /* NDR arrays */
1003 /* function to dissect a unidimensional conformant array */
1004 int
1005 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1006                 proto_tree *tree, char *drep,
1007                 dcerpc_dissect_fnct_t *fnct)
1008 {
1009         guint32 i;
1010         dcerpc_info *di;
1011         int old_offset;
1012
1013         di=pinfo->private_data;
1014         if(di->conformant_run){
1015                 /* conformant run, just dissect the max_count header */
1016                 old_offset=offset;
1017                 di->conformant_run=0;
1018                 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1019                                 hf_dcerpc_array_max_count, &di->array_max_count);
1020                 di->array_max_count_offset=offset-4;
1021                 di->conformant_run=1;
1022                 di->conformant_eaten=offset-old_offset;
1023         } else {
1024                 /* we don't remember where in the bytestream this field was */
1025                 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1026
1027                 /* real run, dissect the elements */
1028                 for(i=0;i<di->array_max_count;i++){
1029                         offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1030                 }
1031         }
1032
1033         return offset;
1034 }
1035 /* function to dissect a unidimensional conformant and varying array */
1036 int
1037 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1038                 proto_tree *tree, char *drep,
1039                 dcerpc_dissect_fnct_t *fnct)
1040 {
1041         guint32 i;
1042         dcerpc_info *di;
1043         int old_offset;
1044
1045         di=pinfo->private_data;
1046         if(di->conformant_run){
1047                 /* conformant run, just dissect the max_count header */
1048                 old_offset=offset;
1049                 di->conformant_run=0;
1050                 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1051                                 hf_dcerpc_array_max_count, &di->array_max_count);
1052                 di->array_max_count_offset=offset-4;
1053                 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1054                                 hf_dcerpc_array_offset, &di->array_offset);
1055                 di->array_offset_offset=offset-4;
1056                 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1057                                 hf_dcerpc_array_actual_count, &di->array_actual_count);
1058                 di->array_actual_count_offset=offset-4;
1059                 di->conformant_run=1;
1060                 di->conformant_eaten=offset-old_offset;
1061         } else {
1062                 /* we dont dont remember where  in the bytestream these fields were */
1063                 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1064                 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
1065                 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
1066
1067                 /* real run, dissect the elements */
1068                 for(i=0;i<di->array_actual_count;i++){
1069                         offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1070                 }
1071         }
1072
1073         return offset;
1074 }
1075
1076 /* Dissect an string of bytes.  This corresponds to
1077    IDL of the form '[string] byte *foo'.
1078
1079    It can also be used for a conformant varying array of bytes if
1080    the contents of the array should be shown as a big blob, rather
1081    than showing each byte as an individual element.
1082
1083    XXX - which of those is really the IDL type for, for example,
1084    the encrypted data in some MAPI packets?  (Microsoft haven't
1085    released that IDL.)
1086
1087    XXX - does this need to do all the conformant array stuff that
1088    "dissect_ndr_ucvarray()" does?  These are presumably for strings
1089    that are conformant and varying - they're stored like conformant
1090    varying arrays of bytes.  */
1091 int
1092 dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1093                             proto_tree *tree, char *drep)
1094 {
1095     dcerpc_info *di;
1096     guint32 len;
1097
1098     di=pinfo->private_data;
1099     if(di->conformant_run){
1100       /* just a run to handle conformant arrays, no scalars to dissect */
1101       return offset;
1102     }
1103
1104     /* NDR array header */
1105
1106     offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1107                                 hf_dcerpc_array_max_count, NULL);
1108
1109     offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1110                                 hf_dcerpc_array_offset, NULL);
1111
1112     offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1113                                 hf_dcerpc_array_actual_count, &len);
1114
1115     if (tree && len)
1116         proto_tree_add_item(tree, hf_dcerpc_array_buffer,
1117                             tvb, offset, len, drep[0] & 0x10);
1118
1119     offset += len;
1120
1121     return offset;
1122 }
1123
1124 /* For dissecting arrays that are to be interpreted as strings.  */
1125
1126 /* Dissect an NDR conformant varying string of elements.
1127    The length of each element is given by the 'size_is' parameter;
1128    the elements are assumed to be characters or wide characters.
1129
1130    XXX - does this need to do all the conformant array stuff that
1131    "dissect_ndr_ucvarray()" does?  */
1132 int
1133 dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1134                      proto_tree *tree, char *drep, int size_is,
1135                      int hfindex, gboolean add_subtree, char **data)
1136 {
1137     dcerpc_info *di;
1138     proto_item *string_item;
1139     proto_tree *string_tree;
1140     guint32 len, buffer_len;
1141     char *s;
1142     header_field_info *hfinfo;
1143
1144     di=pinfo->private_data;
1145     if(di->conformant_run){
1146       /* just a run to handle conformant arrays, no scalars to dissect */
1147       return offset;
1148     }
1149
1150     if (add_subtree) {
1151         string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1152                                           proto_registrar_get_name(hfindex));
1153         string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1154     } else {
1155         string_item = NULL;
1156         string_tree = tree;
1157     }
1158
1159     /* NDR array header */
1160
1161     offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1162                                 hf_dcerpc_array_max_count, NULL);
1163
1164     offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1165                                 hf_dcerpc_array_offset, NULL);
1166
1167     offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1168                                 hf_dcerpc_array_actual_count, &len);
1169
1170     buffer_len = size_is * len;
1171
1172     /* Adjust offset */
1173     if (offset % size_is)
1174         offset += size_is - (offset % size_is);
1175
1176     if (size_is == sizeof(guint16)) {
1177         /* XXX - use drep to determine the byte order? */
1178         s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
1179         /*
1180          * XXX - we don't support a string type with Unicode
1181          * characters, so if this is a string item, we make
1182          * its value be the "fake Unicode" string.
1183          */
1184         if (tree && buffer_len) {
1185             hfinfo = proto_registrar_get_nth(hfindex);
1186             if (hfinfo->type == FT_STRING) {
1187                 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1188                                       buffer_len, s);
1189             } else {
1190                 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1191                                     buffer_len, drep[0] & 0x10);
1192             }
1193         }
1194     } else {
1195         /*
1196          * "tvb_get_string()" throws an exception if the entire string
1197          * isn't in the tvbuff.  If the length is bogus, this should
1198          * keep us from trying to allocate an immensely large buffer.
1199          * (It won't help if the length is *valid* but immensely large,
1200          * but that's another matter; in any case, that would happen only
1201          * if we had an immensely large tvbuff....)
1202          */
1203         s = tvb_get_string(tvb, offset, buffer_len);
1204         if (tree && buffer_len)
1205             proto_tree_add_item(string_tree, hfindex, tvb, offset,
1206                                 buffer_len, drep[0] & 0x10);
1207     }
1208
1209     if (string_item != NULL)
1210         proto_item_append_text(string_item, ": %s", s);
1211
1212     if (data)
1213             *data = s;
1214     else
1215             g_free(s);
1216     
1217     offset += buffer_len;
1218
1219     proto_item_set_end(string_item, tvb, offset);
1220
1221     return offset;
1222 }
1223
1224 /* Dissect an conformant varying string of chars.
1225    This corresponds to IDL of the form '[string] char *foo'.
1226
1227    XXX - at least according to the DCE RPC 1.1 spec, a string has
1228    a null terminator, which isn't necessary as a terminator for
1229    the transfer language (as there's a length), but is presumably
1230    there for the benefit of null-terminated-string languages
1231    such as C.  Is this ever used for purely counted strings?
1232    (Not that it matters if it is.) */
1233 int
1234 dissect_ndr_char_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1235                         proto_tree *tree, char *drep)
1236 {
1237     dcerpc_info *di;
1238     di=pinfo->private_data;
1239
1240     return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1241                                 sizeof(guint8), di->hf_index,
1242                                 FALSE, NULL);
1243 }
1244
1245 /* Dissect a conformant varying string of wchars (wide characters).
1246    This corresponds to IDL of the form '[string] wchar *foo'
1247
1248    XXX - at least according to the DCE RPC 1.1 spec, a string has
1249    a null terminator, which isn't necessary as a terminator for
1250    the transfer language (as there's a length), but is presumably
1251    there for the benefit of null-terminated-string languages
1252    such as C.  Is this ever used for purely counted strings?
1253    (Not that it matters if it is.) */
1254 int
1255 dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1256                         proto_tree *tree, char *drep)
1257 {
1258     dcerpc_info *di;
1259     di=pinfo->private_data;
1260
1261     return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1262                                 sizeof(guint16), di->hf_index,
1263                                 FALSE, NULL);
1264 }
1265
1266 /* ndr pointer handling */
1267 /* list of pointers encountered so far */
1268 static GSList *ndr_pointer_list = NULL;
1269
1270 /* position where in the list to insert newly encountered pointers */
1271 static int ndr_pointer_list_pos=0;
1272
1273 /* boolean controlling whether pointers are top-level or embedded */
1274 static gboolean pointers_are_top_level = TRUE;
1275
1276 /* as a kludge, we represent all embedded reference pointers as id==-1
1277    hoping that his will not collide with any non-ref pointers */
1278 typedef struct ndr_pointer_data {
1279         guint32 id;
1280         proto_item *item;       /* proto_item for pointer */
1281         proto_tree *tree;       /* subtree of above item */
1282         dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
1283         int hf_index;
1284         dcerpc_callback_fnct_t *callback;
1285         void *callback_args;
1286 } ndr_pointer_data_t;
1287
1288 static void
1289 init_ndr_pointer_list(packet_info *pinfo)
1290 {
1291         dcerpc_info *di;
1292
1293         di=pinfo->private_data;
1294         di->conformant_run=0;
1295
1296         while(ndr_pointer_list){
1297                 ndr_pointer_data_t *npd;
1298
1299                 npd=g_slist_nth_data(ndr_pointer_list, 0);
1300                 ndr_pointer_list=g_slist_remove(ndr_pointer_list, npd);
1301                 if(npd){
1302                         g_free(npd);
1303                 }
1304         }
1305
1306         ndr_pointer_list=NULL;
1307         ndr_pointer_list_pos=0;
1308         pointers_are_top_level=TRUE;
1309 }
1310
1311 static int
1312 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, char *drep)
1313 {
1314         int found_new_pointer;
1315         dcerpc_info *di;
1316         int old_offset;
1317
1318         di=pinfo->private_data;
1319         do{
1320                 int i, len;
1321
1322                 found_new_pointer=0;
1323                 len=g_slist_length(ndr_pointer_list);
1324                 for(i=0;i<len;i++){
1325                         ndr_pointer_data_t *tnpd;
1326                         tnpd=g_slist_nth_data(ndr_pointer_list, i);
1327                         if(tnpd->fnct){
1328                                 dcerpc_dissect_fnct_t *fnct;
1329
1330                                 found_new_pointer=1;
1331                                 fnct=tnpd->fnct;
1332                                 tnpd->fnct=NULL;
1333                                 ndr_pointer_list_pos=i+1;
1334                                 di->hf_index=tnpd->hf_index;
1335                                 /* first a run to handle any conformant
1336                                    array headers */
1337                                 di->conformant_run=1;
1338                                 di->conformant_eaten=0;
1339                                 old_offset = offset;
1340                                 offset = (*(fnct))(tvb, offset, pinfo, NULL, drep);
1341
1342                                 g_assert((offset-old_offset)==di->conformant_eaten);
1343                                 /* This is to check for any bugs in the dissectors.
1344                                  *
1345                                  * Basically, the NDR representation will store all
1346                                  * arrays in two blocks, one block with the dimension
1347                                  * discreption, like size, number of elements and such,
1348                                  * and another block that contains the actual data stored
1349                                  * in the array.
1350                                  * If the array is embedded directly inside another,
1351                                  * encapsulating aggregate type, like a union or struct,
1352                                  * then these two blocks will be stored at different places
1353                                  * in the bytestream, with other data between the blocks.
1354                                  *
1355                                  * For this reason, all pointers to types (both aggregate
1356                                  * and scalar, for simplicity no distinction is made)
1357                                  * will have its dissector called twice.
1358                                  * The dissector will first be called with conformant_run==1
1359                                  * in which mode the dissector MUST NOT consume any data from
1360                                  * the tvbuff (i.e. may not dissect anything) except the
1361                                  * initial control block for arrays.
1362                                  * The second time the dissector is called, with
1363                                  * conformant_run==0, all other data for the type will be
1364                                  * dissected.
1365                                  *
1366                                  * All dissect_ndr_<type> dissectors are already prepared
1367                                  * for this and knows when it should eat data from the tvb
1368                                  * and when not to, so implementors of dissectors will
1369                                  * normally not need to worry about this or even know about
1370                                  * it. However, if a dissector for an aggregate type calls
1371                                  * a subdissector from outside packet-dcerpc.c, such as
1372                                  * the dissector in packet-smb.c for NT Security Descriptors
1373                                  * as an example, then it is VERY important to encapsulate
1374                                  * this call to an external subdissector with the appropriate
1375                                  * test for conformant_run, i.e. it will need something like
1376                                  *
1377                                  *      dcerpc_info *di;
1378                                  *
1379                                  *      di=pinfo->private_data;
1380                                  *      if(di->conformant_run){
1381                                  *              return offset;
1382                                  *      }
1383                                  *
1384                                  * to make sure it makes the right thing.
1385                                  * This assert will signal when someone has forgotten to
1386                                  * make the dissector aware of this requirement.
1387                                  */
1388
1389                                 /* now we dissect the actual pointer */
1390                                 di->conformant_run=0;
1391                                 old_offset = offset;
1392                                 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, drep);
1393                                 if (tnpd->callback)
1394                                         tnpd->callback(pinfo, tnpd->tree, tnpd->item, tvb, old_offset, offset, tnpd->callback_args);
1395                                 break;
1396                         }
1397                 }
1398         } while(found_new_pointer);
1399
1400         return offset;
1401 }
1402
1403
1404 static void
1405 add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
1406                     dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index, 
1407                     dcerpc_callback_fnct_t *callback, void *callback_args)
1408 {
1409         ndr_pointer_data_t *npd;
1410
1411         /* check if this pointer is valid */
1412         if(id!=0xffffffff){
1413                 dcerpc_info *di;
1414                 dcerpc_call_value *value;
1415
1416                 di=pinfo->private_data;
1417                 value=di->call_data;
1418
1419                 if(di->request){
1420                         if(!(pinfo->fd->flags.visited)){
1421                                 if(id>value->max_ptr){
1422                                         value->max_ptr=id;
1423                                 }
1424                         }
1425                 } else {
1426                         /* if we havent seen the request bail out since we cant
1427                            know whether this is the first non-NULL instance
1428                            or not */
1429                         if(value->req_frame==0){
1430                                 /* XXX THROW EXCEPTION */
1431                         }
1432
1433                         /* We saw this one in the request frame, nothing to
1434                            dissect later */
1435                         if(id<=value->max_ptr){
1436                                 return;
1437                         }
1438                 }
1439         }
1440
1441         npd=g_malloc(sizeof(ndr_pointer_data_t));
1442         npd->id=id;
1443         npd->tree=tree;
1444         npd->item=item;
1445         npd->fnct=fnct;
1446         npd->hf_index=hf_index;
1447         npd->callback=callback;
1448         npd->callback_args=callback_args;
1449         ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
1450                                         ndr_pointer_list_pos);
1451         ndr_pointer_list_pos++;
1452 }
1453
1454
1455 static int
1456 find_pointer_index(guint32 id)
1457 {
1458         ndr_pointer_data_t *npd;
1459         int i,len;
1460
1461         len=g_slist_length(ndr_pointer_list);
1462         for(i=0;i<len;i++){
1463                 npd=g_slist_nth_data(ndr_pointer_list, i);
1464                 if(npd){
1465                         if(npd->id==id){
1466                                 return i;
1467                         }
1468                 }
1469         }
1470
1471         return -1;
1472 }
1473
1474 /* This function dissects an NDR pointer and stores the callback for later
1475  * deferred dissection.
1476  *
1477  *   fnct is the callback function for when we have reached this object in
1478  *   the bytestream.
1479  *
1480  *   type is what type of pointer.
1481  *
1482  *   this is text is what text we should put in any created tree node.
1483  *
1484  *   hf_index is what hf value we want to pass to the callback function when
1485  *   it is called, the callback can later pich this one up from di->hf_index.
1486  *
1487  *   callback is executed after the pointer has been dereferenced.
1488  *
1489  *   callback_args is passed as an argument to the callback function
1490  *
1491  * See packet-dcerpc-samr.c for examples
1492  */
1493 int
1494 dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1495                     proto_tree *tree, char *drep, dcerpc_dissect_fnct_t *fnct,
1496                     int type, char *text, int hf_index, 
1497                     dcerpc_callback_fnct_t *callback, void *callback_args)
1498 {
1499         dcerpc_info *di;
1500
1501         di=pinfo->private_data;
1502         if(di->conformant_run){
1503                 /* this call was only for dissecting the header for any
1504                    embedded conformant array. we will not parse any
1505                    pointers in this mode.
1506                 */
1507                 return offset;
1508         }
1509
1510         /*TOP LEVEL REFERENCE POINTER*/
1511         if( pointers_are_top_level
1512         &&(type==NDR_POINTER_REF) ){
1513                 proto_item *item;
1514                 proto_tree *tr;
1515
1516                 /* we must find out a nice way to do the length here */
1517                 item=proto_tree_add_text(tree, tvb, offset, 0,
1518                         "%s", text);
1519                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1520
1521                 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff, 
1522                                     hf_index, callback, callback_args);
1523                 goto after_ref_id;
1524         }
1525
1526         /*TOP LEVEL FULL POINTER*/
1527         if( pointers_are_top_level
1528         && (type==NDR_POINTER_PTR) ){
1529                 int idx;
1530                 guint32 id;
1531                 proto_item *item;
1532                 proto_tree *tr;
1533
1534                 /* get the referent id */
1535                 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1536
1537                 /* we got a NULL pointer */
1538                 if(id==0){
1539                         proto_tree_add_text(tree, tvb, offset-4, 4,
1540                                 "(NULL pointer) %s",text);
1541                         goto after_ref_id;
1542                 }
1543
1544                 /* see if we have seen this pointer before */
1545                 idx=find_pointer_index(id);
1546
1547                 /* we have seen this pointer before */
1548                 if(idx>=0){
1549                         proto_tree_add_text(tree, tvb, offset-4, 4,
1550                                 "(duplicate PTR) %s",text);
1551                         goto after_ref_id;
1552                 }
1553
1554                 /* new pointer */
1555                 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1556                         "%s", text);
1557                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1558                 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1559                 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index, 
1560                                     callback, callback_args);
1561                 goto after_ref_id;
1562         }
1563         /*TOP LEVEL UNIQUE POINTER*/
1564         if( pointers_are_top_level
1565         && (type==NDR_POINTER_UNIQUE) ){
1566                 guint32 id;
1567                 proto_item *item;
1568                 proto_tree *tr;
1569
1570                 /* get the referent id */
1571                 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1572
1573                 /* we got a NULL pointer */
1574                 if(id==0){
1575                         proto_tree_add_text(tree, tvb, offset-4, 4,
1576                                 "(NULL pointer) %s",text);
1577                         goto after_ref_id;
1578                 }
1579
1580                 /* new pointer */
1581                 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1582                         "%s", text);
1583                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1584                 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1585                 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff, 
1586                                     hf_index, callback, callback_args);
1587                 goto after_ref_id;
1588         }
1589
1590         /*EMBEDDED REFERENCE POINTER*/
1591         if( (!pointers_are_top_level)
1592         && (type==NDR_POINTER_REF) ){
1593                 guint32 id;
1594                 proto_item *item;
1595                 proto_tree *tr;
1596
1597                 /* get the referent id */
1598                 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1599
1600                 /* new pointer */
1601                 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1602                         "%s",text);
1603                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1604                 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1605                 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff, 
1606                                     hf_index, callback, callback_args);
1607                 goto after_ref_id;
1608         }
1609
1610         /*EMBEDDED UNIQUE POINTER*/
1611         if( (!pointers_are_top_level)
1612         && (type==NDR_POINTER_UNIQUE) ){
1613                 guint32 id;
1614                 proto_item *item;
1615                 proto_tree *tr;
1616
1617                 /* get the referent id */
1618                 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1619
1620                 /* we got a NULL pointer */
1621                 if(id==0){
1622                         proto_tree_add_text(tree, tvb, offset-4, 4,
1623                                 "(NULL pointer) %s", text);
1624                         goto after_ref_id;
1625                 }
1626
1627                 /* new pointer */
1628                 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1629                         "%s",text);
1630                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1631                 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1632                 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff, 
1633                                     hf_index, callback, callback_args);
1634                 goto after_ref_id;
1635         }
1636
1637         /*EMBEDDED FULL POINTER*/
1638         if( (!pointers_are_top_level)
1639         && (type==NDR_POINTER_PTR) ){
1640                 int idx;
1641                 guint32 id;
1642                 proto_item *item;
1643                 proto_tree *tr;
1644
1645                 /* get the referent id */
1646                 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1647
1648                 /* we got a NULL pointer */
1649                 if(id==0){
1650                         proto_tree_add_text(tree, tvb, offset-4, 4,
1651                                 "(NULL pointer) %s",text);
1652                         goto after_ref_id;
1653                 }
1654
1655                 /* see if we have seen this pointer before */
1656                 idx=find_pointer_index(id);
1657
1658                 /* we have seen this pointer before */
1659                 if(idx>=0){
1660                         proto_tree_add_text(tree, tvb, offset-4, 4,
1661                                 "(duplicate PTR) %s",text);
1662                         goto after_ref_id;
1663                 }
1664
1665                 /* new pointer */
1666                 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1667                         "%s", text);
1668                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1669                 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1670                 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index, 
1671                                     callback, callback_args);
1672                 goto after_ref_id;
1673         }
1674
1675
1676 after_ref_id:
1677         /* After each top level pointer we have dissected we have to
1678            dissect all deferrals before we move on to the next top level
1679            argument */
1680         if(pointers_are_top_level==TRUE){
1681                 pointers_are_top_level=FALSE;
1682                 offset = dissect_deferred_pointers(pinfo, tvb, offset, drep);
1683                 pointers_are_top_level=TRUE;
1684         }
1685
1686         return offset;
1687 }
1688
1689 int
1690 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1691                     proto_tree *tree, char *drep, dcerpc_dissect_fnct_t *fnct,
1692                     int type, char *text, int hf_index)
1693 {
1694         return dissect_ndr_pointer_cb(
1695                 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
1696                 NULL, NULL);
1697 }
1698
1699 static void
1700 show_stub_data (tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
1701                 dcerpc_auth_info *auth_info)
1702 {
1703     int length;
1704
1705     /*
1706      * We don't show stub data unless we have some in the tvbuff;
1707      * however, in the protocol tree, we show, as the number of
1708      * bytes, the reported number of bytes, not the number of bytes
1709      * that happen to be in the tvbuff.
1710      */
1711     if (tvb_length_remaining (tvb, offset) > 0) {
1712         length = tvb_reported_length_remaining (tvb, offset);
1713         if (auth_info != NULL &&
1714             auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
1715             proto_tree_add_text(dcerpc_tree, tvb, offset, -1,
1716                                 "Encrypted stub data (%d byte%s)",
1717                                 length, plurality(length, "", "s"));
1718         } else {
1719             proto_tree_add_text (dcerpc_tree, tvb, offset, -1,
1720                                  "Stub data (%d byte%s)", length,
1721                                  plurality(length, "", "s"));
1722         }
1723     }
1724 }
1725
1726 static int
1727 dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
1728                     proto_tree *dcerpc_tree,
1729                     tvbuff_t *volatile tvb, volatile gint offset,
1730                     char *drep, dcerpc_info *info,
1731                     dcerpc_auth_info *auth_info)
1732 {
1733     dcerpc_uuid_key key;
1734     dcerpc_uuid_value *sub_proto;
1735     int length;
1736     proto_tree *volatile sub_tree = NULL;
1737     dcerpc_sub_dissector *proc;
1738     gchar *name = NULL;
1739     dcerpc_dissect_fnct_t *volatile sub_dissect;
1740     const char *volatile saved_proto;
1741     void *volatile saved_private_data;
1742
1743     key.uuid = info->call_data->uuid;
1744     key.ver = info->call_data->ver;
1745
1746
1747     if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == NULL
1748          || !proto_is_protocol_enabled(sub_proto->proto)) {
1749         /*
1750          * We don't have a dissector for this UUID, or the protocol
1751          * for that UUID is disabled.
1752          */
1753         show_stub_data (tvb, offset, dcerpc_tree, auth_info);
1754         return -1;
1755     }
1756
1757     for (proc = sub_proto->procs; proc->name; proc++) {
1758         if (proc->num == info->call_data->opnum) {
1759             name = proc->name;
1760             break;
1761         }
1762     }
1763
1764     if (!name)
1765         name = "Unknown?!";
1766
1767     if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
1768         col_set_str (pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
1769     }
1770
1771     if (check_col (pinfo->cinfo, COL_INFO)) {
1772         col_add_fstr (pinfo->cinfo, COL_INFO, "%s %s",
1773                       name, info->request ? "request" : "reply");
1774     }
1775
1776     if (tree) {
1777         proto_item *sub_item;
1778         sub_item = proto_tree_add_item (tree, sub_proto->proto, tvb, offset,
1779                                         -1, FALSE);
1780
1781         if (sub_item) {
1782             sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
1783         }
1784
1785         /*
1786          * Put the operation number into the tree along with
1787          * the operation's name.
1788          */
1789
1790         if (sub_proto->opnum_hf != -1)
1791                 proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
1792                                            tvb, 0, 0, info->call_data->opnum,
1793                                            "Operation: %s (%u)",
1794                                            name, info->call_data->opnum);
1795         else
1796                 proto_tree_add_uint_format(sub_tree, hf_dcerpc_op, tvb,
1797                                            0, 0, info->call_data->opnum,
1798                                            "Operation: %s (%u)",
1799                                            name, info->call_data->opnum);
1800     }
1801
1802     sub_dissect = info->request ? proc->dissect_rqst : proc->dissect_resp;
1803
1804     /* Call subdissector if we have a zero auth_level and no decrypted data,
1805        or non-zero auth_level and sucessfully decrypted data. */
1806
1807     if (sub_dissect && ((!auth_info->auth_level && !pinfo->decrypted_data) ||
1808                         (auth_info->auth_level && pinfo->decrypted_data))) {
1809             saved_proto = pinfo->current_proto;
1810             saved_private_data = pinfo->private_data;
1811             pinfo->current_proto = sub_proto->name;
1812             pinfo->private_data = (void *)info;
1813             
1814             init_ndr_pointer_list(pinfo);
1815             /*
1816              * Catch ReportedBoundsError, so that even if the stub
1817              * data is bad, we still show the verifier.
1818              */
1819             TRY {
1820                 offset = sub_dissect (tvb, offset, pinfo, sub_tree, drep);
1821             } CATCH(BoundsError) {
1822                 RETHROW;
1823             } CATCH(ReportedBoundsError) {
1824                 show_reported_bounds_error(tvb, pinfo, tree);
1825             } ENDTRY;
1826
1827             /* If there is auth padding at the end of the stub, display it */
1828             if (auth_info != NULL && auth_info->auth_pad_len != 0) {
1829                 proto_tree_add_text (sub_tree, tvb, offset, 
1830                                      auth_info->auth_pad_len,
1831                                      "Auth Padding (%u byte%s)",
1832                                      auth_info->auth_pad_len,
1833                                      plurality(auth_info->auth_pad_len, "", "s"));
1834                 offset += auth_info->auth_pad_len;
1835             }
1836
1837             /* If we have a subdissector and it didn't dissect all data in
1838                the tvb, make a note of it. */
1839
1840             if (tvb_length_remaining(tvb, offset)) {
1841                 if (check_col(pinfo->cinfo, COL_INFO))
1842                         col_append_fstr(pinfo->cinfo, COL_INFO,
1843                                         "[Long frame (%d bytes)]",
1844                                         tvb_length_remaining(tvb, offset));
1845             }
1846
1847             pinfo->current_proto = saved_proto;
1848             pinfo->private_data = saved_private_data;
1849         } else {
1850             length = tvb_length_remaining (tvb, offset);
1851             if (length > 0) {
1852                 proto_tree_add_text (sub_tree, tvb, offset, length,
1853                                      "Stub data (%d byte%s)", length,
1854                                      plurality(length, "", "s"));
1855             }
1856         }
1857
1858     tap_queue_packet(dcerpc_tap, pinfo, info);
1859     return 0;
1860 }
1861
1862 static int
1863 dissect_dcerpc_verifier (tvbuff_t *tvb, packet_info *pinfo, 
1864                          proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
1865                          dcerpc_auth_info *auth_info)
1866 {
1867     int auth_offset;
1868
1869     auth_info->auth_data = NULL;
1870
1871     if (auth_info->auth_size != 0) {
1872             dcerpc_auth_subdissector_fns *auth_fns;
1873             tvbuff_t *auth_tvb;
1874
1875             auth_offset = hdr->frag_len - hdr->auth_len;
1876
1877             auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
1878                                       hdr->auth_len);
1879
1880             auth_info->auth_data = auth_tvb;
1881
1882             if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
1883                                                       auth_info->auth_type)))
1884                     dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
1885                                       hdr, auth_info);
1886             else
1887                     proto_tree_add_text (dcerpc_tree, auth_tvb, 0, hdr->auth_len,
1888                                          "Auth Verifier");
1889     }
1890
1891     return hdr->auth_len;
1892 }
1893
1894 static void
1895 dissect_dcerpc_cn_auth (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1896                         e_dce_cn_common_hdr_t *hdr, gboolean are_credentials, 
1897                         dcerpc_auth_info *auth_info)
1898 {
1899     int offset;
1900
1901     /*
1902      * Initially set auth_level and auth_type to zero to indicate that we 
1903      * haven't yet seen any authentication level information.
1904      */
1905     auth_info->auth_level = 0;
1906     auth_info->auth_type = 0;
1907     
1908     /*
1909      * The authentication information is at the *end* of the PDU; in
1910      * request and response PDUs, the request and response stub data
1911      * come before it.
1912      *
1913      * If the full packet is here, and we've got an auth len, and it's
1914      * valid, then dissect the auth info.
1915      */
1916
1917     if (tvb_length (tvb) >= hdr->frag_len
1918         && hdr->auth_len
1919         && (hdr->auth_len + 8 <= hdr->frag_len)) {
1920
1921         offset = hdr->frag_len - (hdr->auth_len + 8);
1922
1923         offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1924                                        hf_dcerpc_auth_type, 
1925                                        &auth_info->auth_type);
1926         offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1927                                        hf_dcerpc_auth_level, 
1928                                        &auth_info->auth_level);
1929
1930         offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1931                                        hf_dcerpc_auth_pad_len, 
1932                                        &auth_info->auth_pad_len);
1933         offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1934                                        hf_dcerpc_auth_rsrvd, NULL);
1935         offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1936                                         hf_dcerpc_auth_ctx_id, NULL);
1937
1938         /*
1939          * Dissect the authentication data.
1940          */
1941         if (are_credentials) {
1942             tvbuff_t *auth_tvb;
1943             dcerpc_auth_subdissector_fns *auth_fns;
1944
1945             auth_tvb = tvb_new_subset(
1946                     tvb, offset, hdr->auth_len, hdr->auth_len);
1947
1948             if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
1949                                                       auth_info->auth_type)))
1950                     dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns, 
1951                                       hdr, auth_info);
1952             else
1953                     proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len,
1954                                          "Auth Credentials");
1955         }
1956         
1957         /* Compute the size of the auth block.  Note that this should not 
1958            include auth padding, since when NTLMSSP encryption is used, the
1959            padding is actually inside the encrypted stub */
1960         auth_info->auth_size = hdr->auth_len + 8;
1961     } else {
1962         auth_info->auth_size = 0;
1963         auth_info->auth_pad_len = 0;
1964     }
1965 }
1966
1967
1968 /* We need to hash in the SMB fid number to generate a unique hash table
1969    key as DCERPC over SMB allows several pipes over the same TCP/IP
1970    socket. */
1971
1972 static guint16 get_smb_fid (void *private_data)
1973 {
1974     dcerpc_private_info *priv = (dcerpc_private_info *)private_data;
1975
1976     if (!priv)
1977         return 0;       /* Nothing to see here */
1978
1979     /* DCERPC over smb */
1980
1981     if (priv->transport_type == DCERPC_TRANSPORT_SMB)
1982         return priv->data.smb.fid;
1983
1984     /* Some other transport... */
1985
1986     return 0;
1987 }
1988
1989 /*
1990  * Connection oriented packet types
1991  */
1992
1993 static void
1994 dissect_dcerpc_cn_bind (tvbuff_t *tvb, gint offset, packet_info *pinfo, 
1995                         proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
1996 {
1997     conversation_t *conv = NULL;
1998     guint8 num_ctx_items;
1999     guint i;
2000     gboolean saw_ctx_item = FALSE;
2001     guint16 ctx_id;
2002     guint16 num_trans_items;
2003     guint j;
2004     e_uuid_t if_id;
2005     e_uuid_t trans_id;
2006     guint32 trans_ver;
2007     guint16 if_ver, if_ver_minor;
2008     char uuid_str[DCERPC_UUID_STR_LEN]; 
2009     int uuid_str_len;
2010     dcerpc_auth_info auth_info;
2011
2012     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2013                                     hf_dcerpc_cn_max_xmit, NULL);
2014
2015     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2016                                     hf_dcerpc_cn_max_recv, NULL);
2017
2018     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2019                                     hf_dcerpc_cn_assoc_group, NULL);
2020
2021     offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2022                                     hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
2023
2024     /* padding */
2025     offset += 3;
2026
2027     for (i = 0; i < num_ctx_items; i++) {
2028             proto_tree *ctx_tree = NULL, *iface_tree = NULL;
2029
2030       offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, NULL, hdr->drep,
2031                                       hf_dcerpc_cn_ctx_id, &ctx_id);
2032
2033       if (dcerpc_tree) {
2034               proto_item *ctx_item;
2035
2036               ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_id,
2037                                              tvb, offset - 2, 2, 
2038                                              hdr->drep[0] & 0x10);
2039
2040               ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
2041       }
2042
2043       offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, ctx_tree, hdr->drep,
2044                                       hf_dcerpc_cn_num_trans_items, &num_trans_items);
2045
2046       /* XXX - use "dissect_ndr_uuid_t()"? */
2047       dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
2048       if (ctx_tree) {
2049           proto_item *iface_item;
2050
2051           uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, 
2052                                   "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2053                                   if_id.Data1, if_id.Data2, if_id.Data3,
2054                                   if_id.Data4[0], if_id.Data4[1],
2055                                   if_id.Data4[2], if_id.Data4[3],
2056                                   if_id.Data4[4], if_id.Data4[5],
2057                                   if_id.Data4[6], if_id.Data4[7]);
2058
2059           if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2060                   memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2061
2062           iface_item = proto_tree_add_string_format (ctx_tree, hf_dcerpc_cn_bind_if_id, tvb,
2063                                         offset, 16, uuid_str, "Interface UUID: %s", uuid_str);
2064           iface_tree = proto_item_add_subtree(iface_item, ett_dcerpc_cn_iface);
2065       }
2066       offset += 16;
2067
2068       if (hdr->drep[0] & 0x10) {
2069           offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2070                                           hf_dcerpc_cn_bind_if_ver, &if_ver);
2071           offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2072                                           hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2073       } else {
2074           offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2075                                           hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2076           offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2077                                           hf_dcerpc_cn_bind_if_ver, &if_ver);
2078       }
2079
2080       if (!saw_ctx_item) {
2081         conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2082                                   pinfo->srcport, pinfo->destport, 0);
2083         if (conv == NULL) {
2084             conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
2085                                      pinfo->srcport, pinfo->destport, 0);
2086         }
2087
2088         /* if this is the first time we see this packet, we need to
2089            update the dcerpc_binds table so that any later calls can
2090            match to the interface.
2091            XXX We assume that BINDs will NEVER be fragmented.
2092         */
2093         if(!(pinfo->fd->flags.visited)){
2094                 dcerpc_bind_key *key;
2095                 dcerpc_bind_value *value;
2096
2097                 key = g_mem_chunk_alloc (dcerpc_bind_key_chunk);
2098                 key->conv = conv;
2099                 key->ctx_id = ctx_id;
2100                 key->smb_fid = get_smb_fid(pinfo->private_data);
2101
2102                 value = g_mem_chunk_alloc (dcerpc_bind_value_chunk);
2103                 value->uuid = if_id;
2104                 value->ver = if_ver;
2105
2106                 /* add this entry to the bind table, first removing any
2107                    previous ones that are identical
2108                  */
2109                 if(g_hash_table_lookup(dcerpc_binds, key)){
2110                         g_hash_table_remove(dcerpc_binds, key);
2111                 }
2112                 g_hash_table_insert (dcerpc_binds, key, value);
2113         }
2114
2115         if (check_col (pinfo->cinfo, COL_INFO)) {
2116           dcerpc_uuid_key key;
2117           dcerpc_uuid_value *value;
2118
2119           key.uuid = if_id;
2120           key.ver = if_ver;
2121
2122           if ((value = g_hash_table_lookup(dcerpc_uuids, &key)))
2123                   col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %s", value->name);
2124           else
2125                   col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
2126                            if_id.Data1, if_id.Data2, if_id.Data3,
2127                            if_id.Data4[0], if_id.Data4[1],
2128                            if_id.Data4[2], if_id.Data4[3],
2129                            if_id.Data4[4], if_id.Data4[5],
2130                            if_id.Data4[6], if_id.Data4[7],
2131                            if_ver, if_ver_minor);
2132         }
2133         saw_ctx_item = TRUE;
2134       }
2135
2136       for (j = 0; j < num_trans_items; j++) {
2137         /* XXX - use "dissect_ndr_uuid_t()"? */
2138         dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2139         if (iface_tree) {
2140             uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, 
2141                                   "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2142                                   trans_id.Data1, trans_id.Data2, trans_id.Data3,
2143                                   trans_id.Data4[0], trans_id.Data4[1],
2144                                   trans_id.Data4[2], trans_id.Data4[3],
2145                                   trans_id.Data4[4], trans_id.Data4[5],
2146                                   trans_id.Data4[6], trans_id.Data4[7]);
2147             if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2148                 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2149             proto_tree_add_string_format (iface_tree, hf_dcerpc_cn_bind_trans_id, tvb,
2150                                           offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2151         }
2152         offset += 16;
2153
2154         offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, iface_tree, hdr->drep,
2155                                         hf_dcerpc_cn_bind_trans_ver, &trans_ver);
2156       }
2157     }
2158
2159     /*
2160      * XXX - we should save the authentication type *if* we have
2161      * an authentication header, and associate it with an authentication
2162      * context, so subsequent PDUs can use that context.
2163      */
2164     dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2165 }
2166
2167 static void
2168 dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, gint offset, packet_info *pinfo, 
2169                             proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2170 {
2171     guint16 max_xmit, max_recv;
2172     guint16 sec_addr_len;
2173     guint8 num_results;
2174     guint i;
2175     guint16 result;
2176     guint16 reason;
2177     e_uuid_t trans_id;
2178     guint32 trans_ver;
2179     char uuid_str[DCERPC_UUID_STR_LEN]; 
2180     int uuid_str_len;
2181     dcerpc_auth_info auth_info;
2182
2183     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2184                                     hf_dcerpc_cn_max_xmit, &max_xmit);
2185
2186     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2187                                     hf_dcerpc_cn_max_recv, &max_recv);
2188
2189     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2190                                     hf_dcerpc_cn_assoc_group, NULL);
2191
2192     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2193                                     hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
2194     if (sec_addr_len != 0) {
2195         proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
2196                              sec_addr_len, FALSE);
2197         offset += sec_addr_len;
2198     }
2199
2200     if (offset % 4) {
2201         offset += 4 - offset % 4;
2202     }
2203
2204     offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2205                                    hf_dcerpc_cn_num_results, &num_results);
2206
2207     /* padding */
2208     offset += 3;
2209
2210     for (i = 0; i < num_results; i++) {
2211         offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2212                                         hdr->drep, hf_dcerpc_cn_ack_result,
2213                                         &result);
2214         if (result != 0) {
2215             offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2216                                             hdr->drep, hf_dcerpc_cn_ack_reason,
2217                                             &reason);
2218         } else {
2219             /*
2220              * The reason for rejection isn't meaningful, and often isn't
2221              * set, when the syntax was accepted.
2222              */
2223             offset += 2;
2224         }
2225
2226         /* XXX - use "dissect_ndr_uuid_t()"? */
2227         dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2228         if (dcerpc_tree) {
2229             uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, 
2230                                   "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2231                                   trans_id.Data1, trans_id.Data2, trans_id.Data3,
2232                                   trans_id.Data4[0], trans_id.Data4[1],
2233                                   trans_id.Data4[2], trans_id.Data4[3],
2234                                   trans_id.Data4[4], trans_id.Data4[5],
2235                                   trans_id.Data4[6], trans_id.Data4[7]);
2236             if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2237                   memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2238             proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_ack_trans_id, tvb,
2239                                           offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2240         }
2241         offset += 16;
2242
2243         offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2244                                         hf_dcerpc_cn_ack_trans_ver, &trans_ver);
2245     }
2246
2247     /*
2248      * XXX - do we need to do anything with the authentication level
2249      * we get back from this?
2250      */
2251     dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2252
2253     if (check_col (pinfo->cinfo, COL_INFO)) {
2254         if (num_results != 0 && result == 0) {
2255             /* XXX - only checks the last result */
2256             col_append_fstr (pinfo->cinfo, COL_INFO,
2257                              " accept max_xmit: %u max_recv: %u",
2258                              max_xmit, max_recv);
2259         } else {
2260             /* XXX - only shows the last result and reason */
2261             col_append_fstr (pinfo->cinfo, COL_INFO, " %s, reason: %s",
2262                              val_to_str(result, p_cont_result_vals,
2263                                         "Unknown result (%u)"),
2264                              val_to_str(reason, p_provider_reason_vals,
2265                                         "Unknown (%u)"));
2266         }
2267     }
2268 }
2269
2270 static void
2271 dissect_dcerpc_cn_bind_nak (tvbuff_t *tvb, gint offset, packet_info *pinfo, 
2272                             proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2273 {
2274     guint16 reason;
2275     guint8 num_protocols;
2276     guint i;
2277
2278     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2279                                     hdr->drep, hf_dcerpc_cn_reject_reason,
2280                                     &reason);
2281
2282     if (check_col (pinfo->cinfo, COL_INFO)) {
2283         col_append_fstr (pinfo->cinfo, COL_INFO, " reason: %s",
2284                       val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
2285     }
2286
2287     if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
2288         offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2289                                        hf_dcerpc_cn_num_protocols,
2290                                        &num_protocols);
2291
2292         for (i = 0; i < num_protocols; i++) {
2293             offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2294                                         hdr->drep, hf_dcerpc_cn_protocol_ver_major,
2295                                         NULL);
2296             offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2297                                         hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
2298                                         NULL);
2299         }
2300     }
2301 }
2302
2303 /* Return a string describing a DCE/RPC fragment as first, middle, or end
2304    fragment. */
2305
2306 #define PFC_FRAG_MASK  0x03
2307
2308 static char *
2309 fragment_type(guint8 flags)
2310 {
2311         flags = flags & PFC_FRAG_MASK;
2312
2313         if (flags == PFC_FIRST_FRAG)
2314                 return "first";
2315
2316         if (flags == 0)
2317                 return "middle";
2318
2319         if (flags == PFC_LAST_FRAG)
2320                 return "last";
2321
2322         if (flags == (PFC_FIRST_FRAG | PFC_LAST_FRAG))
2323                 return "whole";
2324
2325         return "unknown";
2326 }
2327
2328 /* Dissect stub data (payload) of a DCERPC packet. */
2329
2330 static void
2331 dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
2332                         proto_tree *dcerpc_tree, proto_tree *tree,
2333                         e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
2334                         dcerpc_auth_info *auth_info, guint32 alloc_hint,
2335                         guint32 frame)
2336 {
2337     gboolean save_fragmented, payload_ok;
2338     fragment_data *fd_head=NULL;
2339     guint32 tot_len;
2340     tvbuff_t *payload_tvb;
2341
2342     save_fragmented = pinfo->fragmented;
2343
2344     payload_tvb = tvb_new_subset(
2345             tvb, offset, tvb_length_remaining(tvb, offset) - 
2346             auth_info->auth_size, tvb_length_remaining(tvb, offset) - 
2347             auth_info->auth_size);    
2348
2349     payload_ok = TRUE;
2350
2351     /* Decrypt the PDU if it is encrypted */
2352
2353     pinfo->decrypted_data = NULL;
2354
2355     if (auth_info->auth_type) {
2356             dcerpc_auth_subdissector_fns *auth_fns;
2357             
2358             if (dcerpc_tree)
2359                     proto_tree_add_text(
2360                             dcerpc_tree, payload_tvb, 0, -1,
2361                             "Encrypted Stub Data (%d byte%s)",
2362                             tvb_length(payload_tvb),
2363                             plurality(tvb_length(payload_tvb), "", "s"));
2364
2365             if ((auth_fns = get_auth_subdissector_fns(
2366                          auth_info->auth_level, auth_info->auth_type))) {
2367                     tvbuff_t *result;
2368                     
2369                     result = decode_encrypted_data(
2370                             payload_tvb, pinfo, auth_fns,
2371                             hdr->ptype == PDU_REQ, auth_info);      
2372                     
2373                     if (result) {
2374                             int len = tvb_length(result);
2375
2376                             add_new_data_source(
2377                                     pinfo, result, "Decrypted Stub Data");
2378                             
2379                             pinfo->decrypted_data = result;
2380
2381                             proto_tree_add_text(
2382                                     dcerpc_tree, result, 0, len,
2383                                     "Decrypted Stub Data (%d byte%s)",
2384                                     len, plurality(len, "", "s"));
2385                     } else
2386                             payload_ok = FALSE;
2387             }
2388     }
2389
2390     /* if this packet is not fragmented, just dissect it and exit */
2391     if(PFC_NOT_FRAGMENTED(hdr)){
2392         pinfo->fragmented = FALSE;
2393
2394         dcerpc_try_handoff(
2395                 pinfo, tree, dcerpc_tree, 
2396                 pinfo->decrypted_data ? pinfo->decrypted_data : payload_tvb, 
2397                 0, hdr->drep, di, auth_info);
2398         
2399         pinfo->fragmented = save_fragmented;
2400         return;
2401     }
2402
2403     /* The packet is fragmented. */
2404     pinfo->fragmented = TRUE;
2405
2406     /* if we are not doing reassembly and this is the first fragment
2407        then just dissect it and exit
2408     */
2409     if( (!dcerpc_reassemble) && hdr->flags&PFC_FIRST_FRAG ){
2410
2411         dcerpc_try_handoff(
2412                 pinfo, tree, dcerpc_tree,
2413                 pinfo->decrypted_data ? pinfo->decrypted_data : 
2414                 payload_tvb, 0, hdr->drep, di, auth_info);
2415         
2416         if (check_col(pinfo->cinfo, COL_INFO)) {
2417             col_append_fstr(pinfo->cinfo, COL_INFO,
2418                             " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
2419         }
2420         pinfo->fragmented = save_fragmented;
2421         return;
2422     }
2423
2424     /* Replace encrypted payload with decrypted version for reassembly. */
2425
2426     if (pinfo->decrypted_data)
2427             payload_tvb = (tvbuff_t *)pinfo->decrypted_data;
2428
2429     /* if we have already seen this packet, see if it was reassembled
2430        and if so dissect the full pdu.
2431        then exit 
2432     */
2433     if(pinfo->fd->flags.visited){
2434         fd_head=fragment_get(pinfo, frame, dcerpc_co_reassemble_table);
2435         goto end_cn_stub;
2436     }
2437
2438     /* if we are not doing reassembly and it was neither a complete PDU
2439        nor the first fragment then there is nothing more we can do
2440        so we just have to exit
2441     */
2442     if( !dcerpc_reassemble )
2443         goto end_cn_stub;
2444
2445     /* if we didnt get 'frame' we dont know where the PDU started and thus
2446        it is pointless to continue 
2447     */
2448     if(!frame)
2449         goto end_cn_stub;
2450
2451     /* from now on we must attempt to reassemble the PDU 
2452     */
2453
2454     /* if we get here we know it is the first time we see the packet
2455        and we also know it is only a fragment and not a full PDU,
2456        thus we must reassemble it.
2457     */
2458
2459     /* if this is the first fragment we need to start reassembly
2460     */
2461     if(hdr->flags&PFC_FIRST_FRAG){
2462         fragment_add(payload_tvb, 0, pinfo, frame, dcerpc_co_reassemble_table,
2463                      0, tvb_length(payload_tvb), TRUE);
2464         fragment_set_tot_len(pinfo, frame,
2465                  dcerpc_co_reassemble_table, alloc_hint);
2466
2467         goto end_cn_stub;
2468     }
2469
2470     /* if this is a middle fragment, just add it and exit */
2471     if(!(hdr->flags&PFC_LAST_FRAG)){
2472         tot_len = fragment_get_tot_len(pinfo, frame,
2473                  dcerpc_co_reassemble_table);
2474         fragment_add(payload_tvb, 0, pinfo, frame,
2475                  dcerpc_co_reassemble_table,
2476                  tot_len-alloc_hint, tvb_length(payload_tvb),
2477                  TRUE);
2478
2479         goto end_cn_stub;
2480     }
2481
2482     /* this was the last fragment add it to reassembly
2483     */
2484     tot_len = fragment_get_tot_len(pinfo, frame,
2485                 dcerpc_co_reassemble_table);
2486     fd_head = fragment_add(payload_tvb, 0, pinfo,
2487                 frame,
2488                 dcerpc_co_reassemble_table,
2489                 tot_len-alloc_hint, tvb_length(payload_tvb),
2490                 TRUE);
2491
2492 end_cn_stub:
2493
2494     /* if reassembly is complete, dissect the full PDU
2495     */
2496     if(fd_head && (fd_head->flags&FD_DEFRAGMENTED) ){
2497
2498         if(pinfo->fd->num==fd_head->reassembled_in){
2499             tvbuff_t *next_tvb;
2500
2501             next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
2502             tvb_set_child_real_data_tvbuff(payload_tvb, next_tvb);
2503             add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
2504             show_fragment_tree(fd_head, &dcerpc_frag_items,
2505                 dcerpc_tree, pinfo, next_tvb);
2506
2507             pinfo->fragmented = FALSE;
2508
2509             dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
2510                 0, hdr->drep, di, auth_info);
2511
2512         } else {
2513             proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in, payload_tvb, 0, 0, 
2514                                 fd_head->reassembled_in);
2515             if (check_col(pinfo->cinfo, COL_INFO)) {
2516                 col_append_fstr(pinfo->cinfo, COL_INFO,
2517                         " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
2518             }
2519         }
2520     } else {
2521         /* Reassembly not complete - some fragments
2522            are missing */
2523
2524         if (check_col(pinfo->cinfo, COL_INFO)) {
2525             col_append_fstr(pinfo->cinfo, COL_INFO,
2526                         " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
2527         }
2528     }
2529
2530     pinfo->fragmented = save_fragmented;
2531 }
2532
2533 static void
2534 dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo, 
2535                         proto_tree *dcerpc_tree, proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
2536 {
2537     conversation_t *conv;
2538     guint16 ctx_id;
2539     guint16 opnum;
2540     e_uuid_t obj_id;
2541     dcerpc_auth_info auth_info;
2542     guint32 alloc_hint;
2543     char uuid_str[DCERPC_UUID_STR_LEN]; 
2544     int uuid_str_len;
2545
2546     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2547                                     hf_dcerpc_cn_alloc_hint, &alloc_hint);
2548
2549     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2550                                     hf_dcerpc_cn_ctx_id, &ctx_id);
2551
2552     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2553                                     hf_dcerpc_opnum, &opnum);
2554
2555     if (check_col (pinfo->cinfo, COL_INFO)) {
2556         col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u ctx_id: %u",
2557                          opnum, ctx_id);
2558     }
2559
2560     if (hdr->flags & PFC_OBJECT_UUID) {
2561         /* XXX - use "dissect_ndr_uuid_t()"? */
2562         dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id);
2563         if (dcerpc_tree) {
2564             uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, 
2565                                     "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2566                                     obj_id.Data1, obj_id.Data2, obj_id.Data3,
2567                                     obj_id.Data4[0],
2568                                     obj_id.Data4[1],
2569                                     obj_id.Data4[2],
2570                                     obj_id.Data4[3],
2571                                     obj_id.Data4[4],
2572                                     obj_id.Data4[5],
2573                                     obj_id.Data4[6],
2574                                     obj_id.Data4[7]);
2575             if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2576                   memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2577             proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
2578                                           offset, 16, uuid_str, "Object UUID: %s", uuid_str);
2579         }
2580         offset += 16;
2581     }
2582
2583     /*
2584      * XXX - what if this was set when the connection was set up,
2585      * and we just have a security context?
2586      */
2587     dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
2588     dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
2589
2590     conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2591                               pinfo->srcport, pinfo->destport, 0);
2592     if (!conv)
2593         show_stub_data (tvb, offset, dcerpc_tree, &auth_info);
2594     else {
2595         dcerpc_matched_key matched_key, *new_matched_key;
2596         dcerpc_call_value *value;
2597
2598         /* !!! we can NOT check flags.visited here since this will interact
2599            badly with when SMB handles (i.e. calls the subdissector)
2600            and desegmented pdu's .
2601            Instead we check if this pdu is already in the matched table or not
2602         */
2603         matched_key.frame = pinfo->fd->num;
2604         matched_key.call_id = hdr->call_id;
2605         value = g_hash_table_lookup(dcerpc_matched, &matched_key);
2606         if(!value){
2607                 dcerpc_bind_key bind_key;
2608                 dcerpc_bind_value *bind_value;
2609
2610                 bind_key.conv=conv;
2611                 bind_key.ctx_id=ctx_id;
2612                 bind_key.smb_fid=get_smb_fid(pinfo->private_data);
2613
2614                 if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key)) ){
2615                         if(!(hdr->flags&PFC_FIRST_FRAG)){
2616                                 dcerpc_call_key call_key;
2617                                 dcerpc_call_value *call_value;
2618
2619                                 call_key.conv=conv;
2620                                 call_key.call_id=hdr->call_id;
2621                                 call_key.smb_fid=get_smb_fid(pinfo->private_data);
2622                                 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
2623                                         new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
2624                                         *new_matched_key = matched_key;
2625                                         g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
2626                                         value = call_value;
2627                                 }
2628                         } else {
2629                                 dcerpc_call_key *call_key;
2630                                 dcerpc_call_value *call_value;
2631
2632                                 /* We found the binding and it is the first fragment 
2633                                    (or a complete PDU) of a dcerpc pdu so just add 
2634                                    the call to both the call table and the 
2635                                    matched table
2636                                 */
2637                                 call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
2638                                 call_key->conv=conv;
2639                                 call_key->call_id=hdr->call_id;
2640                                 call_key->smb_fid=get_smb_fid(pinfo->private_data);
2641
2642                                 /* if there is already a matching call in the table
2643                                    remove it so it is replaced with the new one */
2644                                 if(g_hash_table_lookup(dcerpc_calls, call_key)){
2645                                         g_hash_table_remove(dcerpc_calls, call_key);
2646                                 }
2647
2648                                 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
2649                                 call_value->uuid = bind_value->uuid;
2650                                 call_value->ver = bind_value->ver;
2651                                 call_value->opnum = opnum;
2652                                 call_value->req_frame=pinfo->fd->num;
2653                                 call_value->req_time.secs=pinfo->fd->abs_secs;
2654                                 call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000;
2655                                 call_value->rep_frame=0;
2656                                 call_value->max_ptr=0;
2657                                 call_value->private_data = NULL;
2658                                 g_hash_table_insert (dcerpc_calls, call_key, call_value);
2659
2660                                 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
2661                                 *new_matched_key = matched_key;
2662                                 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
2663                                 value = call_value;
2664                         }
2665                 }
2666         }
2667
2668         if (value) {
2669             dcerpc_info *di;
2670
2671             di=get_next_di();
2672             /* handoff this call */
2673             di->conv = conv;
2674             di->call_id = hdr->call_id;
2675             di->smb_fid = get_smb_fid(pinfo->private_data);
2676             di->request = TRUE;
2677             di->call_data = value;
2678                 di->hf_index = -1;
2679
2680             if(value->rep_frame!=0){
2681                 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
2682                                     tvb, 0, 0, value->rep_frame);
2683             }
2684
2685             dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
2686                                     hdr, di, &auth_info, alloc_hint,
2687                                     value->req_frame);
2688         } else
2689             show_stub_data (tvb, offset, dcerpc_tree, &auth_info);
2690     }
2691 }
2692
2693 static void
2694 dissect_dcerpc_cn_resp (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2695                         proto_tree *dcerpc_tree, proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
2696 {
2697     dcerpc_call_value *value = NULL;
2698     conversation_t *conv;
2699     guint16 ctx_id;
2700     dcerpc_auth_info auth_info;
2701     guint32 alloc_hint;
2702
2703     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2704                                     hf_dcerpc_cn_alloc_hint, &alloc_hint);
2705
2706     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2707                                     hf_dcerpc_cn_ctx_id, &ctx_id);
2708
2709     if (check_col (pinfo->cinfo, COL_INFO)) {
2710         col_append_fstr (pinfo->cinfo, COL_INFO, " ctx_id: %u", ctx_id);
2711     }
2712
2713     offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2714                                    hf_dcerpc_cn_cancel_count, NULL);
2715     /* padding */
2716     offset++;
2717
2718     /*
2719      * XXX - what if this was set when the connection was set up,
2720      * and we just have a security context?
2721      */
2722     dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
2723     dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
2724
2725     conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2726                               pinfo->srcport, pinfo->destport, 0);
2727
2728     if (!conv) {
2729         /* no point in creating one here, really */
2730         show_stub_data (tvb, offset, dcerpc_tree, &auth_info);
2731     } else {
2732         dcerpc_matched_key matched_key, *new_matched_key;
2733
2734         /* !!! we can NOT check flags.visited here since this will interact
2735            badly with when SMB handles (i.e. calls the subdissector)
2736            and desegmented pdu's .
2737            Instead we check if this pdu is already in the matched table or not
2738         */
2739         matched_key.frame = pinfo->fd->num;
2740         matched_key.call_id = hdr->call_id;
2741         value=g_hash_table_lookup(dcerpc_matched, &matched_key);
2742         if(!value){
2743                 dcerpc_call_key call_key;
2744                 dcerpc_call_value *call_value;
2745
2746                 call_key.conv=conv;
2747                 call_key.call_id=hdr->call_id;
2748                 call_key.smb_fid=get_smb_fid(pinfo->private_data);
2749
2750                 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
2751                         new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
2752                         *new_matched_key = matched_key;
2753                         g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
2754                         value = call_value;
2755                         if(call_value->rep_frame==0){
2756                                 call_value->rep_frame=pinfo->fd->num;
2757                         }
2758                 }
2759         }
2760
2761         if (value) {
2762             dcerpc_info *di;
2763
2764             di=get_next_di();
2765             /* handoff this call */
2766             di->conv = conv;
2767             di->call_id = hdr->call_id;
2768             di->smb_fid = get_smb_fid(pinfo->private_data);
2769             di->request = FALSE;
2770             di->call_data = value;
2771
2772             proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
2773             if(value->req_frame!=0){
2774                 nstime_t ns;
2775                 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
2776                                     tvb, 0, 0, value->req_frame);
2777                 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
2778                 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
2779                 if(ns.nsecs<0){
2780                         ns.nsecs+=1000000000;
2781                         ns.secs--;
2782                 }
2783                 proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
2784             }
2785
2786             dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
2787                                     hdr, di, &auth_info, alloc_hint,
2788                                     value->rep_frame);
2789         } else
2790             show_stub_data (tvb, offset, dcerpc_tree, &auth_info);
2791     }
2792 }
2793
2794 static void
2795 dissect_dcerpc_cn_fault (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2796                          proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2797 {
2798     dcerpc_call_value *value = NULL;
2799     conversation_t *conv;
2800     guint16 ctx_id;
2801     guint32 status;
2802     guint32 alloc_hint;
2803     dcerpc_auth_info auth_info;
2804
2805     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2806                                     hf_dcerpc_cn_alloc_hint, &alloc_hint);
2807
2808     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2809                                     hf_dcerpc_cn_ctx_id, &ctx_id);
2810
2811     offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2812                                    hf_dcerpc_cn_cancel_count, NULL);
2813     /* padding */
2814     offset++;
2815
2816     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2817                                     hf_dcerpc_cn_status, &status);
2818
2819     if (check_col (pinfo->cinfo, COL_INFO)) {
2820         col_append_fstr (pinfo->cinfo, COL_INFO,
2821                       " ctx_id: %u status: %s", ctx_id,
2822                       val_to_str(status, reject_status_vals,
2823                                  "Unknown (0x%08x)"));
2824     }
2825
2826     /* padding */
2827     offset += 4;
2828
2829     /*
2830      * XXX - what if this was set when the connection was set up,
2831      * and we just have a security context?
2832      */
2833     dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
2834
2835     conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2836                               pinfo->srcport, pinfo->destport, 0);
2837     if (!conv) {
2838         /* no point in creating one here, really */
2839     } else {
2840         dcerpc_matched_key matched_key, *new_matched_key;
2841
2842         /* !!! we can NOT check flags.visited here since this will interact
2843            badly with when SMB handles (i.e. calls the subdissector)
2844            and desegmented pdu's .
2845            Instead we check if this pdu is already in the matched table or not
2846         */
2847         matched_key.frame = pinfo->fd->num;
2848         matched_key.call_id = hdr->call_id;
2849         value=g_hash_table_lookup(dcerpc_matched, &matched_key);
2850         if(!value){
2851                 dcerpc_call_key call_key;
2852                 dcerpc_call_value *call_value;
2853
2854                 call_key.conv=conv;
2855                 call_key.call_id=hdr->call_id;
2856                 call_key.smb_fid=get_smb_fid(pinfo->private_data);
2857
2858                 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
2859                         new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
2860                         *new_matched_key = matched_key;
2861                         g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
2862                         value = call_value;
2863                         if(call_value->rep_frame==0){
2864                                 call_value->rep_frame=pinfo->fd->num;
2865                         }
2866
2867                 }
2868         }
2869
2870         if (value) {
2871             int length, reported_length, stub_length;
2872             dcerpc_info *di;
2873
2874             di=get_next_di();
2875             /* handoff this call */
2876             di->conv = conv;
2877             di->call_id = hdr->call_id;
2878             di->smb_fid = get_smb_fid(pinfo->private_data);
2879             di->request = FALSE;
2880             di->call_data = value;
2881
2882             proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
2883             if(value->req_frame!=0){
2884                 nstime_t ns;
2885                 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
2886                                     tvb, 0, 0, value->req_frame);
2887                 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
2888                 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
2889                 if(ns.nsecs<0){
2890                         ns.nsecs+=1000000000;
2891                         ns.secs--;
2892                 }
2893                 proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
2894             }
2895
2896             length = tvb_length_remaining(tvb, offset);
2897             reported_length = tvb_reported_length_remaining(tvb, offset);
2898             stub_length = hdr->frag_len - offset - auth_info.auth_size;
2899             if (length > stub_length)
2900               length = stub_length;
2901             if (reported_length > stub_length)
2902               reported_length = stub_length;
2903
2904             /* If we don't have reassembly enabled, or this packet contains
2905                the entire PDU, or if we don't have all the data in this
2906                fragment, just call the handoff directly if this is the
2907                first fragment or the PDU isn't fragmented. */
2908             if( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
2909                         !tvb_bytes_exist(tvb, offset, stub_length) ){
2910                 if(hdr->flags&PFC_FIRST_FRAG){
2911                     /* First fragment, possibly the only fragment */
2912                     /*
2913                      * XXX - should there be a third routine for each
2914                      * function in an RPC subdissector, to handle
2915                      * fault responses?  The DCE RPC 1.1 spec says
2916                      * three's "stub data" here, which I infer means
2917                      * that it's protocol-specific and call-specific.
2918                      *
2919                      * It should probably get passed the status code
2920                      * as well, as that might be protocol-specific.
2921                      */
2922                     if (dcerpc_tree) {
2923                         if (stub_length > 0) {
2924                             proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
2925                                                  "Fault stub data (%d byte%s)",
2926                                                  stub_length,
2927                                                  plurality(stub_length, "", "s"));
2928                         }
2929                     }
2930                 } else {
2931                     /* PDU is fragmented and this isn't the first fragment */
2932                     if (check_col(pinfo->cinfo, COL_INFO)) {
2933                         col_append_fstr(pinfo->cinfo, COL_INFO,
2934                                         " [DCE/RPC fragment]");
2935                     }
2936                     if (dcerpc_tree) {
2937                         if (stub_length > 0) {
2938                             proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
2939                                                  "Fragment data (%d byte%s)",
2940                                                  stub_length,
2941                                                  plurality(stub_length, "", "s"));
2942                         }
2943                     }
2944                 }
2945             } else {
2946                 /* Reassembly is enabled, the PDU is fragmented, and
2947                    we have all the data in the fragment; the first two
2948                    of those mean we should attempt reassembly, and the
2949                    third means we can attempt reassembly. */
2950                 if (dcerpc_tree) {
2951                     if (length > 0) {
2952                         proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
2953                                              "Fragment data (%d byte%s)",
2954                                              stub_length,
2955                                              plurality(stub_length, "", "s"));
2956                     }
2957                 }
2958                 if(hdr->flags&PFC_FIRST_FRAG){  /* FIRST fragment */
2959                     if( (!pinfo->fd->flags.visited) && value->rep_frame ){
2960                         fragment_add(tvb, offset, pinfo, value->rep_frame,
2961                              dcerpc_co_reassemble_table,
2962                              0,
2963                              stub_length,
2964                              TRUE);
2965                         fragment_set_tot_len(pinfo, value->rep_frame,
2966                              dcerpc_co_reassemble_table, alloc_hint);
2967                     }
2968                     if (check_col(pinfo->cinfo, COL_INFO)) {
2969                         col_append_fstr(pinfo->cinfo, COL_INFO,
2970                                         " [DCE/RPC fragment]");
2971                     }
2972                 } else if(hdr->flags&PFC_LAST_FRAG){  /* LAST fragment */
2973                     if( value->rep_frame ){
2974                         fragment_data *fd_head;
2975                         guint32 tot_len;
2976
2977                         tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
2978                                        dcerpc_co_reassemble_table);
2979                         fd_head = fragment_add(tvb, offset, pinfo,
2980                              value->rep_frame,
2981                              dcerpc_co_reassemble_table,
2982                              tot_len-alloc_hint,
2983                              stub_length,
2984                              TRUE);
2985
2986                         if(fd_head){
2987                             /* We completed reassembly */
2988                             tvbuff_t *next_tvb;
2989
2990                             next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
2991                             tvb_set_child_real_data_tvbuff(tvb, next_tvb);
2992                             add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
2993                             show_fragment_tree(fd_head, &dcerpc_frag_items,
2994                                 dcerpc_tree, pinfo, next_tvb);
2995
2996                             /*
2997                              * XXX - should there be a third routine for each
2998                              * function in an RPC subdissector, to handle
2999                              * fault responses?  The DCE RPC 1.1 spec says
3000                              * three's "stub data" here, which I infer means
3001                              * that it's protocol-specific and call-specific.
3002                              *
3003                              * It should probably get passed the status code
3004                              * as well, as that might be protocol-specific.
3005                              */
3006                             if (dcerpc_tree) {
3007                                 if (length > 0) {
3008                                      proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3009                                                           "Fault stub data (%d byte%s)",
3010                                                           stub_length,
3011                                                           plurality(stub_length, "", "s"));
3012                                 }
3013                             }
3014                         } else {
3015                             /* Reassembly not complete - some fragments
3016                                are missing */
3017                             if (check_col(pinfo->cinfo, COL_INFO)) {
3018                                 col_append_fstr(pinfo->cinfo, COL_INFO,
3019                                                 " [DCE/RPC fragment]");
3020                             }
3021                         }
3022                     }
3023                 } else {  /* MIDDLE fragment(s) */
3024                     if( (!pinfo->fd->flags.visited) && value->rep_frame ){
3025                         guint32 tot_len;
3026                         tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
3027                                        dcerpc_co_reassemble_table);
3028                         fragment_add(tvb, offset, pinfo, value->rep_frame,
3029                              dcerpc_co_reassemble_table,
3030                              tot_len-alloc_hint,
3031                              stub_length,
3032                              TRUE);
3033                     }
3034                     if (check_col(pinfo->cinfo, COL_INFO)) {
3035                         col_append_fstr(pinfo->cinfo, COL_INFO,
3036                                         " [DCE/RPC fragment]");
3037                     }
3038                 }
3039             }
3040         }
3041     }
3042 }
3043
3044 /*
3045  * DCERPC dissector for connection oriented calls
3046  */
3047 static int
3048 dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
3049                    proto_tree *tree, gboolean can_desegment)
3050 {
3051     static char nulls[4] = { 0 };
3052     int start_offset;
3053     int padding = 0;
3054     proto_item *ti = NULL;
3055     proto_item *tf = NULL;
3056     proto_tree *dcerpc_tree = NULL;
3057     proto_tree *cn_flags_tree = NULL;
3058     proto_tree *drep_tree = NULL;
3059     e_dce_cn_common_hdr_t hdr;
3060     dcerpc_auth_info auth_info;
3061
3062     /*
3063      * when done over nbt, dcerpc requests are padded with 4 bytes of null
3064      * data for some reason.
3065      *
3066      * XXX - if that's always the case, the right way to do this would
3067      * be to have a "dissect_dcerpc_cn_nb" routine which strips off
3068      * the 4 bytes of null padding, and make that the dissector
3069      * used for "netbios".
3070      */
3071     if (tvb_memeql (tvb, offset, nulls, 4) == 0) {
3072
3073         /*
3074          * Skip the padding.
3075          */
3076         offset += 4;
3077         padding += 4;
3078     }
3079
3080     /*
3081      * Check if this looks like a C/O DCERPC call
3082      */
3083     if (!tvb_bytes_exist (tvb, offset, sizeof (hdr))) {
3084         return -1;
3085     }
3086     start_offset = offset;
3087     hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
3088     if (hdr.rpc_ver != 5)
3089         return -1;
3090     hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
3091     if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
3092         return -1;
3093     hdr.ptype = tvb_get_guint8 (tvb, offset++);
3094     if (hdr.ptype > 19)
3095         return -1;
3096
3097     hdr.flags = tvb_get_guint8 (tvb, offset++);
3098     tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
3099     offset += sizeof (hdr.drep);
3100
3101     hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3102     offset += 2;
3103     hdr.auth_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3104     offset += 2;
3105     hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3106     offset += 4;
3107
3108     if (can_desegment && pinfo->can_desegment
3109         && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
3110         pinfo->desegment_offset = start_offset;
3111         pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, start_offset);
3112         return 0;       /* desegmentation required */
3113     }
3114
3115     if (check_col (pinfo->cinfo, COL_PROTOCOL))
3116         col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
3117     if (check_col (pinfo->cinfo, COL_INFO))
3118         col_add_fstr (pinfo->cinfo, COL_INFO, "%s: call_id: %u",
3119             pckt_vals[hdr.ptype].strptr, hdr.call_id);
3120
3121     if (tree) {
3122       offset = start_offset;
3123         ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE);
3124         if (ti) {
3125             dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
3126         }
3127         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver);
3128         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset++, 1, hdr.rpc_ver_minor);
3129         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype);
3130         tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
3131         cn_flags_tree = proto_item_add_subtree (tf, ett_dcerpc_cn_flags);
3132         if (cn_flags_tree) {
3133             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
3134             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
3135             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
3136             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
3137             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
3138             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
3139             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
3140             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
3141         }
3142         offset++;
3143
3144         tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
3145         drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
3146         if (drep_tree) {
3147             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
3148             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
3149             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
3150         }
3151         offset += sizeof (hdr.drep);
3152
3153         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
3154         offset += 2;
3155
3156         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
3157         offset += 2;
3158
3159         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
3160         offset += 4;
3161     }
3162
3163     /*
3164      * Packet type specific stuff is next.
3165      */
3166     switch (hdr.ptype) {
3167     case PDU_BIND:
3168     case PDU_ALTER:
3169         dissect_dcerpc_cn_bind (tvb, offset, pinfo, dcerpc_tree, &hdr);
3170         break;
3171
3172     case PDU_BIND_ACK:
3173     case PDU_ALTER_ACK:
3174         dissect_dcerpc_cn_bind_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3175         break;
3176
3177     case PDU_AUTH3:
3178         /*
3179          * Nothing after the common header other than credentials.
3180          */
3181         dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, TRUE, 
3182                                 &auth_info);
3183         break;
3184
3185     case PDU_REQ:
3186         dissect_dcerpc_cn_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
3187         break;
3188
3189     case PDU_RESP:
3190         dissect_dcerpc_cn_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
3191         break;
3192
3193     case PDU_FAULT:
3194         dissect_dcerpc_cn_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
3195         break;
3196
3197     case PDU_BIND_NAK:
3198         dissect_dcerpc_cn_bind_nak (tvb, offset, pinfo, dcerpc_tree, &hdr);
3199         break;
3200
3201     case PDU_CO_CANCEL:
3202     case PDU_ORPHANED:
3203         /*
3204          * Nothing after the common header other than an authentication
3205          * verifier.
3206          */
3207         dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, FALSE, 
3208                                 &auth_info);
3209         break;
3210
3211     case PDU_SHUTDOWN:
3212         /*
3213          * Nothing after the common header, not even an authentication
3214          * verifier.
3215          */
3216         break;
3217
3218     default:
3219         /* might as well dissect the auth info */
3220         dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, FALSE, 
3221                                 &auth_info);
3222         break;
3223     }
3224     return hdr.frag_len + padding;
3225 }
3226
3227 /*
3228  * DCERPC dissector for connection oriented calls over packet-oriented
3229  * transports
3230  */
3231 static gboolean
3232 dissect_dcerpc_cn_pk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3233 {
3234     /*
3235      * Only one PDU per transport packet, and only one transport
3236      * packet per PDU.
3237      */
3238     if (dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE) == -1) {
3239         /*
3240          * It wasn't a DCERPC PDU.
3241          */
3242         return FALSE;
3243     } else {
3244         /*
3245          * It was.
3246          */
3247         return TRUE;
3248     }
3249 }
3250
3251 /*
3252  * DCERPC dissector for connection oriented calls over byte-stream
3253  * transports
3254  */
3255 static gboolean
3256 dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3257 {
3258     int offset = 0;
3259     int pdu_len;
3260     gboolean ret = FALSE;
3261
3262     /*
3263      * There may be multiple PDUs per transport packet; keep
3264      * processing them.
3265      */
3266     while (tvb_reported_length_remaining(tvb, offset) != 0) {
3267         pdu_len = dissect_dcerpc_cn (tvb, offset, pinfo, tree,
3268                                      dcerpc_cn_desegment);
3269         if (pdu_len == -1) {
3270             /*
3271              * Not a DCERPC PDU.
3272              */
3273             break;
3274         }
3275
3276         /*
3277          * Well, we've seen at least one DCERPC PDU.
3278          */
3279         ret = TRUE;
3280
3281         if (pdu_len == 0) {
3282             /*
3283              * Desegmentation required - bail now.
3284              */
3285             break;
3286         }
3287
3288         /*
3289          * Step to the next PDU.
3290          */
3291         offset += pdu_len;
3292     }
3293     return ret;
3294 }
3295
3296 static void
3297 dissect_dcerpc_dg_auth (tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
3298                         e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
3299 {
3300     proto_item *ti = NULL;
3301     proto_tree *auth_tree = NULL;
3302     guint8 protection_level;
3303
3304     /*
3305      * Initially set "*auth_level_p" to -1 to indicate that we haven't
3306      * yet seen any authentication level information.
3307      */
3308     if (auth_level_p != NULL)
3309         *auth_level_p = -1;
3310
3311     /*
3312      * The authentication information is at the *end* of the PDU; in
3313      * request and response PDUs, the request and response stub data
3314      * come before it.
3315      *
3316      * If the full packet is here, and there's data past the end of the
3317      * packet body, then dissect the auth info.
3318      */
3319     offset += hdr->frag_len;
3320     if (tvb_length_remaining(tvb, offset) > 0) {
3321         switch (hdr->auth_proto) {
3322
3323         case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
3324             ti = proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Kerberos authentication verifier");
3325             auth_tree = proto_item_add_subtree (ti, ett_dcerpc_krb5_auth_verf);
3326             protection_level = tvb_get_guint8 (tvb, offset);
3327             if (auth_level_p != NULL)
3328                 *auth_level_p = protection_level;
3329             proto_tree_add_uint (auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
3330             offset++;
3331             proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, FALSE);
3332             offset++;
3333             if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
3334                 offset += 6;    /* 6 bytes of padding */
3335             else
3336                 offset += 2;    /* 6 bytes of padding */
3337             proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, FALSE);
3338             offset += 16;
3339             break;
3340
3341         default:
3342             proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Authentication verifier");
3343             break;
3344         }
3345     }
3346 }
3347
3348 static void
3349 dissect_dcerpc_dg_cancel_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
3350                               proto_tree *dcerpc_tree,
3351                               e_dce_dg_common_hdr_t *hdr)
3352 {
3353     guint32 version;
3354
3355     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3356                                     hdr->drep, hf_dcerpc_dg_cancel_vers,
3357                                     &version);
3358
3359     switch (version) {
3360
3361     case 0:
3362         /* The only version we know about */
3363         offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3364                                         hdr->drep, hf_dcerpc_dg_cancel_id,
3365                                         NULL);
3366         offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
3367                                        hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
3368                                        NULL);
3369         break;
3370     }
3371 }
3372
3373 static void
3374 dissect_dcerpc_dg_cancel (tvbuff_t *tvb, int offset, packet_info *pinfo,
3375                           proto_tree *dcerpc_tree,
3376                           e_dce_dg_common_hdr_t *hdr)
3377 {
3378     guint32 version;
3379
3380     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3381                                     hdr->drep, hf_dcerpc_dg_cancel_vers,
3382                                     &version);
3383
3384     switch (version) {
3385
3386     case 0:
3387         /* The only version we know about */
3388         offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3389                                         hdr->drep, hf_dcerpc_dg_cancel_id,
3390                                         NULL);
3391         /* XXX - are NDR booleans 32 bits? */
3392         offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3393                                         hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
3394                                         NULL);
3395         break;
3396     }
3397 }
3398
3399 static void
3400 dissect_dcerpc_dg_fack (tvbuff_t *tvb, int offset, packet_info *pinfo,
3401                         proto_tree *dcerpc_tree,
3402                         e_dce_dg_common_hdr_t *hdr)
3403 {
3404     guint8 version;
3405     guint16 serial_num;
3406     guint16 selack_len;
3407     guint i;
3408
3409     offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
3410                                   hdr->drep, hf_dcerpc_dg_fack_vers,
3411                                   &version);
3412     /* padding */
3413     offset++;
3414
3415     switch (version) {
3416
3417     case 0:     /* The only version documented in the DCE RPC 1.1 spec */
3418     case 1:     /* This appears to be the same */
3419         offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
3420                                         hdr->drep, hf_dcerpc_dg_fack_window_size,
3421                                         NULL);
3422         offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3423                                         hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
3424                                         NULL);
3425         offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3426                                         hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
3427                                         NULL);
3428         offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
3429                                         hdr->drep, hf_dcerpc_dg_fack_serial_num,
3430                                         &serial_num);
3431         if (check_col (pinfo->cinfo, COL_INFO)) {
3432             col_append_fstr (pinfo->cinfo, COL_INFO, " serial_num: %u",
3433                              serial_num);
3434         }
3435         offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
3436                                         hdr->drep, hf_dcerpc_dg_fack_selack_len,
3437                                         &selack_len);
3438         for (i = 0; i < selack_len; i++) {
3439             offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3440                                             hdr->drep, hf_dcerpc_dg_fack_selack,
3441                                             NULL);
3442         }
3443
3444         break;
3445     }
3446 }
3447
3448 static void
3449 dissect_dcerpc_dg_reject_fault (tvbuff_t *tvb, int offset, packet_info *pinfo,
3450                         proto_tree *dcerpc_tree,
3451                         e_dce_dg_common_hdr_t *hdr)
3452 {
3453     guint32 status;
3454
3455     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3456                                     hdr->drep, hf_dcerpc_dg_status,
3457                                     &status);
3458
3459     if (check_col (pinfo->cinfo, COL_INFO)) {
3460         col_append_fstr (pinfo->cinfo, COL_INFO,
3461                       ": status: %s",
3462                       val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
3463     }
3464 }
3465
3466 static void
3467 dissect_dcerpc_dg_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
3468                         proto_tree *dcerpc_tree, proto_tree *tree,
3469                         e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
3470 {
3471     int length, reported_length, stub_length;
3472     gboolean save_fragmented;
3473     fragment_data *fd_head;
3474
3475     if (check_col (pinfo->cinfo, COL_INFO)) {
3476         col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u",
3477                          di->call_data->opnum);
3478     }
3479
3480     length = tvb_length_remaining (tvb, offset);
3481     reported_length = tvb_reported_length_remaining (tvb, offset);
3482     stub_length = hdr->frag_len;
3483     if (length > stub_length)
3484         length = stub_length;
3485     if (reported_length > stub_length)
3486         reported_length = stub_length;
3487
3488     save_fragmented = pinfo->fragmented;
3489
3490     /* If we don't have reassembly enabled, or this packet contains
3491        the entire PDU, or if this is a short frame (or a frame
3492        not reassembled at a lower layer) that doesn't include all
3493        the data in the fragment, just call the handoff directly if
3494        this is the first fragment or the PDU isn't fragmented. */
3495     if( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
3496                 !tvb_bytes_exist(tvb, offset, stub_length) ){
3497         if(hdr->frag_num == 0) {
3498             /* First fragment, possibly the only fragment */
3499
3500             /*
3501              * XXX - authentication info?
3502              */
3503             pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
3504             dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
3505                                 tvb_new_subset (tvb, offset, length,
3506                                                 reported_length),
3507                                 0, hdr->drep, di, NULL);
3508         } else {
3509             /* PDU is fragmented and this isn't the first fragment */
3510             if (check_col(pinfo->cinfo, COL_INFO)) {
3511                 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
3512             }
3513             if (dcerpc_tree) {
3514                 if (length > 0) {
3515                     proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3516                                          "Fragment data (%d byte%s)",
3517                                          stub_length,
3518                                          plurality(stub_length, "", "s"));
3519                 }
3520             }
3521         }
3522     } else {
3523         /* Reassembly is enabled, the PDU is fragmented, and
3524            we have all the data in the fragment; the first two
3525            of those mean we should attempt reassembly, and the
3526            third means we can attempt reassembly. */
3527         if (dcerpc_tree) {
3528             if (length > 0) {
3529                 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3530                                      "Fragment data (%d byte%s)", stub_length,
3531                                      plurality(stub_length, "", "s"));
3532             }
3533         }
3534
3535         fd_head = fragment_add_seq(tvb, offset, pinfo,
3536                         hdr->seqnum, dcerpc_cl_reassemble_table,
3537                         hdr->frag_num, stub_length,
3538                         !(hdr->flags1 & PFCL1_LASTFRAG));
3539         if (fd_head != NULL) {
3540             /* We completed reassembly */
3541             tvbuff_t *next_tvb;
3542
3543             next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
3544             tvb_set_child_real_data_tvbuff(tvb, next_tvb);
3545             add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3546             show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
3547                                    dcerpc_tree, pinfo, next_tvb);
3548
3549             /*
3550              * XXX - authentication info?
3551              */
3552             pinfo->fragmented = FALSE;
3553             dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
3554                                 0, hdr->drep, di, NULL);
3555         } else {
3556             /* Reassembly isn't completed yet */
3557             if (check_col(pinfo->cinfo, COL_INFO)) {
3558                 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
3559             }
3560         }
3561     }
3562     pinfo->fragmented = save_fragmented;
3563 }
3564
3565 static void
3566 dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo,
3567                         proto_tree *dcerpc_tree, proto_tree *tree,
3568                         e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
3569 {
3570     dcerpc_info *di;
3571     dcerpc_call_value *value, v;
3572     dcerpc_matched_key matched_key, *new_matched_key;
3573
3574     di=get_next_di();
3575     if(!(pinfo->fd->flags.visited)){
3576         dcerpc_call_value *call_value;
3577         dcerpc_call_key *call_key;
3578
3579         call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
3580         call_key->conv=conv;
3581         call_key->call_id=hdr->seqnum;
3582         call_key->smb_fid=get_smb_fid(pinfo->private_data);
3583
3584         call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
3585         call_value->uuid = hdr->if_id;
3586         call_value->ver = hdr->if_ver;
3587         call_value->opnum = hdr->opnum;
3588         call_value->req_frame=pinfo->fd->num;
3589         call_value->req_time.secs=pinfo->fd->abs_secs;
3590         call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000;
3591         call_value->rep_frame=0;
3592         call_value->max_ptr=0;
3593         call_value->private_data = NULL;
3594         g_hash_table_insert (dcerpc_calls, call_key, call_value);
3595
3596         new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3597         new_matched_key->frame = pinfo->fd->num;
3598         new_matched_key->call_id = hdr->seqnum;
3599         g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3600     }
3601
3602     matched_key.frame = pinfo->fd->num;
3603     matched_key.call_id = hdr->seqnum;
3604     value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3605     if (!value) {
3606         v.uuid = hdr->if_id;
3607         v.ver = hdr->if_ver;
3608         v.opnum = hdr->opnum;
3609         v.req_frame = pinfo->fd->num;
3610         v.rep_frame = 0;
3611         v.max_ptr = 0;
3612         v.private_data=NULL;
3613         value = &v;
3614     }
3615
3616     di->conv = conv;
3617     di->call_id = hdr->seqnum;
3618     di->smb_fid = -1;
3619     di->request = TRUE;
3620     di->call_data = value;
3621
3622     if(value->rep_frame!=0){
3623         proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
3624                             tvb, 0, 0, value->rep_frame);
3625     }
3626     dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
3627 }
3628
3629 static void
3630 dissect_dcerpc_dg_resp (tvbuff_t *tvb, int offset, packet_info *pinfo,
3631                         proto_tree *dcerpc_tree, proto_tree *tree,
3632                         e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
3633 {
3634     dcerpc_info *di;
3635     dcerpc_call_value *value, v;
3636     dcerpc_matched_key matched_key, *new_matched_key;
3637
3638     di=get_next_di();
3639     if(!(pinfo->fd->flags.visited)){
3640         dcerpc_call_value *call_value;
3641         dcerpc_call_key call_key;
3642
3643         call_key.conv=conv;
3644         call_key.call_id=hdr->seqnum;
3645         call_key.smb_fid=get_smb_fid(pinfo->private_data);
3646
3647         if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
3648             new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3649             new_matched_key->frame = pinfo->fd->num;
3650             new_matched_key->call_id = hdr->seqnum;
3651             g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3652             if(call_value->rep_frame==0){
3653                 call_value->rep_frame=pinfo->fd->num;
3654             }
3655         }
3656     }
3657
3658     matched_key.frame = pinfo->fd->num;
3659     matched_key.call_id = hdr->seqnum;
3660     value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3661     if (!value) {
3662         v.uuid = hdr->if_id;
3663         v.ver = hdr->if_ver;
3664         v.opnum = hdr->opnum;
3665         v.req_frame=0;
3666         v.rep_frame=pinfo->fd->num;
3667         v.private_data=NULL;
3668         value = &v;
3669     }
3670
3671     di->conv = conv;
3672     di->call_id = 0;
3673     di->smb_fid = -1;
3674     di->request = FALSE;
3675     di->call_data = value;
3676
3677     if(value->req_frame!=0){
3678         nstime_t ns;
3679         proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3680                             tvb, 0, 0, value->req_frame);
3681         ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
3682         ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
3683         if(ns.nsecs<0){
3684                 ns.nsecs+=1000000000;
3685                 ns.secs--;
3686         }
3687         proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
3688     }
3689     dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
3690 }
3691
3692 /*
3693  * DCERPC dissector for connectionless calls
3694  */
3695 static gboolean
3696 dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3697 {
3698     proto_item *ti = NULL;
3699     proto_item *tf = NULL;
3700     proto_tree *dcerpc_tree = NULL;
3701     proto_tree *dg_flags1_tree = NULL;
3702     proto_tree *dg_flags2_tree = NULL;
3703     proto_tree *drep_tree = NULL;
3704     e_dce_dg_common_hdr_t hdr;
3705     int offset = 0;
3706     conversation_t *conv;
3707     int auth_level;
3708     char uuid_str[DCERPC_UUID_STR_LEN]; 
3709     int uuid_str_len;
3710
3711     /*
3712      * Check if this looks like a CL DCERPC call.  All dg packets
3713      * have an 80 byte header on them.  Which starts with
3714      * version (4), pkt_type.
3715      */
3716     if (!tvb_bytes_exist (tvb, 0, sizeof (hdr))) {
3717         return FALSE;
3718     }
3719     hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
3720     if (hdr.rpc_ver != 4)
3721         return FALSE;
3722     hdr.ptype = tvb_get_guint8 (tvb, offset++);
3723     if (hdr.ptype > 19)
3724         return FALSE;
3725
3726     if (check_col (pinfo->cinfo, COL_PROTOCOL))
3727         col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
3728     if (check_col (pinfo->cinfo, COL_INFO))
3729         col_add_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
3730
3731     hdr.flags1 = tvb_get_guint8 (tvb, offset++);
3732     hdr.flags2 = tvb_get_guint8 (tvb, offset++);
3733     tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
3734     offset += sizeof (hdr.drep);
3735     hdr.serial_hi = tvb_get_guint8 (tvb, offset++);
3736     dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.obj_id);
3737     offset += 16;
3738     dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.if_id);
3739     offset += 16;
3740     dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.act_id);
3741     offset += 16;
3742     hdr.server_boot = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3743     offset += 4;
3744     hdr.if_ver = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3745     offset += 4;
3746     hdr.seqnum = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3747     offset += 4;
3748     hdr.opnum = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3749     offset += 2;
3750     hdr.ihint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3751     offset += 2;
3752     hdr.ahint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3753     offset += 2;
3754     hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3755     offset += 2;
3756     hdr.frag_num = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3757     offset += 2;
3758     hdr.auth_proto = tvb_get_guint8 (tvb, offset++);
3759     hdr.serial_lo = tvb_get_guint8 (tvb, offset++);
3760
3761     if (tree) {
3762         ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, -1, FALSE);
3763         if (ti) {
3764             dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
3765         }
3766     }
3767     offset = 0;
3768
3769     if (tree)
3770         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
3771     offset++;
3772
3773     if (tree)
3774         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
3775     offset++;
3776
3777     if (tree) {
3778         tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
3779         dg_flags1_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags1);
3780         if (dg_flags1_tree) {
3781             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
3782             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
3783             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
3784             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
3785             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
3786             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
3787             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
3788             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
3789         }
3790     }
3791     offset++;
3792
3793     if (tree) {
3794         tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
3795         dg_flags2_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags2);
3796         if (dg_flags2_tree) {
3797             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
3798             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
3799             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
3800             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
3801             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
3802             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
3803             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
3804             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
3805         }
3806     }
3807     offset++;
3808
3809     if (tree) {
3810         tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
3811         drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
3812         if (drep_tree) {
3813             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
3814             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
3815             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
3816         }
3817     }
3818     offset += sizeof (hdr.drep);
3819
3820     if (tree)
3821         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
3822     offset++;
3823
3824     if (tree) {
3825         /* XXX - use "dissect_ndr_uuid_t()"? */
3826         uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, 
3827                                 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3828                                 hdr.obj_id.Data1, hdr.obj_id.Data2, hdr.obj_id.Data3,
3829                                 hdr.obj_id.Data4[0],
3830                                 hdr.obj_id.Data4[1],
3831                                 hdr.obj_id.Data4[2],
3832                                 hdr.obj_id.Data4[3],
3833                                 hdr.obj_id.Data4[4],
3834                                 hdr.obj_id.Data4[5],
3835                                 hdr.obj_id.Data4[6],
3836                                 hdr.obj_id.Data4[7]);
3837         if (uuid_str_len >= DCERPC_UUID_STR_LEN)
3838                 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
3839         proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
3840                                       offset, 16, uuid_str, "Object UUID: %s", uuid_str);
3841     }
3842     offset += 16;
3843
3844     if (tree) {
3845         /* XXX - use "dissect_ndr_uuid_t()"? */
3846         uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, 
3847                                 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3848                                 hdr.if_id.Data1, hdr.if_id.Data2, hdr.if_id.Data3,
3849                                 hdr.if_id.Data4[0],
3850                                 hdr.if_id.Data4[1],
3851                                 hdr.if_id.Data4[2],
3852                                 hdr.if_id.Data4[3],
3853                                 hdr.if_id.Data4[4],
3854                                 hdr.if_id.Data4[5],
3855                                 hdr.if_id.Data4[6],
3856                                 hdr.if_id.Data4[7]);
3857         if (uuid_str_len >= DCERPC_UUID_STR_LEN)
3858                 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
3859         proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
3860                                       offset, 16, uuid_str, "Interface: %s", uuid_str);
3861     }
3862     offset += 16;
3863
3864     if (tree) {
3865         /* XXX - use "dissect_ndr_uuid_t()"? */
3866         uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, 
3867                                 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3868                                 hdr.act_id.Data1, hdr.act_id.Data2, hdr.act_id.Data3,
3869                                 hdr.act_id.Data4[0],
3870                                 hdr.act_id.Data4[1],
3871                                 hdr.act_id.Data4[2],
3872                                 hdr.act_id.Data4[3],
3873                                 hdr.act_id.Data4[4],
3874                                 hdr.act_id.Data4[5],
3875                                 hdr.act_id.Data4[6],
3876                                 hdr.act_id.Data4[7]);
3877         if (uuid_str_len >= DCERPC_UUID_STR_LEN)
3878                 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
3879         proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
3880                                       offset, 16, uuid_str, "Activity: %s", uuid_str);
3881     }
3882     offset += 16;
3883
3884     if (tree)
3885         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_server_boot, tvb, offset, 4, hdr.server_boot);
3886     offset += 4;
3887
3888     if (tree)
3889         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
3890     offset += 4;
3891
3892     if (tree)
3893         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
3894     if (check_col (pinfo->cinfo, COL_INFO)) {
3895         col_append_fstr (pinfo->cinfo, COL_INFO, ": seq_num: %u", hdr.seqnum);
3896     }
3897     offset += 4;
3898
3899     if (tree)
3900         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
3901     offset += 2;
3902
3903     if (tree)
3904         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
3905     offset += 2;
3906
3907     if (tree)
3908         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
3909     offset += 2;
3910
3911     if (tree)
3912         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
3913     offset += 2;
3914
3915     if (tree)
3916         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
3917     if (check_col (pinfo->cinfo, COL_INFO)) {
3918         if (hdr.flags1 & PFCL1_FRAG) {
3919             /* Fragmented - put the fragment number into the Info column */
3920             col_append_fstr (pinfo->cinfo, COL_INFO, " frag_num: %u",
3921                              hdr.frag_num);
3922         }
3923     }
3924     offset += 2;
3925
3926     if (tree)
3927         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
3928     offset++;
3929
3930     if (tree)
3931         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
3932     if (check_col (pinfo->cinfo, COL_INFO)) {
3933         if (hdr.flags1 & PFCL1_FRAG) {
3934             /* Fragmented - put the serial number into the Info column */
3935             col_append_fstr (pinfo->cinfo, COL_INFO, " serial_num: %u",
3936                              (hdr.serial_hi << 8) | hdr.serial_lo);
3937         }
3938     }
3939     offset++;
3940
3941     if (tree) {
3942         /*
3943          * XXX - for Kerberos, we get a protection level; if it's
3944          * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
3945          * stub data.
3946          */
3947         dissect_dcerpc_dg_auth (tvb, offset, dcerpc_tree, &hdr,
3948                                 &auth_level);
3949     }
3950
3951     /*
3952      * keeping track of the conversation shouldn't really be necessary
3953      * for connectionless packets, because everything we need to know
3954      * to dissect is in the header for each packet.  Unfortunately,
3955      * Microsoft's implementation is buggy and often puts the
3956      * completely wrong if_id in the header.  go figure.  So, keep
3957      * track of the seqnum and use that if possible.  Note: that's not
3958      * completely correct.  It should really be done based on both the
3959      * activity_id and seqnum.  I haven't seen anywhere that it would
3960      * make a difference, but for future reference...
3961      */
3962     conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
3963                               pinfo->srcport, pinfo->destport, 0);
3964     if (!conv) {
3965         conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
3966                                  pinfo->srcport, pinfo->destport, 0);
3967     }
3968
3969     /*
3970      * Packet type specific stuff is next.
3971      */
3972
3973     switch (hdr.ptype) {
3974
3975     case PDU_CANCEL_ACK:
3976         /* Body is optional */
3977         /* XXX - we assume "frag_len" is the length of the body */
3978         if (hdr.frag_len != 0)
3979             dissect_dcerpc_dg_cancel_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3980         break;
3981
3982     case PDU_CL_CANCEL:
3983         /*
3984          * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
3985          * but in at least one capture none of the Cl_cancel PDUs had a
3986          * body.
3987          */
3988         /* XXX - we assume "frag_len" is the length of the body */
3989         if (hdr.frag_len != 0)
3990             dissect_dcerpc_dg_cancel (tvb, offset, pinfo, dcerpc_tree, &hdr);
3991         break;
3992
3993     case PDU_NOCALL:
3994         /* Body is optional; if present, it's the same as PDU_FACK */
3995         /* XXX - we assume "frag_len" is the length of the body */
3996         if (hdr.frag_len != 0)
3997             dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3998         break;
3999
4000     case PDU_FACK:
4001         dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
4002         break;
4003
4004     case PDU_REJECT:
4005     case PDU_FAULT:
4006         dissect_dcerpc_dg_reject_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
4007         break;
4008
4009     case PDU_REQ:
4010         dissect_dcerpc_dg_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
4011         break;
4012
4013     case PDU_RESP:
4014         dissect_dcerpc_dg_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
4015         break;
4016
4017     /* these requests have no body */
4018     case PDU_ACK:
4019     case PDU_PING:
4020     case PDU_WORKING:
4021     default:
4022         break;
4023     }
4024
4025     return TRUE;
4026 }
4027
4028 static void
4029 dcerpc_init_protocol (void)
4030 {
4031         /* structures and data for BIND */
4032         if (dcerpc_binds){
4033                 g_hash_table_destroy (dcerpc_binds);
4034         }
4035         dcerpc_binds = g_hash_table_new (dcerpc_bind_hash, dcerpc_bind_equal);
4036
4037         if (dcerpc_bind_key_chunk){
4038                 g_mem_chunk_destroy (dcerpc_bind_key_chunk);
4039         }
4040         dcerpc_bind_key_chunk = g_mem_chunk_new ("dcerpc_bind_key_chunk",
4041                                              sizeof (dcerpc_bind_key),
4042                                              200 * sizeof (dcerpc_bind_key),
4043                                              G_ALLOC_ONLY);
4044         if (dcerpc_bind_value_chunk){
4045                 g_mem_chunk_destroy (dcerpc_bind_value_chunk);
4046         }
4047         dcerpc_bind_value_chunk = g_mem_chunk_new ("dcerpc_bind_value_chunk",
4048                                              sizeof (dcerpc_bind_value),
4049                                              200 * sizeof (dcerpc_bind_value),
4050                                              G_ALLOC_ONLY);
4051         /* structures and data for CALL */
4052         if (dcerpc_calls){
4053                 g_hash_table_destroy (dcerpc_calls);
4054         }
4055         dcerpc_calls = g_hash_table_new (dcerpc_call_hash, dcerpc_call_equal);
4056         if (dcerpc_call_key_chunk){
4057                 g_mem_chunk_destroy (dcerpc_call_key_chunk);
4058         }
4059         dcerpc_call_key_chunk = g_mem_chunk_new ("dcerpc_call_key_chunk",
4060                                              sizeof (dcerpc_call_key),
4061                                              200 * sizeof (dcerpc_call_key),
4062                                              G_ALLOC_ONLY);
4063         if (dcerpc_call_value_chunk){
4064                 g_mem_chunk_destroy (dcerpc_call_value_chunk);
4065         }
4066         dcerpc_call_value_chunk = g_mem_chunk_new ("dcerpc_call_value_chunk",
4067                                              sizeof (dcerpc_call_value),
4068                                              200 * sizeof (dcerpc_call_value),
4069                                              G_ALLOC_ONLY);
4070
4071         /* structure and data for MATCHED */
4072         if (dcerpc_matched){
4073                 g_hash_table_destroy (dcerpc_matched);
4074         }
4075         dcerpc_matched = g_hash_table_new (dcerpc_matched_hash, dcerpc_matched_equal);
4076         if (dcerpc_matched_key_chunk){
4077                 g_mem_chunk_destroy (dcerpc_matched_key_chunk);
4078         }
4079         dcerpc_matched_key_chunk = g_mem_chunk_new ("dcerpc_matched_key_chunk",
4080                                              sizeof (dcerpc_matched_key),
4081                                              200 * sizeof (dcerpc_matched_key),
4082                                              G_ALLOC_ONLY);
4083 }
4084
4085 void
4086 proto_register_dcerpc (void)
4087 {
4088     static hf_register_info hf[] = {
4089         { &hf_dcerpc_request_in,
4090                 { "Request in", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE,
4091                 NULL, 0, "This packet is a response to the packet in this frame", HFILL }},
4092         { &hf_dcerpc_response_in,
4093                 { "Response in", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
4094                 NULL, 0, "The response to this packet is in this packet", HFILL }},
4095         { &hf_dcerpc_referent_id,
4096                 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
4097                 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
4098         { &hf_dcerpc_ver,
4099           { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4100         { &hf_dcerpc_ver_minor,
4101           { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4102         { &hf_dcerpc_packet_type,
4103           { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS (pckt_vals), 0x0, "", HFILL }},
4104         { &hf_dcerpc_cn_flags,
4105           { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4106         { &hf_dcerpc_cn_flags_first_frag,
4107           { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_FIRST_FRAG, "", HFILL }},
4108         { &hf_dcerpc_cn_flags_last_frag,
4109           { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_LAST_FRAG, "", HFILL }},
4110         { &hf_dcerpc_cn_flags_cancel_pending,
4111           { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_PENDING_CANCEL, "", HFILL }},
4112         { &hf_dcerpc_cn_flags_reserved,
4113           { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_RESERVED_1, "", HFILL }},
4114         { &hf_dcerpc_cn_flags_mpx,
4115           { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_CONC_MPX, "", HFILL }},
4116         { &hf_dcerpc_cn_flags_dne,
4117           { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_DID_NOT_EXECUTE, "", HFILL }},
4118         { &hf_dcerpc_cn_flags_maybe,
4119           { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_MAYBE, "", HFILL }},
4120         { &hf_dcerpc_cn_flags_object,
4121           { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_OBJECT_UUID, "", HFILL }},
4122         { &hf_dcerpc_drep,
4123           { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
4124         { &hf_dcerpc_drep_byteorder,
4125           { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS (drep_byteorder_vals), 0x0, "", HFILL }},
4126         { &hf_dcerpc_drep_character,
4127           { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS (drep_character_vals), 0x0, "", HFILL }},
4128         { &hf_dcerpc_drep_fp,
4129           { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS (drep_fp_vals), 0x0, "", HFILL }},
4130         { &hf_dcerpc_cn_frag_len,
4131           { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4132         { &hf_dcerpc_cn_auth_len,
4133           { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4134         { &hf_dcerpc_cn_call_id,
4135           { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4136         { &hf_dcerpc_cn_max_xmit,
4137           { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4138         { &hf_dcerpc_cn_max_recv,
4139           { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4140         { &hf_dcerpc_cn_assoc_group,
4141           { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
4142         { &hf_dcerpc_cn_num_ctx_items,
4143           { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4144         { &hf_dcerpc_cn_ctx_id,
4145           { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4146         { &hf_dcerpc_cn_num_trans_items,
4147           { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4148         { &hf_dcerpc_cn_bind_if_id,
4149           { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4150         { &hf_dcerpc_cn_bind_if_ver,
4151           { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4152         { &hf_dcerpc_cn_bind_if_ver_minor,
4153           { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4154         { &hf_dcerpc_cn_bind_trans_id,
4155           { "Transfer Syntax", "dcerpc.cn_bind_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4156         { &hf_dcerpc_cn_bind_trans_ver,
4157           { "Syntax ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4158         { &hf_dcerpc_cn_alloc_hint,
4159           { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4160         { &hf_dcerpc_cn_sec_addr_len,
4161           { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4162         { &hf_dcerpc_cn_sec_addr,
4163           { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, "", HFILL }},
4164         { &hf_dcerpc_cn_num_results,
4165           { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4166         { &hf_dcerpc_cn_ack_result,
4167           { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, "", HFILL }},
4168         { &hf_dcerpc_cn_ack_reason,
4169           { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, "", HFILL }},
4170         { &hf_dcerpc_cn_ack_trans_id,
4171           { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4172         { &hf_dcerpc_cn_ack_trans_ver,
4173           { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4174         { &hf_dcerpc_cn_reject_reason,
4175           { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, "", HFILL }},
4176         { &hf_dcerpc_cn_num_protocols,
4177           { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4178         { &hf_dcerpc_cn_protocol_ver_major,
4179           { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4180         { &hf_dcerpc_cn_protocol_ver_minor,
4181           { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4182         { &hf_dcerpc_cn_cancel_count,
4183           { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4184         { &hf_dcerpc_cn_status,
4185           { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
4186         { &hf_dcerpc_auth_type,
4187           { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
4188         { &hf_dcerpc_auth_level,
4189           { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS (authn_level_vals), 0x0, "", HFILL }},
4190         { &hf_dcerpc_auth_pad_len,
4191           { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4192         { &hf_dcerpc_auth_rsrvd,
4193           { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4194         { &hf_dcerpc_auth_ctx_id,
4195           { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4196         { &hf_dcerpc_dg_flags1,
4197           { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4198         { &hf_dcerpc_dg_flags1_rsrvd_01,
4199           { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_01, "", HFILL }},
4200         { &hf_dcerpc_dg_flags1_last_frag,
4201           { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_LASTFRAG, "", HFILL }},
4202         { &hf_dcerpc_dg_flags1_frag,
4203           { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_FRAG, "", HFILL }},
4204         { &hf_dcerpc_dg_flags1_nofack,
4205           { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_NOFACK, "", HFILL }},
4206         { &hf_dcerpc_dg_flags1_maybe,
4207           { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_MAYBE, "", HFILL }},
4208         { &hf_dcerpc_dg_flags1_idempotent,
4209           { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_IDEMPOTENT, "", HFILL }},
4210         { &hf_dcerpc_dg_flags1_broadcast,
4211           { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_BROADCAST, "", HFILL }},
4212         { &hf_dcerpc_dg_flags1_rsrvd_80,
4213           { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_80, "", HFILL }},
4214         { &hf_dcerpc_dg_flags2,
4215           { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4216         { &hf_dcerpc_dg_flags2_rsrvd_01,
4217           { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_01, "", HFILL }},
4218         { &hf_dcerpc_dg_flags2_cancel_pending,
4219           { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_CANCEL_PENDING, "", HFILL }},
4220         { &hf_dcerpc_dg_flags2_rsrvd_04,
4221           { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_04, "", HFILL }},
4222         { &hf_dcerpc_dg_flags2_rsrvd_08,
4223           { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_08, "", HFILL }},
4224         { &hf_dcerpc_dg_flags2_rsrvd_10,
4225           { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_10, "", HFILL }},
4226         { &hf_dcerpc_dg_flags2_rsrvd_20,
4227           { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_20, "", HFILL }},
4228         { &hf_dcerpc_dg_flags2_rsrvd_40,
4229           { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_40, "", HFILL }},
4230         { &hf_dcerpc_dg_flags2_rsrvd_80,
4231           { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_80, "", HFILL }},
4232         { &hf_dcerpc_dg_serial_lo,
4233           { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4234         { &hf_dcerpc_dg_serial_hi,
4235           { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4236         { &hf_dcerpc_dg_ahint,
4237           { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
4238         { &hf_dcerpc_dg_ihint,
4239           { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
4240         { &hf_dcerpc_dg_frag_len,
4241           { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4242         { &hf_dcerpc_dg_frag_num,
4243           { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4244         { &hf_dcerpc_dg_auth_proto,
4245           { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
4246         { &hf_dcerpc_dg_seqnum,
4247           { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4248         { &hf_dcerpc_dg_server_boot,
4249           { "Server boot time", "dcerpc.dg_server_boot", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
4250         { &hf_dcerpc_dg_if_ver,
4251           { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4252         { &hf_dcerpc_krb5_av_prot_level,
4253           { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, "", HFILL }},
4254         { &hf_dcerpc_krb5_av_key_vers_num,
4255           { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4256         { &hf_dcerpc_krb5_av_key_auth_verifier,
4257           { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
4258         { &hf_dcerpc_obj_id,
4259           { "Object", "dcerpc.obj_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4260         { &hf_dcerpc_dg_if_id,
4261           { "Interface", "dcerpc.dg_if_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4262         { &hf_dcerpc_dg_act_id,
4263           { "Activity", "dcerpc.dg_act_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4264         { &hf_dcerpc_opnum,
4265           { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4266
4267         { &hf_dcerpc_dg_cancel_vers,
4268           { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4269
4270         { &hf_dcerpc_dg_cancel_id,
4271           { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4272
4273         { &hf_dcerpc_dg_server_accepting_cancels,
4274           { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
4275
4276         { &hf_dcerpc_dg_fack_vers,
4277           { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4278
4279         { &hf_dcerpc_dg_fack_window_size,
4280           { "Window Size", "dcerpc.fack_window size", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4281
4282         { &hf_dcerpc_dg_fack_max_tsdu,
4283           { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4284
4285         { &hf_dcerpc_dg_fack_max_frag_size,
4286           { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4287
4288         { &hf_dcerpc_dg_fack_serial_num,
4289           { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4290
4291         { &hf_dcerpc_dg_fack_selack_len,
4292           { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4293
4294         { &hf_dcerpc_dg_fack_selack,
4295           { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
4296
4297         { &hf_dcerpc_dg_status,
4298           { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
4299
4300         { &hf_dcerpc_array_max_count,
4301           { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
4302
4303         { &hf_dcerpc_array_offset,
4304           { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
4305
4306         { &hf_dcerpc_array_actual_count,
4307           { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
4308
4309         { &hf_dcerpc_array_buffer,
4310           { "Buffer", "dcerpc.array.buffer", FT_BYTES, BASE_NONE, NULL, 0x0, "Buffer: Buffer containing elements of the array", HFILL }},
4311                 
4312         { &hf_dcerpc_op,
4313           { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4314
4315         { &hf_dcerpc_fragments,
4316           { "DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
4317           NULL, 0x0, "DCE/RPC Fragments", HFILL }},
4318
4319         { &hf_dcerpc_fragment,
4320           { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM, BASE_NONE,
4321           NULL, 0x0, "DCE/RPC Fragment", HFILL }},
4322
4323         { &hf_dcerpc_fragment_overlap,
4324           { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
4325
4326         { &hf_dcerpc_fragment_overlap_conflict,
4327           { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
4328
4329         { &hf_dcerpc_fragment_multiple_tails,
4330           { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
4331
4332         { &hf_dcerpc_fragment_too_long_fragment,
4333           { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
4334
4335         { &hf_dcerpc_fragment_error,
4336           { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
4337
4338         { &hf_dcerpc_time, 
4339           { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0, "Time between Request and Reply for DCE-RPC calls", HFILL }},
4340         { &hf_dcerpc_reassembled_in,
4341           { "This PDU is reassembled in", "dcerpc.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "The DCE/RPC PDU is completely reassembled in this frame", HFILL }},
4342    };
4343     static gint *ett[] = {
4344         &ett_dcerpc,
4345         &ett_dcerpc_cn_flags,
4346         &ett_dcerpc_cn_ctx,
4347         &ett_dcerpc_cn_iface,
4348         &ett_dcerpc_drep,
4349         &ett_dcerpc_dg_flags1,
4350         &ett_dcerpc_dg_flags2,
4351         &ett_dcerpc_pointer_data,
4352         &ett_dcerpc_string,
4353         &ett_dcerpc_fragments,
4354         &ett_dcerpc_fragment,
4355         &ett_dcerpc_krb5_auth_verf,
4356     };
4357     module_t *dcerpc_module;
4358
4359     proto_dcerpc = proto_register_protocol ("DCE RPC", "DCERPC", "dcerpc");
4360     proto_register_field_array (proto_dcerpc, hf, array_length (hf));
4361     proto_register_subtree_array (ett, array_length (ett));
4362     register_init_routine (dcerpc_init_protocol);
4363     dcerpc_module = prefs_register_protocol (proto_dcerpc, NULL);
4364     prefs_register_bool_preference (dcerpc_module,
4365                                     "desegment_dcerpc",
4366                                     "Desegment all DCE/RPC over TCP",
4367                                     "Whether the DCE/RPC dissector should desegment all DCE/RPC over TCP",
4368                                     &dcerpc_cn_desegment);
4369     prefs_register_bool_preference (dcerpc_module,
4370                                     "reassemble_dcerpc",
4371                                     "Reassemble DCE/RPC fragments",
4372                                     "Whether the DCE/RPC dissector should reassemble all fragmented PDUs",
4373                                     &dcerpc_reassemble);
4374     register_init_routine(dcerpc_reassemble_init);
4375     dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
4376     dcerpc_tap=register_tap("dcerpc");
4377 }
4378
4379 void
4380 proto_reg_handoff_dcerpc (void)
4381 {
4382     heur_dissector_add ("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
4383     heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
4384     heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
4385     heur_dissector_add ("smb_transact", dissect_dcerpc_cn_bs, proto_dcerpc);
4386     dcerpc_smb_init(proto_dcerpc);
4387 }