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