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