pinfo->private_data was a quite subptimal idea
[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->dce_smb_fid 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     guint hash;
814
815     hash=GPOINTER_TO_UINT(key->conv) + key->ctx_id + key->smb_fid;
816     return hash;
817
818 }
819
820 /*
821  * To keep track of callid mappings.  Should really use some generic
822  * conversation support instead.
823  */
824 static GHashTable *dcerpc_cn_calls=NULL;
825 static GHashTable *dcerpc_dg_calls=NULL;
826
827 typedef struct _dcerpc_cn_call_key {
828     conversation_t *conv;
829     guint32 call_id;
830     guint16 smb_fid;
831 } dcerpc_cn_call_key;
832
833 typedef struct _dcerpc_dg_call_key {
834     conversation_t *conv;
835     guint32 seqnum;
836     e_uuid_t act_id ;
837 } dcerpc_dg_call_key;
838
839 static GMemChunk *dcerpc_cn_call_key_chunk=NULL;
840
841 static GMemChunk *dcerpc_dg_call_key_chunk=NULL;
842
843 static GMemChunk *dcerpc_call_value_chunk=NULL;
844
845
846 static gint
847 dcerpc_cn_call_equal (gconstpointer k1, gconstpointer k2)
848 {
849     const dcerpc_cn_call_key *key1 = (const dcerpc_cn_call_key *)k1;
850     const dcerpc_cn_call_key *key2 = (const dcerpc_cn_call_key *)k2;
851     return (key1->conv == key2->conv
852             && key1->call_id == key2->call_id
853             && key1->smb_fid == key2->smb_fid);
854 }
855
856 static gint
857 dcerpc_dg_call_equal (gconstpointer k1, gconstpointer k2)
858 {
859     const dcerpc_dg_call_key *key1 = (const dcerpc_dg_call_key *)k1;
860     const dcerpc_dg_call_key *key2 = (const dcerpc_dg_call_key *)k2;
861     return (key1->conv == key2->conv
862             && key1->seqnum == key2->seqnum
863             && (memcmp (&key1->act_id, &key2->act_id, sizeof (e_uuid_t)) == 0));
864 }
865
866 static guint
867 dcerpc_cn_call_hash (gconstpointer k)
868 {
869     const dcerpc_cn_call_key *key = (const dcerpc_cn_call_key *)k;
870     return GPOINTER_TO_UINT(key->conv) + key->call_id + key->smb_fid;
871 }
872
873 static guint
874 dcerpc_dg_call_hash (gconstpointer k)
875 {
876     const dcerpc_dg_call_key *key = (const dcerpc_dg_call_key *)k;
877     return (GPOINTER_TO_UINT(key->conv) + key->seqnum + key->act_id.Data1
878             + (key->act_id.Data2 << 16) + key->act_id.Data3
879             + (key->act_id.Data4[0] << 24) + (key->act_id.Data4[1] << 16)
880             + (key->act_id.Data4[2] << 8) + (key->act_id.Data4[3] << 0)
881             + (key->act_id.Data4[4] << 24) + (key->act_id.Data4[5] << 16)
882             + (key->act_id.Data4[6] << 8) + (key->act_id.Data4[7] << 0));
883 }
884
885 /* to keep track of matched calls/responses
886    this one uses the same value struct as calls, but the key is the frame id
887    and call id; there can be more than one call in a frame.
888
889    XXX - why not just use the same keys as are used for calls?
890 */
891
892 static GHashTable *dcerpc_matched=NULL;
893
894 typedef struct _dcerpc_matched_key {
895     guint32 frame;
896     guint32 call_id;
897 } dcerpc_matched_key;
898
899 static GMemChunk *dcerpc_matched_key_chunk=NULL;
900
901 static gint
902 dcerpc_matched_equal (gconstpointer k1, gconstpointer k2)
903 {
904     const dcerpc_matched_key *key1 = (const dcerpc_matched_key *)k1;
905     const dcerpc_matched_key *key2 = (const dcerpc_matched_key *)k2;
906     return (key1->frame == key2->frame
907             && key1->call_id == key2->call_id);
908 }
909
910 static guint
911 dcerpc_matched_hash (gconstpointer k)
912 {
913     const dcerpc_matched_key *key = (const dcerpc_matched_key *)k;
914     return key->frame;
915 }
916
917
918
919 /*
920  * Utility functions.  Modeled after packet-rpc.c
921  */
922
923 int
924 dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
925                       proto_tree *tree, guint8 *drep,
926                       int hfindex, guint8 *pdata)
927 {
928     guint8 data;
929
930     data = tvb_get_guint8 (tvb, offset);
931     if (tree) {
932         proto_tree_add_item (tree, hfindex, tvb, offset, 1, (drep[0] & 0x10));
933     }
934     if (pdata)
935         *pdata = data;
936     return offset + 1;
937 }
938
939 int
940 dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
941                        proto_tree *tree, guint8 *drep,
942                        int hfindex, guint16 *pdata)
943 {
944     guint16 data;
945
946     data = ((drep[0] & 0x10)
947             ? tvb_get_letohs (tvb, offset)
948             : tvb_get_ntohs (tvb, offset));
949
950     if (tree) {
951         proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10));
952     }
953     if (pdata)
954         *pdata = data;
955     return offset + 2;
956 }
957
958 int
959 dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
960                        proto_tree *tree, guint8 *drep,
961                        int hfindex, guint32 *pdata)
962 {
963     guint32 data;
964
965     data = ((drep[0] & 0x10)
966             ? tvb_get_letohl (tvb, offset)
967             : tvb_get_ntohl (tvb, offset));
968
969     if (tree) {
970         proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10));
971     }
972     if (pdata)
973         *pdata = data;
974     return offset+4;
975 }
976
977 /* handles 32 bit unix time_t */
978 int
979 dissect_dcerpc_time_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
980                        proto_tree *tree, guint8 *drep,
981                        int hfindex, guint32 *pdata)
982 {
983     guint32 data;
984     nstime_t tv;
985
986     data = ((drep[0] & 0x10)
987             ? tvb_get_letohl (tvb, offset)
988             : tvb_get_ntohl (tvb, offset));
989
990     tv.secs=data;
991     tv.nsecs=0;
992     if (tree) {
993         if(data==0xffffffff){
994             /* special case,   no time specified */
995             proto_tree_add_time_format(tree, hfindex, tvb, offset, 4, &tv, "%s: No time specified", proto_registrar_get_nth(hfindex)->name);
996         } else {
997             proto_tree_add_time (tree, hfindex, tvb, offset, 4, &tv);
998         }
999     }
1000     if (pdata)
1001         *pdata = data;
1002
1003     return offset+4;
1004 }
1005
1006 int
1007 dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1008                        proto_tree *tree, guint8 *drep,
1009                        int hfindex, guint64 *pdata)
1010 {
1011     guint64 data;
1012
1013     data = ((drep[0] & 0x10)
1014             ? tvb_get_letoh64 (tvb, offset)
1015             : tvb_get_ntoh64 (tvb, offset));
1016
1017     if (tree) {
1018         proto_tree_add_item(tree, hfindex, tvb, offset, 8, (drep[0] & 0x10));
1019     }
1020     if (pdata)
1021         *pdata = data;
1022     return offset+8;
1023 }
1024
1025
1026 int
1027 dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1028                     proto_tree *tree, guint8 *drep, 
1029                     int hfindex, gfloat *pdata)
1030 {
1031         gfloat data;
1032
1033
1034         switch(drep[1]) {
1035                 case(DCE_RPC_DREP_FP_IEEE):
1036                         data = ((drep[0] & 0x10)
1037                                         ? tvb_get_letohieee_float(tvb, offset)
1038                                         : tvb_get_ntohieee_float(tvb, offset));
1039                         if (tree) {
1040                                 proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
1041                         }
1042                         break;
1043                 case(DCE_RPC_DREP_FP_VAX):  /* (fall trough) */
1044                 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1045                 case(DCE_RPC_DREP_FP_IBM):  /* (fall trough) */
1046                 default:
1047                         /* ToBeDone: non IEEE floating formats */
1048                         /* Set data to a negative infinity value */
1049                         data = -G_MAXFLOAT;
1050                         if (tree) {
1051                                 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep[1]);
1052                         }
1053         }
1054     if (pdata)
1055         *pdata = data;
1056     return offset + 4;
1057 }
1058
1059
1060 int
1061 dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1062                     proto_tree *tree, guint8 *drep, 
1063                     int hfindex, gdouble *pdata)
1064 {
1065     gdouble data;
1066
1067
1068         switch(drep[1]) {
1069                 case(DCE_RPC_DREP_FP_IEEE):
1070                         data = ((drep[0] & 0x10)
1071                                         ? tvb_get_letohieee_double(tvb, offset)
1072                                         : tvb_get_ntohieee_double(tvb, offset));
1073                         if (tree) {
1074                                 proto_tree_add_double(tree, hfindex, tvb, offset, 8, data);
1075                         }
1076                         break;
1077                 case(DCE_RPC_DREP_FP_VAX):  /* (fall trough) */
1078                 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1079                 case(DCE_RPC_DREP_FP_IBM):  /* (fall trough) */
1080                 default:
1081                         /* ToBeDone: non IEEE double formats */
1082                         /* Set data to a negative infinity value */
1083                         data = -G_MAXDOUBLE;
1084                         if (tree) {
1085                                 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep[1]);
1086                         }
1087         }
1088     if (pdata)
1089         *pdata = data;
1090     return offset + 8;
1091 }
1092
1093
1094 int
1095 dissect_dcerpc_uuid_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1096                     proto_tree *tree, char *drep,
1097                     int hfindex, e_uuid_t *pdata)
1098 {
1099     e_uuid_t uuid;
1100         header_field_info* hfi;
1101 #if 0
1102         gchar *uuid_name;
1103 #endif
1104
1105
1106     dcerpc_tvb_get_uuid (tvb, offset, drep, &uuid);
1107     if (tree) {
1108                 /* get name of protocol field to prepend it later */
1109                 hfi = proto_registrar_get_nth(hfindex);
1110
1111 #if 0
1112         /* XXX - get the name won't work correct, as we don't know the version of this uuid (if it has one) */
1113                 /* look for a registered uuid name */
1114                 uuid_name = dcerpc_get_uuid_name(&uuid, 0);
1115
1116                 if (uuid_name) {
1117                         /* we know the name of this uuid */
1118                         proto_tree_add_string_format (tree, hfindex, tvb, offset, 16, "",
1119                                       "%s: %s (%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x)",
1120                                                                           hfi->name, uuid_name,
1121                                       uuid.Data1, uuid.Data2, uuid.Data3,
1122                                       uuid.Data4[0], uuid.Data4[1],
1123                                       uuid.Data4[2], uuid.Data4[3],
1124                                       uuid.Data4[4], uuid.Data4[5],
1125                                       uuid.Data4[6], uuid.Data4[7]);
1126                 } else {
1127 #endif
1128                         /* we don't know the name of this uuid */
1129                         proto_tree_add_string_format (tree, hfindex, tvb, offset, 16, "",
1130                                       "%s: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1131                                                                           hfi->name,
1132                                       uuid.Data1, uuid.Data2, uuid.Data3,
1133                                       uuid.Data4[0], uuid.Data4[1],
1134                                       uuid.Data4[2], uuid.Data4[3],
1135                                       uuid.Data4[4], uuid.Data4[5],
1136                                       uuid.Data4[6], uuid.Data4[7]);
1137 #if 0
1138                 }
1139 #endif
1140     }
1141     if (pdata) {
1142         *pdata = uuid;
1143     }
1144     return offset + 16;
1145 }
1146
1147
1148 /*
1149  * a couple simpler things
1150  */
1151 guint16
1152 dcerpc_tvb_get_ntohs (tvbuff_t *tvb, gint offset, guint8 *drep)
1153 {
1154     if (drep[0] & 0x10) {
1155         return tvb_get_letohs (tvb, offset);
1156     } else {
1157         return tvb_get_ntohs (tvb, offset);
1158     }
1159 }
1160
1161 guint32
1162 dcerpc_tvb_get_ntohl (tvbuff_t *tvb, gint offset, guint8 *drep)
1163 {
1164     if (drep[0] & 0x10) {
1165         return tvb_get_letohl (tvb, offset);
1166     } else {
1167         return tvb_get_ntohl (tvb, offset);
1168     }
1169 }
1170
1171 void
1172 dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, guint8 *drep, e_uuid_t *uuid)
1173 {
1174     unsigned int i;
1175     uuid->Data1 = dcerpc_tvb_get_ntohl (tvb, offset, drep);
1176     uuid->Data2 = dcerpc_tvb_get_ntohs (tvb, offset+4, drep);
1177     uuid->Data3 = dcerpc_tvb_get_ntohs (tvb, offset+6, drep);
1178
1179     for (i=0; i<sizeof (uuid->Data4); i++) {
1180         uuid->Data4[i] = tvb_get_guint8 (tvb, offset+8+i);
1181     }
1182 }
1183
1184
1185
1186 /* NDR arrays */
1187 /* function to dissect a unidimensional conformant array */
1188 int
1189 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1190                 proto_tree *tree, guint8 *drep,
1191                 dcerpc_dissect_fnct_t *fnct)
1192 {
1193         guint32 i;
1194         dcerpc_info *di;
1195         int old_offset;
1196
1197         di=pinfo->private_data;
1198         if(di->conformant_run){
1199                 /* conformant run, just dissect the max_count header */
1200                 old_offset=offset;
1201                 di->conformant_run=0;
1202                 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1203                                 hf_dcerpc_array_max_count, &di->array_max_count);
1204                 di->array_max_count_offset=offset-4;
1205                 di->conformant_run=1;
1206                 di->conformant_eaten=offset-old_offset;
1207         } else {
1208                 /* we don't remember where in the bytestream this field was */
1209                 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1210
1211                 /* real run, dissect the elements */
1212                 for(i=0;i<di->array_max_count;i++){
1213                         offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1214                 }
1215         }
1216
1217         return offset;
1218 }
1219 /* function to dissect a unidimensional conformant and varying array */
1220 int
1221 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1222                 proto_tree *tree, guint8 *drep,
1223                 dcerpc_dissect_fnct_t *fnct)
1224 {
1225         guint32 i;
1226         dcerpc_info *di;
1227         int old_offset;
1228
1229         di=pinfo->private_data;
1230         if(di->conformant_run){
1231                 /* conformant run, just dissect the max_count header */
1232                 old_offset=offset;
1233                 di->conformant_run=0;
1234                 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1235                                 hf_dcerpc_array_max_count, &di->array_max_count);
1236                 di->array_max_count_offset=offset-4;
1237                 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1238                                 hf_dcerpc_array_offset, &di->array_offset);
1239                 di->array_offset_offset=offset-4;
1240                 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1241                                 hf_dcerpc_array_actual_count, &di->array_actual_count);
1242                 di->array_actual_count_offset=offset-4;
1243                 di->conformant_run=1;
1244                 di->conformant_eaten=offset-old_offset;
1245         } else {
1246                 /* we dont dont remember where  in the bytestream these fields were */
1247                 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1248                 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
1249                 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
1250
1251                 /* real run, dissect the elements */
1252                 for(i=0;i<di->array_actual_count;i++){
1253                         offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1254                 }
1255         }
1256
1257         return offset;
1258 }
1259 /* function to dissect a unidimensional varying array */
1260 int
1261 dissect_ndr_uvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1262                 proto_tree *tree, guint8 *drep,
1263                 dcerpc_dissect_fnct_t *fnct)
1264 {
1265         guint32 i;
1266         dcerpc_info *di;
1267         int old_offset;
1268
1269         di=pinfo->private_data;
1270         if(di->conformant_run){
1271                 /* conformant run, just dissect the max_count header */
1272                 old_offset=offset;
1273                 di->conformant_run=0;
1274                 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1275                                 hf_dcerpc_array_offset, &di->array_offset);
1276                 di->array_offset_offset=offset-4;
1277                 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1278                                 hf_dcerpc_array_actual_count, &di->array_actual_count);
1279                 di->array_actual_count_offset=offset-4;
1280                 di->conformant_run=1;
1281                 di->conformant_eaten=offset-old_offset;
1282         } else {
1283                 /* we dont dont remember where  in the bytestream these fields were */
1284                 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
1285                 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
1286
1287                 /* real run, dissect the elements */
1288                 for(i=0;i<di->array_actual_count;i++){
1289                         offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1290                 }
1291         }
1292
1293         return offset;
1294 }
1295
1296 /* Dissect an string of bytes.  This corresponds to
1297    IDL of the form '[string] byte *foo'.
1298
1299    It can also be used for a conformant varying array of bytes if
1300    the contents of the array should be shown as a big blob, rather
1301    than showing each byte as an individual element.
1302
1303    XXX - which of those is really the IDL type for, for example,
1304    the encrypted data in some MAPI packets?  (Microsoft haven't
1305    released that IDL.)
1306
1307    XXX - does this need to do all the conformant array stuff that
1308    "dissect_ndr_ucvarray()" does?  These are presumably for strings
1309    that are conformant and varying - they're stored like conformant
1310    varying arrays of bytes.  */
1311 int
1312 dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1313                             proto_tree *tree, guint8 *drep)
1314 {
1315     dcerpc_info *di;
1316     guint32 len;
1317
1318     di=pinfo->private_data;
1319     if(di->conformant_run){
1320       /* just a run to handle conformant arrays, no scalars to dissect */
1321       return offset;
1322     }
1323
1324     /* NDR array header */
1325
1326     offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1327                                 hf_dcerpc_array_max_count, NULL);
1328
1329     offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1330                                 hf_dcerpc_array_offset, NULL);
1331
1332     offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1333                                 hf_dcerpc_array_actual_count, &len);
1334
1335     if (tree && len)
1336         proto_tree_add_item(tree, hf_dcerpc_array_buffer,
1337                             tvb, offset, len, drep[0] & 0x10);
1338
1339     offset += len;
1340
1341     return offset;
1342 }
1343
1344 /* For dissecting arrays that are to be interpreted as strings.  */
1345
1346 /* Dissect an NDR conformant varying string of elements.
1347    The length of each element is given by the 'size_is' parameter;
1348    the elements are assumed to be characters or wide characters.
1349
1350    XXX - does this need to do all the conformant array stuff that
1351    "dissect_ndr_ucvarray()" does?  */
1352 int
1353 dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1354                      proto_tree *tree, guint8 *drep, int size_is,
1355                      int hfindex, gboolean add_subtree, char **data)
1356 {
1357     dcerpc_info *di;
1358     proto_item *string_item;
1359     proto_tree *string_tree;
1360     guint32 len, buffer_len;
1361     char *s;
1362     header_field_info *hfinfo;
1363
1364     di=pinfo->private_data;
1365     if(di->conformant_run){
1366       /* just a run to handle conformant arrays, no scalars to dissect */
1367       return offset;
1368     }
1369
1370     if (add_subtree) {
1371         string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1372                                           proto_registrar_get_name(hfindex));
1373         string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1374     } else {
1375         string_item = NULL;
1376         string_tree = tree;
1377     }
1378
1379     /* NDR array header */
1380
1381     offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1382                                 hf_dcerpc_array_max_count, NULL);
1383
1384     offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1385                                 hf_dcerpc_array_offset, NULL);
1386
1387     offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1388                                 hf_dcerpc_array_actual_count, &len);
1389
1390     buffer_len = size_is * len;
1391
1392     /* Adjust offset */
1393     if (offset % size_is)
1394         offset += size_is - (offset % size_is);
1395
1396     if (size_is == sizeof(guint16)) {
1397         /* XXX - use drep to determine the byte order? */
1398         s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
1399         /*
1400          * XXX - we don't support a string type with Unicode
1401          * characters, so if this is a string item, we make
1402          * its value be the "fake Unicode" string.
1403          */
1404         if (tree && buffer_len) {
1405             hfinfo = proto_registrar_get_nth(hfindex);
1406             if (hfinfo->type == FT_STRING) {
1407                 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1408                                       buffer_len, s);
1409             } else {
1410                 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1411                                     buffer_len, drep[0] & 0x10);
1412             }
1413         }
1414     } else {
1415         /*
1416          * "tvb_get_string()" throws an exception if the entire string
1417          * isn't in the tvbuff.  If the length is bogus, this should
1418          * keep us from trying to allocate an immensely large buffer.
1419          * (It won't help if the length is *valid* but immensely large,
1420          * but that's another matter; in any case, that would happen only
1421          * if we had an immensely large tvbuff....)
1422          */
1423         s = tvb_get_string(tvb, offset, buffer_len);
1424         if (tree && buffer_len)
1425             proto_tree_add_item(string_tree, hfindex, tvb, offset,
1426                                 buffer_len, drep[0] & 0x10);
1427     }
1428
1429     if (string_item != NULL)
1430         proto_item_append_text(string_item, ": %s", s);
1431
1432     if (data)
1433             *data = s;
1434     else
1435             g_free(s);
1436     
1437     offset += buffer_len;
1438
1439     proto_item_set_end(string_item, tvb, offset);
1440
1441     return offset;
1442 }
1443
1444 /* Dissect an conformant varying string of chars.
1445    This corresponds to IDL of the form '[string] char *foo'.
1446
1447    XXX - at least according to the DCE RPC 1.1 spec, a string has
1448    a null terminator, which isn't necessary as a terminator for
1449    the transfer language (as there's a length), but is presumably
1450    there for the benefit of null-terminated-string languages
1451    such as C.  Is this ever used for purely counted strings?
1452    (Not that it matters if it is.) */
1453 int
1454 dissect_ndr_char_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1455                         proto_tree *tree, guint8 *drep)
1456 {
1457     dcerpc_info *di;
1458     di=pinfo->private_data;
1459
1460     return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1461                                 sizeof(guint8), di->hf_index,
1462                                 FALSE, NULL);
1463 }
1464
1465 /* Dissect a conformant varying string of wchars (wide characters).
1466    This corresponds to IDL of the form '[string] wchar *foo'
1467
1468    XXX - at least according to the DCE RPC 1.1 spec, a string has
1469    a null terminator, which isn't necessary as a terminator for
1470    the transfer language (as there's a length), but is presumably
1471    there for the benefit of null-terminated-string languages
1472    such as C.  Is this ever used for purely counted strings?
1473    (Not that it matters if it is.) */
1474 int
1475 dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1476                         proto_tree *tree, guint8 *drep)
1477 {
1478     dcerpc_info *di;
1479     di=pinfo->private_data;
1480
1481     return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1482                                 sizeof(guint16), di->hf_index,
1483                                 FALSE, NULL);
1484 }
1485
1486 /* Dissect an NDR varying string of elements.
1487    The length of each element is given by the 'size_is' parameter;
1488    the elements are assumed to be characters or wide characters.
1489 */
1490 int
1491 dissect_ndr_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1492                      proto_tree *tree, guint8 *drep, int size_is,
1493                      int hfindex, gboolean add_subtree, char **data)
1494 {
1495     dcerpc_info *di;
1496     proto_item *string_item;
1497     proto_tree *string_tree;
1498     guint32 len, buffer_len;
1499     char *s;
1500     header_field_info *hfinfo;
1501
1502     di=pinfo->private_data;
1503     if(di->conformant_run){
1504       /* just a run to handle conformant arrays, no scalars to dissect */
1505       return offset;
1506     }
1507
1508     if (add_subtree) {
1509         string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1510                                           proto_registrar_get_name(hfindex));
1511         string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1512     } else {
1513         string_item = NULL;
1514         string_tree = tree;
1515     }
1516
1517     /* NDR array header */
1518     offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1519                                 hf_dcerpc_array_offset, NULL);
1520
1521     offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1522                                 hf_dcerpc_array_actual_count, &len);
1523
1524     buffer_len = size_is * len;
1525
1526     /* Adjust offset */
1527     if (offset % size_is)
1528         offset += size_is - (offset % size_is);
1529
1530     if (size_is == sizeof(guint16)) {
1531         /* XXX - use drep to determine the byte order? */
1532         s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
1533         /*
1534          * XXX - we don't support a string type with Unicode
1535          * characters, so if this is a string item, we make
1536          * its value be the "fake Unicode" string.
1537          */
1538         if (tree && buffer_len) {
1539             hfinfo = proto_registrar_get_nth(hfindex);
1540             if (hfinfo->type == FT_STRING) {
1541                 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1542                                       buffer_len, s);
1543             } else {
1544                 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1545                                     buffer_len, drep[0] & 0x10);
1546             }
1547         }
1548     } else {
1549         /*
1550          * "tvb_get_string()" throws an exception if the entire string
1551          * isn't in the tvbuff.  If the length is bogus, this should
1552          * keep us from trying to allocate an immensely large buffer.
1553          * (It won't help if the length is *valid* but immensely large,
1554          * but that's another matter; in any case, that would happen only
1555          * if we had an immensely large tvbuff....)
1556          */
1557         s = tvb_get_string(tvb, offset, buffer_len);
1558         if (tree && buffer_len)
1559             proto_tree_add_item(string_tree, hfindex, tvb, offset,
1560                                 buffer_len, drep[0] & 0x10);
1561     }
1562
1563     if (string_item != NULL)
1564         proto_item_append_text(string_item, ": %s", s);
1565
1566     if (data)
1567             *data = s;
1568     else
1569             g_free(s);
1570     
1571     offset += buffer_len;
1572
1573     proto_item_set_end(string_item, tvb, offset);
1574
1575     return offset;
1576 }
1577 /* Dissect an varying string of chars.
1578    This corresponds to IDL of the form '[string] char *foo'.
1579
1580    XXX - at least according to the DCE RPC 1.1 spec, a string has
1581    a null terminator, which isn't necessary as a terminator for
1582    the transfer language (as there's a length), but is presumably
1583    there for the benefit of null-terminated-string languages
1584    such as C.  Is this ever used for purely counted strings?
1585    (Not that it matters if it is.) */
1586 int
1587 dissect_ndr_char_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1588                         proto_tree *tree, guint8 *drep)
1589 {
1590     dcerpc_info *di;
1591     di=pinfo->private_data;
1592
1593     return dissect_ndr_vstring(tvb, offset, pinfo, tree, drep,
1594                                 sizeof(guint8), di->hf_index,
1595                                 FALSE, NULL);
1596 }
1597
1598 /* Dissect a varying string of wchars (wide characters).
1599    This corresponds to IDL of the form '[string] wchar *foo'
1600
1601    XXX - at least according to the DCE RPC 1.1 spec, a string has
1602    a null terminator, which isn't necessary as a terminator for
1603    the transfer language (as there's a length), but is presumably
1604    there for the benefit of null-terminated-string languages
1605    such as C.  Is this ever used for purely counted strings?
1606    (Not that it matters if it is.) */
1607 int
1608 dissect_ndr_wchar_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1609                         proto_tree *tree, guint8 *drep)
1610 {
1611     dcerpc_info *di;
1612     di=pinfo->private_data;
1613
1614     return dissect_ndr_vstring(tvb, offset, pinfo, tree, drep,
1615                                 sizeof(guint16), di->hf_index,
1616                                 FALSE, NULL);
1617 }
1618
1619
1620 /* ndr pointer handling */
1621 /* list of pointers encountered so far */
1622 static GSList *ndr_pointer_list = NULL;
1623
1624 /* position where in the list to insert newly encountered pointers */
1625 static int ndr_pointer_list_pos=0;
1626
1627 /* boolean controlling whether pointers are top-level or embedded */
1628 static gboolean pointers_are_top_level = TRUE;
1629
1630 /* as a kludge, we represent all embedded reference pointers as id==-1
1631    hoping that his will not collide with any non-ref pointers */
1632 typedef struct ndr_pointer_data {
1633         guint32 id;
1634         proto_item *item;       /* proto_item for pointer */
1635         proto_tree *tree;       /* subtree of above item */
1636         dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
1637         int hf_index;
1638         dcerpc_callback_fnct_t *callback;
1639         void *callback_args;
1640 } ndr_pointer_data_t;
1641
1642 void
1643 init_ndr_pointer_list(packet_info *pinfo)
1644 {
1645         dcerpc_info *di;
1646
1647         di=pinfo->private_data;
1648         di->conformant_run=0;
1649
1650         while(ndr_pointer_list){
1651                 ndr_pointer_data_t *npd;
1652
1653                 npd=g_slist_nth_data(ndr_pointer_list, 0);
1654                 ndr_pointer_list=g_slist_remove(ndr_pointer_list, npd);
1655                 if(npd){
1656                         g_free(npd);
1657                 }
1658         }
1659
1660         ndr_pointer_list=NULL;
1661         ndr_pointer_list_pos=0;
1662         pointers_are_top_level=TRUE;
1663 }
1664
1665 static int
1666 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, guint8 *drep)
1667 {
1668         int found_new_pointer;
1669         dcerpc_info *di;
1670         int old_offset;
1671         int next_pointer;
1672
1673         next_pointer=0;
1674         di=pinfo->private_data;
1675         do{
1676                 int i, len;
1677
1678                 found_new_pointer=0;
1679                 len=g_slist_length(ndr_pointer_list);
1680                 for(i=next_pointer;i<len;i++){
1681                         ndr_pointer_data_t *tnpd;
1682                         tnpd=g_slist_nth_data(ndr_pointer_list, i);
1683                         if(tnpd->fnct){
1684                                 dcerpc_dissect_fnct_t *fnct;
1685
1686                                 next_pointer=i+1;
1687                                 found_new_pointer=1;
1688                                 fnct=tnpd->fnct;
1689                                 tnpd->fnct=NULL;
1690                                 ndr_pointer_list_pos=i+1;
1691                                 di->hf_index=tnpd->hf_index;
1692                                 /* first a run to handle any conformant
1693                                    array headers */
1694                                 di->conformant_run=1;
1695                                 di->conformant_eaten=0;
1696                                 old_offset = offset;
1697                                 offset = (*(fnct))(tvb, offset, pinfo, NULL, drep);
1698
1699                                 g_assert((offset-old_offset)==di->conformant_eaten);
1700                                 /* This is to check for any bugs in the dissectors.
1701                                  *
1702                                  * Basically, the NDR representation will store all
1703                                  * arrays in two blocks, one block with the dimension
1704                                  * discreption, like size, number of elements and such,
1705                                  * and another block that contains the actual data stored
1706                                  * in the array.
1707                                  * If the array is embedded directly inside another,
1708                                  * encapsulating aggregate type, like a union or struct,
1709                                  * then these two blocks will be stored at different places
1710                                  * in the bytestream, with other data between the blocks.
1711                                  *
1712                                  * For this reason, all pointers to types (both aggregate
1713                                  * and scalar, for simplicity no distinction is made)
1714                                  * will have its dissector called twice.
1715                                  * The dissector will first be called with conformant_run==1
1716                                  * in which mode the dissector MUST NOT consume any data from
1717                                  * the tvbuff (i.e. may not dissect anything) except the
1718                                  * initial control block for arrays.
1719                                  * The second time the dissector is called, with
1720                                  * conformant_run==0, all other data for the type will be
1721                                  * dissected.
1722                                  *
1723                                  * All dissect_ndr_<type> dissectors are already prepared
1724                                  * for this and knows when it should eat data from the tvb
1725                                  * and when not to, so implementors of dissectors will
1726                                  * normally not need to worry about this or even know about
1727                                  * it. However, if a dissector for an aggregate type calls
1728                                  * a subdissector from outside packet-dcerpc.c, such as
1729                                  * the dissector in packet-smb.c for NT Security Descriptors
1730                                  * as an example, then it is VERY important to encapsulate
1731                                  * this call to an external subdissector with the appropriate
1732                                  * test for conformant_run, i.e. it will need something like
1733                                  *
1734                                  *      dcerpc_info *di;
1735                                  *
1736                                  *      di=pinfo->private_data;
1737                                  *      if(di->conformant_run){
1738                                  *              return offset;
1739                                  *      }
1740                                  *
1741                                  * to make sure it makes the right thing.
1742                                  * This assert will signal when someone has forgotten to
1743                                  * make the dissector aware of this requirement.
1744                                  */
1745
1746                                 /* now we dissect the actual pointer */
1747                                 di->conformant_run=0;
1748                                 old_offset = offset;
1749                                 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, drep);
1750                                 if (tnpd->callback)
1751                                         tnpd->callback(pinfo, tnpd->tree, tnpd->item, tvb, old_offset, offset, tnpd->callback_args);
1752                                 break;
1753                         }
1754                 }
1755         } while(found_new_pointer);
1756
1757         return offset;
1758 }
1759
1760
1761 static void
1762 add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
1763                     dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index, 
1764                     dcerpc_callback_fnct_t *callback, void *callback_args)
1765 {
1766         ndr_pointer_data_t *npd;
1767
1768         /* check if this pointer is valid */
1769         if(id!=0xffffffff){
1770                 dcerpc_info *di;
1771                 dcerpc_call_value *value;
1772
1773                 di=pinfo->private_data;
1774                 value=di->call_data;
1775
1776                 if(di->ptype == PDU_REQ){
1777                         if(!(pinfo->fd->flags.visited)){
1778                                 if(id>value->max_ptr){
1779                                         value->max_ptr=id;
1780                                 }
1781                         }
1782                 } else {
1783                         /* if we havent seen the request bail out since we cant
1784                            know whether this is the first non-NULL instance
1785                            or not */
1786                         if(value->req_frame==0){
1787                                 /* XXX THROW EXCEPTION */
1788                         }
1789
1790                         /* We saw this one in the request frame, nothing to
1791                            dissect later */
1792                         if(id<=value->max_ptr){
1793                                 return;
1794                         }
1795                 }
1796         }
1797
1798         npd=g_malloc(sizeof(ndr_pointer_data_t));
1799         npd->id=id;
1800         npd->tree=tree;
1801         npd->item=item;
1802         npd->fnct=fnct;
1803         npd->hf_index=hf_index;
1804         npd->callback=callback;
1805         npd->callback_args=callback_args;
1806         ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
1807                                         ndr_pointer_list_pos);
1808         ndr_pointer_list_pos++;
1809 }
1810
1811
1812 static int
1813 find_pointer_index(guint32 id)
1814 {
1815         ndr_pointer_data_t *npd;
1816         int i,len;
1817
1818         len=g_slist_length(ndr_pointer_list);
1819         for(i=0;i<len;i++){
1820                 npd=g_slist_nth_data(ndr_pointer_list, i);
1821                 if(npd){
1822                         if(npd->id==id){
1823                                 return i;
1824                         }
1825                 }
1826         }
1827
1828         return -1;
1829 }
1830
1831 /* This function dissects an NDR pointer and stores the callback for later
1832  * deferred dissection.
1833  *
1834  *   fnct is the callback function for when we have reached this object in
1835  *   the bytestream.
1836  *
1837  *   type is what type of pointer.
1838  *
1839  *   this is text is what text we should put in any created tree node.
1840  *
1841  *   hf_index is what hf value we want to pass to the callback function when
1842  *   it is called, the callback can later pich this one up from di->hf_index.
1843  *
1844  *   callback is executed after the pointer has been dereferenced.
1845  *
1846  *   callback_args is passed as an argument to the callback function
1847  *
1848  * See packet-dcerpc-samr.c for examples
1849  */
1850 int
1851 dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1852                     proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
1853                     int type, char *text, int hf_index, 
1854                     dcerpc_callback_fnct_t *callback, void *callback_args)
1855 {
1856         dcerpc_info *di;
1857
1858         di=pinfo->private_data;
1859         if(di->conformant_run){
1860                 /* this call was only for dissecting the header for any
1861                    embedded conformant array. we will not parse any
1862                    pointers in this mode.
1863                 */
1864                 return offset;
1865         }
1866
1867         /*TOP LEVEL REFERENCE POINTER*/
1868         if( pointers_are_top_level
1869         &&(type==NDR_POINTER_REF) ){
1870                 proto_item *item;
1871                 proto_tree *tr;
1872
1873                 /* we must find out a nice way to do the length here */
1874                 item=proto_tree_add_text(tree, tvb, offset, 0,
1875                         "%s", text);
1876                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1877
1878                 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff, 
1879                                     hf_index, callback, callback_args);
1880                 goto after_ref_id;
1881         }
1882
1883         /*TOP LEVEL FULL POINTER*/
1884         if( pointers_are_top_level
1885         && (type==NDR_POINTER_PTR) ){
1886                 int idx;
1887                 guint32 id;
1888                 proto_item *item;
1889                 proto_tree *tr;
1890
1891                 /* get the referent id */
1892                 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1893
1894                 /* we got a NULL pointer */
1895                 if(id==0){
1896                         proto_tree_add_text(tree, tvb, offset-4, 4,
1897                                 "(NULL pointer) %s",text);
1898                         goto after_ref_id;
1899                 }
1900
1901                 /* see if we have seen this pointer before */
1902                 idx=find_pointer_index(id);
1903
1904                 /* we have seen this pointer before */
1905                 if(idx>=0){
1906                         proto_tree_add_text(tree, tvb, offset-4, 4,
1907                                 "(duplicate PTR) %s",text);
1908                         goto after_ref_id;
1909                 }
1910
1911                 /* new pointer */
1912                 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1913                         "%s", text);
1914                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1915                 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1916                 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index, 
1917                                     callback, callback_args);
1918                 goto after_ref_id;
1919         }
1920         /*TOP LEVEL UNIQUE POINTER*/
1921         if( pointers_are_top_level
1922         && (type==NDR_POINTER_UNIQUE) ){
1923                 guint32 id;
1924                 proto_item *item;
1925                 proto_tree *tr;
1926
1927                 /* get the referent id */
1928                 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1929
1930                 /* we got a NULL pointer */
1931                 if(id==0){
1932                         proto_tree_add_text(tree, tvb, offset-4, 4,
1933                                 "(NULL pointer) %s",text);
1934                         goto after_ref_id;
1935                 }
1936
1937                 /* new pointer */
1938                 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1939                         "%s", text);
1940                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1941                 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1942                 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff, 
1943                                     hf_index, callback, callback_args);
1944                 goto after_ref_id;
1945         }
1946
1947         /*EMBEDDED REFERENCE POINTER*/
1948         if( (!pointers_are_top_level)
1949         && (type==NDR_POINTER_REF) ){
1950                 guint32 id;
1951                 proto_item *item;
1952                 proto_tree *tr;
1953
1954                 /* get the referent id */
1955                 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1956
1957                 /* new pointer */
1958                 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1959                         "%s",text);
1960                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1961                 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1962                 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff, 
1963                                     hf_index, callback, callback_args);
1964                 goto after_ref_id;
1965         }
1966
1967         /*EMBEDDED UNIQUE POINTER*/
1968         if( (!pointers_are_top_level)
1969         && (type==NDR_POINTER_UNIQUE) ){
1970                 guint32 id;
1971                 proto_item *item;
1972                 proto_tree *tr;
1973
1974                 /* get the referent id */
1975                 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1976
1977                 /* we got a NULL pointer */
1978                 if(id==0){
1979                         proto_tree_add_text(tree, tvb, offset-4, 4,
1980                                 "(NULL pointer) %s", text);
1981                         goto after_ref_id;
1982                 }
1983
1984                 /* new pointer */
1985                 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1986                         "%s",text);
1987                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1988                 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1989                 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff, 
1990                                     hf_index, callback, callback_args);
1991                 goto after_ref_id;
1992         }
1993
1994         /*EMBEDDED FULL POINTER*/
1995         if( (!pointers_are_top_level)
1996         && (type==NDR_POINTER_PTR) ){
1997                 int idx;
1998                 guint32 id;
1999                 proto_item *item;
2000                 proto_tree *tr;
2001
2002                 /* get the referent id */
2003                 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
2004
2005                 /* we got a NULL pointer */
2006                 if(id==0){
2007                         proto_tree_add_text(tree, tvb, offset-4, 4,
2008                                 "(NULL pointer) %s",text);
2009                         goto after_ref_id;
2010                 }
2011
2012                 /* see if we have seen this pointer before */
2013                 idx=find_pointer_index(id);
2014
2015                 /* we have seen this pointer before */
2016                 if(idx>=0){
2017                         proto_tree_add_text(tree, tvb, offset-4, 4,
2018                                 "(duplicate PTR) %s",text);
2019                         goto after_ref_id;
2020                 }
2021
2022                 /* new pointer */
2023                 item=proto_tree_add_text(tree, tvb, offset-4, 4,
2024                         "%s", text);
2025                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2026                 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
2027                 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index, 
2028                                     callback, callback_args);
2029                 goto after_ref_id;
2030         }
2031
2032
2033 after_ref_id:
2034         /* After each top level pointer we have dissected we have to
2035            dissect all deferrals before we move on to the next top level
2036            argument */
2037         if(pointers_are_top_level==TRUE){
2038                 pointers_are_top_level=FALSE;
2039                 offset = dissect_deferred_pointers(pinfo, tvb, offset, drep);
2040                 pointers_are_top_level=TRUE;
2041         }
2042
2043         return offset;
2044 }
2045
2046 int
2047 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2048                     proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2049                     int type, char *text, int hf_index)
2050 {
2051         return dissect_ndr_pointer_cb(
2052                 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
2053                 NULL, NULL);
2054 }
2055
2056 static void
2057 show_stub_data (tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
2058                 dcerpc_auth_info *auth_info, gboolean is_encrypted)
2059 {
2060     int length;
2061
2062     /*
2063      * We don't show stub data unless we have some in the tvbuff;
2064      * however, in the protocol tree, we show, as the number of
2065      * bytes, the reported number of bytes, not the number of bytes
2066      * that happen to be in the tvbuff.
2067      */
2068     if (tvb_length_remaining (tvb, offset) > 0) {
2069         length = tvb_reported_length_remaining (tvb, offset);
2070         if (auth_info != NULL &&
2071             auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
2072             if (is_encrypted) {
2073                 proto_tree_add_text(dcerpc_tree, tvb, offset, -1,
2074                                     "Encrypted stub data (%d byte%s)",
2075                                     length, plurality(length, "", "s"));
2076             } else {
2077                 proto_tree_add_text(dcerpc_tree, tvb, offset, -1,
2078                                     "Decrypted stub data (%d byte%s)",
2079                                     length, plurality(length, "", "s"));
2080             }
2081         } else {
2082             proto_tree_add_text (dcerpc_tree, tvb, offset, -1,
2083                                  "Stub data (%d byte%s)", length,
2084                                  plurality(length, "", "s"));
2085         }
2086     }
2087 }
2088
2089 static int
2090 dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
2091                     proto_tree *dcerpc_tree,
2092                     tvbuff_t *volatile tvb, tvbuff_t *decrypted_tvb,
2093                     guint8 *drep, dcerpc_info *info,
2094                     dcerpc_auth_info *auth_info)
2095 {
2096     volatile gint offset = 0;
2097     dcerpc_uuid_key key;
2098     dcerpc_uuid_value *sub_proto;
2099     proto_tree *volatile sub_tree = NULL;
2100     dcerpc_sub_dissector *proc;
2101     gchar *name = NULL;
2102     dcerpc_dissect_fnct_t *volatile sub_dissect;
2103     const char *volatile saved_proto;
2104     void *volatile saved_private_data;
2105     guint length, reported_length;
2106     tvbuff_t *volatile stub_tvb;
2107     volatile guint auth_pad_len;
2108     volatile int auth_pad_offset;
2109 #ifdef _WIN32
2110     char UUID_NAME[MAX_PATH];
2111 #endif
2112
2113     key.uuid = info->call_data->uuid;
2114     key.ver = info->call_data->ver;
2115
2116
2117     if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == NULL
2118          || !proto_is_protocol_enabled(sub_proto->proto)) {
2119         /*
2120          * We don't have a dissector for this UUID, or the protocol
2121          * for that UUID is disabled.
2122          */
2123
2124         proto_tree_add_boolean_hidden(dcerpc_tree, hf_dcerpc_unknown_if_id,
2125                                           tvb, offset, 0, TRUE);
2126         if (check_col (pinfo->cinfo, COL_INFO)) {
2127 #ifdef _WIN32
2128                 if(ResolveWin32UUID(info->call_data->uuid, UUID_NAME, MAX_PATH))
2129                         col_append_fstr (pinfo->cinfo, COL_INFO, " [%s] UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x rpcver: %u",
2130                                 UUID_NAME, info->call_data->uuid.Data1, info->call_data->uuid.Data2, info->call_data->uuid.Data3, info->call_data->uuid.Data4[0],
2131                                 info->call_data->uuid.Data4[1], info->call_data->uuid.Data4[2], info->call_data->uuid.Data4[3],
2132                                 info->call_data->uuid.Data4[4], info->call_data->uuid.Data4[5], info->call_data->uuid.Data4[6],
2133                                 info->call_data->uuid.Data4[7], info->call_data->ver);
2134 else
2135 #endif
2136                 col_append_fstr (pinfo->cinfo, COL_INFO, " UNKUUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x rpcver: %u",
2137                         info->call_data->uuid.Data1, info->call_data->uuid.Data2, info->call_data->uuid.Data3, info->call_data->uuid.Data4[0],
2138                         info->call_data->uuid.Data4[1], info->call_data->uuid.Data4[2], info->call_data->uuid.Data4[3],
2139                         info->call_data->uuid.Data4[4], info->call_data->uuid.Data4[5], info->call_data->uuid.Data4[6],
2140                         info->call_data->uuid.Data4[7], info->call_data->ver);
2141         }
2142
2143         if (decrypted_tvb != NULL) {
2144             show_stub_data (decrypted_tvb, 0, dcerpc_tree, auth_info,
2145                             FALSE);
2146         } else
2147             show_stub_data (tvb, 0, dcerpc_tree, auth_info, TRUE);
2148         return -1;
2149     }
2150
2151     for (proc = sub_proto->procs; proc->name; proc++) {
2152         if (proc->num == info->call_data->opnum) {
2153             name = proc->name;
2154             break;
2155         }
2156     }
2157
2158     if (!name)
2159         name = "Unknown?!";
2160
2161     if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
2162         col_set_str (pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
2163     }
2164
2165     if (check_col (pinfo->cinfo, COL_INFO)) {
2166         col_add_fstr (pinfo->cinfo, COL_INFO, "%s %s",
2167                       name, (info->ptype == PDU_REQ) ? "request" : "response");
2168     }
2169
2170     if (tree) {
2171         proto_item *sub_item;
2172         sub_item = proto_tree_add_item (tree, sub_proto->proto_id, tvb, 0,
2173                                         -1, FALSE);
2174
2175         if (sub_item) {
2176             sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
2177             proto_item_append_text(sub_item, ", %s", name);
2178         }
2179
2180         /*
2181          * Put the operation number into the tree along with
2182          * the operation's name.
2183          */
2184
2185         if (sub_proto->opnum_hf != -1)
2186             proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
2187                                        tvb, 0, 0, info->call_data->opnum,
2188                                        "Operation: %s (%u)",
2189                                        name, info->call_data->opnum);
2190         else
2191             proto_tree_add_uint_format(sub_tree, hf_dcerpc_op, tvb,
2192                                        0, 0, info->call_data->opnum,
2193                                        "Operation: %s (%u)",
2194                                        name, info->call_data->opnum);
2195     }
2196
2197     sub_dissect = (info->ptype == PDU_REQ) ? 
2198             proc->dissect_rqst : proc->dissect_resp;
2199
2200     if (decrypted_tvb != NULL) {
2201         /* Either there was no encryption or we successfully decrypted
2202            the entrypted payload. */
2203         if (sub_dissect) {
2204             /* We have a subdissector - call it. */
2205             saved_proto = pinfo->current_proto;
2206             saved_private_data = pinfo->private_data;
2207             pinfo->current_proto = sub_proto->name;
2208             pinfo->private_data = (void *)info;
2209             
2210             init_ndr_pointer_list(pinfo);
2211
2212             /*
2213              * Remove the authentication padding from the stub data.
2214              */
2215             if (auth_info != NULL && auth_info->auth_pad_len != 0) {
2216                 length = tvb_length(decrypted_tvb);
2217                 reported_length = tvb_reported_length(decrypted_tvb);
2218                 if (reported_length >= auth_info->auth_pad_len) {
2219                     /*
2220                      * OK, the padding length isn't so big that it
2221                      * exceeds the stub length.  Trim the reported
2222                      * length of the tvbuff.
2223                      */
2224                     reported_length -= auth_info->auth_pad_len;
2225
2226                     /*
2227                      * If that exceeds the actual amount of data in
2228                      * the tvbuff (which means we have at least one
2229                      * byte of authentication padding in the tvbuff),
2230                      * trim the actual amount.
2231                      */
2232                     if (length > reported_length)
2233                         length = reported_length;
2234
2235                     stub_tvb = tvb_new_subset(tvb, 0, length, reported_length);
2236                     auth_pad_len = auth_info->auth_pad_len;
2237                     auth_pad_offset = reported_length;
2238                 } else {
2239                     /*
2240                      * The padding length exceeds the stub length.
2241                      * Don't bother dissecting the stub, trim the padding
2242                      * length to what's in the stub data, and show the
2243                      * entire stub as authentication padding.
2244                      */
2245                     stub_tvb = NULL;
2246                     auth_pad_len = reported_length;
2247                     auth_pad_offset = 0;
2248                 }
2249             } else {
2250                 /*
2251                  * No authentication padding.
2252                  */
2253                 stub_tvb = decrypted_tvb;
2254                 auth_pad_len = 0;
2255                 auth_pad_offset = 0;
2256             }
2257
2258             if (stub_tvb != NULL) {
2259                 /*
2260                  * Catch all exceptions other than BoundsError, so that even
2261                  * if the stub data is bad, we still show the authentication
2262                  * padding, if any.
2263                  *
2264                  * If we get BoundsError, it means the frame was cut short
2265                  * by a snapshot length, so there's nothing more to
2266                  * dissect; just re-throw that exception.
2267                  */
2268                 TRY {
2269                     offset = sub_dissect (decrypted_tvb, 0, pinfo, sub_tree,
2270                                           drep);
2271
2272                     /* If we have a subdissector and it didn't dissect all
2273                        data in the tvb, make a note of it. */
2274
2275                     if (tvb_reported_length_remaining(stub_tvb, offset) > 0) {
2276                         if (check_col(pinfo->cinfo, COL_INFO))
2277                             col_append_fstr(pinfo->cinfo, COL_INFO,
2278                                             "[Long frame (%d bytes)]",
2279                                             tvb_reported_length_remaining(stub_tvb, offset));
2280                     }
2281                 } CATCH(BoundsError) {
2282                     RETHROW;
2283                 } CATCH_ALL {
2284                     show_exception(decrypted_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
2285                 } ENDTRY;
2286             }
2287
2288             /* If there is auth padding at the end of the stub, display it */
2289             if (auth_pad_len != 0) {
2290                 proto_tree_add_text (sub_tree, decrypted_tvb, auth_pad_offset,
2291                                      auth_pad_len,
2292                                      "Auth Padding (%u byte%s)",
2293                                      auth_pad_len,
2294                                      plurality(auth_pad_len, "", "s"));
2295             }
2296
2297             pinfo->current_proto = saved_proto;
2298             pinfo->private_data = saved_private_data;
2299         } else {
2300             /* No subdissector - show it as stub data. */
2301             if(decrypted_tvb){
2302                show_stub_data (decrypted_tvb, 0, sub_tree, auth_info, FALSE);
2303             } else {
2304                show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
2305             }
2306         }
2307     } else
2308         show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
2309
2310     tap_queue_packet(dcerpc_tap, pinfo, info);
2311     return 0;
2312 }
2313
2314 static int
2315 dissect_dcerpc_verifier (tvbuff_t *tvb, packet_info *pinfo, 
2316                          proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
2317                          dcerpc_auth_info *auth_info)
2318 {
2319     int auth_offset;
2320
2321     auth_info->auth_data = NULL;
2322
2323     if (auth_info->auth_size != 0) {
2324         dcerpc_auth_subdissector_fns *auth_fns;
2325         tvbuff_t *auth_tvb;
2326
2327         auth_offset = hdr->frag_len - hdr->auth_len;
2328
2329         auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
2330                                   hdr->auth_len);
2331
2332         auth_info->auth_data = auth_tvb;
2333
2334         if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
2335                                                   auth_info->auth_type))) {
2336             /*
2337              * Catch all exceptions, so that even if the verifier is bad
2338              * or we don't have all of it, we still show the stub data.
2339              */
2340             TRY {
2341                 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
2342                                   hdr, auth_info);
2343             } CATCH_ALL {
2344                 show_exception(auth_tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
2345             } ENDTRY;
2346         } else {
2347             proto_tree_add_text (dcerpc_tree, auth_tvb, 0, hdr->auth_len,
2348                                  "Auth Verifier");
2349         }
2350     }
2351
2352     return hdr->auth_len;
2353 }
2354
2355 static void
2356 dissect_dcerpc_cn_auth (tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
2357                         proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
2358                         gboolean are_credentials, dcerpc_auth_info *auth_info)
2359 {
2360     volatile int offset;
2361
2362     /*
2363      * Initially set auth_level and auth_type to zero to indicate that we 
2364      * haven't yet seen any authentication level information.
2365      */
2366     auth_info->auth_level = 0;
2367     auth_info->auth_type = 0;
2368     auth_info->auth_size = 0;
2369     auth_info->auth_pad_len = 0;
2370     
2371     /*
2372      * The authentication information is at the *end* of the PDU; in
2373      * request and response PDUs, the request and response stub data
2374      * come before it.
2375      *
2376      * Is there any authentication data (i.e., is the authentication length
2377      * non-zero), and is the authentication length valid (i.e., is it, plus
2378      * 8 bytes for the type/level/pad length/reserved/context id, less than
2379      * or equal to the fragment length minus the starting offset of the
2380      * stub data?)
2381      */
2382
2383     if (hdr->auth_len
2384         && (hdr->auth_len + 8 <= hdr->frag_len - stub_offset)) {
2385
2386         /*
2387          * Yes, there is authentication data, and the length is valid.
2388          * Do we have all the bytes of stub data?
2389          * (If not, we'd throw an exception dissecting *that*, so don't
2390          * bother trying to dissect the authentication information and
2391          * throwing another exception there.)
2392          */
2393         offset = hdr->frag_len - (hdr->auth_len + 8);
2394         if (offset == 0 || tvb_offset_exists(tvb, offset - 1)) {
2395             /*
2396              * Either there's no stub data, or the last byte of the stub
2397              * data is present in the captured data, so we shouldn't
2398              * get a BoundsError dissecting the stub data.
2399              *
2400              * Try dissecting the authentication data.
2401              * Catch all exceptions, so that even if the auth info is bad
2402              * or we don't have all of it, we still show the stuff we
2403              * dissect after this, such as stub data.
2404              */
2405             TRY {
2406                 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2407                                                hf_dcerpc_auth_type, 
2408                                                &auth_info->auth_type);
2409                 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2410                                                hf_dcerpc_auth_level, 
2411                                                &auth_info->auth_level);
2412
2413                 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2414                                                hf_dcerpc_auth_pad_len, 
2415                                                &auth_info->auth_pad_len);
2416                 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2417                                                hf_dcerpc_auth_rsrvd, NULL);
2418                 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2419                                                 hf_dcerpc_auth_ctx_id, NULL);
2420
2421                 /*
2422                  * Dissect the authentication data.
2423                  */
2424                 if (are_credentials) {
2425                     tvbuff_t *auth_tvb;
2426                     dcerpc_auth_subdissector_fns *auth_fns;
2427
2428                     auth_tvb = tvb_new_subset(tvb, offset, hdr->auth_len,
2429                                               hdr->auth_len);
2430
2431                     if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
2432                                                               auth_info->auth_type)))
2433                         dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns, 
2434                                           hdr, auth_info);
2435                     else
2436                         proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len,
2437                                              "Auth Credentials");
2438                 }
2439         
2440                 /* Compute the size of the auth block.  Note that this should not 
2441                    include auth padding, since when NTLMSSP encryption is used, the
2442                    padding is actually inside the encrypted stub */
2443                    auth_info->auth_size = hdr->auth_len + 8;
2444             } CATCH_ALL {
2445                 show_exception(tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
2446             } ENDTRY;
2447         }
2448     }
2449 }
2450
2451
2452 /* We need to hash in the SMB fid number to generate a unique hash table
2453  * key as DCERPC over SMB allows several pipes over the same TCP/IP
2454  * socket. 
2455  * We pass this function the transport type here to make sure we only look
2456  * at this function if it came across an SMB pipe.
2457  * Other transports might need to mix in their own extra multiplexing data
2458  * as well in the future.
2459  */
2460
2461 guint16 dcerpc_get_transport_salt (packet_info *pinfo)
2462 {
2463     switch(pinfo->dcetransporttype){
2464         case DCE_CN_TRANSPORT_SMBPIPE:
2465             /* DCERPC over smb */
2466             return pinfo->dcetransportsalt;
2467     }
2468
2469     /* Some other transport... */
2470     return 0;
2471 }
2472
2473 /*
2474  * Connection oriented packet types
2475  */
2476
2477 static void
2478 dissect_dcerpc_cn_bind (tvbuff_t *tvb, gint offset, packet_info *pinfo, 
2479                         proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2480 {
2481     conversation_t *conv = NULL;
2482     guint8 num_ctx_items = 0;
2483     guint i;
2484     gboolean saw_ctx_item = FALSE;
2485     guint16 ctx_id;
2486     guint8 num_trans_items;
2487     guint j;
2488     e_uuid_t if_id;
2489     e_uuid_t trans_id;
2490     guint32 trans_ver;
2491     guint16 if_ver, if_ver_minor;
2492     char uuid_str[DCERPC_UUID_STR_LEN]; 
2493     int uuid_str_len;
2494     dcerpc_auth_info auth_info;
2495 #ifdef _WIN32
2496     char UUID_NAME[MAX_PATH];
2497 #endif
2498
2499     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2500                                     hf_dcerpc_cn_max_xmit, NULL);
2501
2502     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2503                                     hf_dcerpc_cn_max_recv, NULL);
2504
2505     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2506                                     hf_dcerpc_cn_assoc_group, NULL);
2507
2508     offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2509                                     hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
2510
2511     /* padding */
2512     offset += 3;
2513
2514     for (i = 0; i < num_ctx_items; i++) {
2515             proto_tree *ctx_tree = NULL, *iface_tree = NULL;
2516
2517       offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, NULL, hdr->drep,
2518                                       hf_dcerpc_cn_ctx_id, &ctx_id);
2519
2520       /* save context ID for use with dcerpc_add_conv_to_bind_table() */
2521       /* (if we have multiple contexts, this might cause "decode as"
2522        *  to behave unpredictably) */
2523       pinfo->dcectxid = ctx_id;
2524
2525       if (dcerpc_tree) {
2526               proto_item *ctx_item;
2527
2528               ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_id,
2529                                              tvb, offset - 2, 2, 
2530                                              hdr->drep[0] & 0x10);
2531
2532               ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
2533       }
2534
2535       offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, ctx_tree, hdr->drep,
2536                                       hf_dcerpc_cn_num_trans_items, &num_trans_items);
2537
2538       /* padding */
2539       offset += 1;
2540
2541       /* XXX - use "dissect_ndr_uuid_t()"? */
2542       dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
2543       if (ctx_tree) {
2544           proto_item *iface_item;
2545
2546           uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, 
2547                                   "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2548                                   if_id.Data1, if_id.Data2, if_id.Data3,
2549                                   if_id.Data4[0], if_id.Data4[1],
2550                                   if_id.Data4[2], if_id.Data4[3],
2551                                   if_id.Data4[4], if_id.Data4[5],
2552                                   if_id.Data4[6], if_id.Data4[7]);
2553
2554           if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2555                   memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2556 #ifdef _WIN32
2557           if(ResolveWin32UUID(if_id, UUID_NAME, MAX_PATH))
2558                   iface_item = proto_tree_add_string_format (ctx_tree, hf_dcerpc_cn_bind_if_id, tvb,
2559                                         offset, 16, uuid_str, "Interface [%s] UUID: %s", UUID_NAME, uuid_str);
2560           else
2561 #endif
2562           iface_item = proto_tree_add_string_format (ctx_tree, hf_dcerpc_cn_bind_if_id, tvb,
2563                                         offset, 16, uuid_str, "Interface UUID: %s", uuid_str);
2564           iface_tree = proto_item_add_subtree(iface_item, ett_dcerpc_cn_iface);
2565       }
2566       offset += 16;
2567
2568       if (hdr->drep[0] & 0x10) {
2569           offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2570                                           hf_dcerpc_cn_bind_if_ver, &if_ver);
2571           offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2572                                           hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2573       } else {
2574           offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2575                                           hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2576           offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2577                                           hf_dcerpc_cn_bind_if_ver, &if_ver);
2578       }
2579
2580       if (!saw_ctx_item) {
2581         conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
2582                                   pinfo->srcport, pinfo->destport, 0);
2583         if (conv == NULL) {
2584             conv = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
2585                                      pinfo->srcport, pinfo->destport, 0);
2586         }
2587
2588
2589         /* if this is the first time we see this packet, we need to
2590            update the dcerpc_binds table so that any later calls can
2591            match to the interface.
2592            XXX We assume that BINDs will NEVER be fragmented.
2593         */
2594         if(!(pinfo->fd->flags.visited)){
2595                 dcerpc_bind_key *key;
2596                 dcerpc_bind_value *value;
2597
2598                 key = g_mem_chunk_alloc (dcerpc_bind_key_chunk);
2599                 key->conv = conv;
2600                 key->ctx_id = ctx_id;
2601                 key->smb_fid = dcerpc_get_transport_salt(pinfo);
2602
2603                 value = g_mem_chunk_alloc (dcerpc_bind_value_chunk);
2604                 value->uuid = if_id;
2605                 value->ver = if_ver;
2606
2607                 /* add this entry to the bind table, first removing any
2608                    previous ones that are identical
2609                  */
2610                 if(g_hash_table_lookup(dcerpc_binds, key)){
2611                         g_hash_table_remove(dcerpc_binds, key);
2612                 }
2613                 g_hash_table_insert (dcerpc_binds, key, value);
2614         }
2615
2616         if (check_col (pinfo->cinfo, COL_INFO)) {
2617           dcerpc_uuid_key key;
2618           dcerpc_uuid_value *value;
2619
2620           key.uuid = if_id;
2621           key.ver = if_ver;
2622
2623           if (num_ctx_items > 1)
2624                   col_append_fstr(pinfo->cinfo, COL_INFO, ", %u context items, 1st", num_ctx_items);
2625                 
2626           if ((value = g_hash_table_lookup(dcerpc_uuids, &key)))
2627                   col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %s", value->name);
2628           else
2629 #ifdef _WIN32
2630                 if(ResolveWin32UUID(if_id, UUID_NAME, MAX_PATH))
2631                         col_append_fstr(pinfo->cinfo, COL_INFO, " [%s] UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
2632                            UUID_NAME, if_id.Data1, if_id.Data2, if_id.Data3,
2633                            if_id.Data4[0], if_id.Data4[1],
2634                            if_id.Data4[2], if_id.Data4[3],
2635                            if_id.Data4[4], if_id.Data4[5],
2636                            if_id.Data4[6], if_id.Data4[7],
2637                            if_ver, if_ver_minor);
2638           else
2639 #endif
2640                         col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
2641                            if_id.Data1, if_id.Data2, if_id.Data3,
2642                            if_id.Data4[0], if_id.Data4[1],
2643                            if_id.Data4[2], if_id.Data4[3],
2644                            if_id.Data4[4], if_id.Data4[5],
2645                            if_id.Data4[6], if_id.Data4[7],
2646                            if_ver, if_ver_minor);
2647         }
2648         saw_ctx_item = TRUE;
2649       }
2650
2651       for (j = 0; j < num_trans_items; j++) {
2652         /* XXX - use "dissect_ndr_uuid_t()"? */
2653         dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2654         if (iface_tree) {
2655             uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, 
2656                                   "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2657                                   trans_id.Data1, trans_id.Data2, trans_id.Data3,
2658                                   trans_id.Data4[0], trans_id.Data4[1],
2659                                   trans_id.Data4[2], trans_id.Data4[3],
2660                                   trans_id.Data4[4], trans_id.Data4[5],
2661                                   trans_id.Data4[6], trans_id.Data4[7]);
2662             if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2663                 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2664             proto_tree_add_string_format (iface_tree, hf_dcerpc_cn_bind_trans_id, tvb,
2665                                           offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2666         }
2667         offset += 16;
2668
2669         offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, iface_tree, hdr->drep,
2670                                         hf_dcerpc_cn_bind_trans_ver, &trans_ver);
2671       }
2672     }
2673
2674     /*
2675      * XXX - we should save the authentication type *if* we have
2676      * an authentication header, and associate it with an authentication
2677      * context, so subsequent PDUs can use that context.
2678      */
2679     dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2680 }
2681
2682 static void
2683 dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, gint offset, packet_info *pinfo, 
2684                             proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2685 {
2686     guint16 max_xmit, max_recv;
2687     guint16 sec_addr_len;
2688     guint8 num_results;
2689     guint i;
2690     guint16 result;
2691     guint16 reason;
2692     e_uuid_t trans_id;
2693     guint32 trans_ver;
2694     char uuid_str[DCERPC_UUID_STR_LEN]; 
2695     int uuid_str_len;
2696     dcerpc_auth_info auth_info;
2697
2698     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2699                                     hf_dcerpc_cn_max_xmit, &max_xmit);
2700
2701     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2702                                     hf_dcerpc_cn_max_recv, &max_recv);
2703
2704     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2705                                     hf_dcerpc_cn_assoc_group, NULL);
2706
2707     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2708                                     hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
2709     if (sec_addr_len != 0) {
2710         proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
2711                              sec_addr_len, FALSE);
2712         offset += sec_addr_len;
2713     }
2714
2715     if (offset % 4) {
2716         offset += 4 - offset % 4;
2717     }
2718
2719     offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2720                                    hf_dcerpc_cn_num_results, &num_results);
2721
2722     /* padding */
2723     offset += 3;
2724
2725     for (i = 0; i < num_results; i++) {
2726         offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2727                                         hdr->drep, hf_dcerpc_cn_ack_result,
2728                                         &result);
2729         if (result != 0) {
2730             offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2731                                             hdr->drep, hf_dcerpc_cn_ack_reason,
2732                                             &reason);
2733         } else {
2734             /*
2735              * The reason for rejection isn't meaningful, and often isn't
2736              * set, when the syntax was accepted.
2737              */
2738             offset += 2;
2739         }
2740
2741         /* XXX - use "dissect_ndr_uuid_t()"? */
2742         dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2743         if (dcerpc_tree) {
2744             uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, 
2745                                   "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2746                                   trans_id.Data1, trans_id.Data2, trans_id.Data3,
2747                                   trans_id.Data4[0], trans_id.Data4[1],
2748                                   trans_id.Data4[2], trans_id.Data4[3],
2749                                   trans_id.Data4[4], trans_id.Data4[5],
2750                                   trans_id.Data4[6], trans_id.Data4[7]);
2751             if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2752                   memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2753             proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_ack_trans_id, tvb,
2754                                           offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2755         }
2756         offset += 16;
2757
2758         offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2759                                         hf_dcerpc_cn_ack_trans_ver, &trans_ver);
2760     }
2761
2762     /*
2763      * XXX - do we need to do anything with the authentication level
2764      * we get back from this?
2765      */
2766     dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2767
2768     if (check_col (pinfo->cinfo, COL_INFO)) {
2769         if (num_results != 0 && result == 0) {
2770             /* XXX - only checks the last result */
2771             col_append_fstr (pinfo->cinfo, COL_INFO,
2772                              " accept max_xmit: %u max_recv: %u",
2773                              max_xmit, max_recv);
2774         } else {
2775             /* XXX - only shows the last result and reason */
2776             col_append_fstr (pinfo->cinfo, COL_INFO, " %s, reason: %s",
2777                              val_to_str(result, p_cont_result_vals,
2778                                         "Unknown result (%u)"),
2779                              val_to_str(reason, p_provider_reason_vals,
2780                                         "Unknown (%u)"));
2781         }
2782     }
2783 }
2784
2785 static void
2786 dissect_dcerpc_cn_bind_nak (tvbuff_t *tvb, gint offset, packet_info *pinfo, 
2787                             proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2788 {
2789     guint16 reason;
2790     guint8 num_protocols;
2791     guint i;
2792
2793     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2794                                     hdr->drep, hf_dcerpc_cn_reject_reason,
2795                                     &reason);
2796
2797     if (check_col (pinfo->cinfo, COL_INFO)) {
2798         col_append_fstr (pinfo->cinfo, COL_INFO, " reason: %s",
2799                       val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
2800     }
2801
2802     if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
2803         offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2804                                        hf_dcerpc_cn_num_protocols,
2805                                        &num_protocols);
2806
2807         for (i = 0; i < num_protocols; i++) {
2808             offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2809                                         hdr->drep, hf_dcerpc_cn_protocol_ver_major,
2810                                         NULL);
2811             offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2812                                         hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
2813                                         NULL);
2814         }
2815     }
2816 }
2817
2818 /* Return a string describing a DCE/RPC fragment as first, middle, or end
2819    fragment. */
2820
2821 #define PFC_FRAG_MASK  0x03
2822
2823 static char *
2824 fragment_type(guint8 flags)
2825 {
2826         flags = flags & PFC_FRAG_MASK;
2827
2828         if (flags == PFC_FIRST_FRAG)
2829                 return "first";
2830
2831         if (flags == 0)
2832                 return "middle";
2833
2834         if (flags == PFC_LAST_FRAG)
2835                 return "last";
2836
2837         if (flags == (PFC_FIRST_FRAG | PFC_LAST_FRAG))
2838                 return "whole";
2839
2840         return "unknown";
2841 }
2842
2843 /* Dissect stub data (payload) of a DCERPC packet. */
2844
2845 static void
2846 dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
2847                         proto_tree *dcerpc_tree, proto_tree *tree,
2848                         e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
2849                         dcerpc_auth_info *auth_info, guint32 alloc_hint,
2850                         guint32 frame)
2851 {
2852     gint length, reported_length;
2853     gboolean save_fragmented;
2854     fragment_data *fd_head=NULL;
2855     guint32 tot_len;
2856     tvbuff_t *payload_tvb, *decrypted_tvb;
2857     proto_item *pi;
2858
2859     save_fragmented = pinfo->fragmented;
2860
2861     length = tvb_length_remaining(tvb, offset);
2862     reported_length = tvb_reported_length_remaining(tvb, offset);
2863     if (reported_length < 0 ||
2864         (guint32)reported_length < auth_info->auth_size) {
2865         /* We don't even have enough bytes for the authentication
2866            stuff. */
2867         return;
2868     }
2869     reported_length -= auth_info->auth_size;
2870     if (length > reported_length)
2871         length = reported_length;
2872     payload_tvb = tvb_new_subset(tvb, offset, length, reported_length);
2873
2874     /* Decrypt the PDU if it is encrypted */
2875
2876     if (auth_info->auth_type &&
2877         auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
2878             /*
2879              * We know the authentication type, and the authentication
2880              * level is "Packet privacy", meaning the payload is
2881              * encrypted; attempt to decrypt it.
2882              */
2883             dcerpc_auth_subdissector_fns *auth_fns;
2884             
2885             /* Start out assuming we won't succeed in decrypting. */
2886             decrypted_tvb = NULL;
2887
2888             if ((auth_fns = get_auth_subdissector_fns(
2889                          auth_info->auth_level, auth_info->auth_type))) {
2890                     tvbuff_t *result;
2891                     
2892                     result = decode_encrypted_data(
2893                             payload_tvb, pinfo, auth_fns,
2894                             hdr->ptype == PDU_REQ, auth_info);      
2895                     
2896                     if (result) {
2897                             if (dcerpc_tree)
2898                                 proto_tree_add_text(
2899                                             dcerpc_tree, payload_tvb, 0, -1,
2900                                             "Encrypted stub data (%d byte%s)",
2901                                             tvb_reported_length(payload_tvb),
2902
2903                             plurality(tvb_length(payload_tvb), "", "s"));
2904
2905                             add_new_data_source(
2906                                     pinfo, result, "Decrypted stub data");
2907                             
2908                             /* We succeeded. */
2909                             decrypted_tvb = result;
2910                     }
2911             }
2912     } else
2913             decrypted_tvb = payload_tvb;
2914
2915     /* if this packet is not fragmented, just dissect it and exit */
2916     if(PFC_NOT_FRAGMENTED(hdr)){
2917         pinfo->fragmented = FALSE;
2918
2919         dcerpc_try_handoff(
2920                 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
2921                 hdr->drep, di, auth_info);
2922         
2923         pinfo->fragmented = save_fragmented;
2924         return;
2925     }
2926
2927     /* The packet is fragmented. */
2928     pinfo->fragmented = TRUE;
2929
2930     /* if we are not doing reassembly and this is the first fragment
2931        then just dissect it and exit
2932        XXX - if we're not doing reassembly, can we decrypt an
2933        encrypted stub?
2934     */
2935     if( (!dcerpc_reassemble) && hdr->flags&PFC_FIRST_FRAG ){
2936
2937         dcerpc_try_handoff(
2938                 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
2939                 hdr->drep, di, auth_info);
2940         
2941         if (check_col(pinfo->cinfo, COL_INFO)) {
2942             col_append_fstr(pinfo->cinfo, COL_INFO,
2943                             " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
2944         }
2945         pinfo->fragmented = save_fragmented;
2946         return;
2947     }
2948
2949     /* if we have already seen this packet, see if it was reassembled
2950        and if so dissect the full pdu.
2951        then exit 
2952     */
2953     if(pinfo->fd->flags.visited){
2954         fd_head=fragment_get(pinfo, frame, dcerpc_co_reassemble_table);
2955         goto end_cn_stub;
2956     }
2957
2958     /* if we are not doing reassembly and it was neither a complete PDU
2959        nor the first fragment then there is nothing more we can do
2960        so we just have to exit
2961     */
2962     if( !dcerpc_reassemble )
2963         goto end_cn_stub;
2964
2965     /* if we didnt get 'frame' we dont know where the PDU started and thus
2966        it is pointless to continue 
2967     */
2968     if(!frame)
2969         goto end_cn_stub;
2970
2971     /* from now on we must attempt to reassemble the PDU 
2972     */
2973
2974     /* if we get here we know it is the first time we see the packet
2975        and we also know it is only a fragment and not a full PDU,
2976        thus we must reassemble it.
2977     */
2978
2979     /* Do we have any non-encrypted data to reassemble? */
2980     if (decrypted_tvb == NULL) {
2981       /* No.  We can't even try to reassemble.  */
2982       goto end_cn_stub;
2983     }
2984
2985     /* defragmentation is a bit tricky here, as there's no offset of the fragment 
2986      * in the protocol data.
2987      *
2988      * Currently two possible ways:
2989      * - the transmitter sends an alloc_hint != 0, use it
2990      * - the transmitter sends an alloc_hint == 0, simply append fragments
2991      */
2992
2993     /* if this is the first fragment we need to start reassembly
2994     */
2995     if(hdr->flags&PFC_FIRST_FRAG){
2996         fragment_add(decrypted_tvb, 0, pinfo, frame, dcerpc_co_reassemble_table,
2997                      0, tvb_length(decrypted_tvb), TRUE);
2998         fragment_set_tot_len(pinfo, frame,
2999         dcerpc_co_reassemble_table, alloc_hint ? alloc_hint : tvb_length(decrypted_tvb));
3000
3001         goto end_cn_stub;
3002     }
3003
3004     /* if this is a middle fragment, just add it and exit */
3005     if(!(hdr->flags&PFC_LAST_FRAG)){
3006         tot_len = fragment_get_tot_len(pinfo, frame,
3007                  dcerpc_co_reassemble_table);
3008         fragment_add(decrypted_tvb, 0, pinfo, frame,
3009                  dcerpc_co_reassemble_table,
3010                  tot_len-alloc_hint, tvb_length(decrypted_tvb),
3011                  TRUE);
3012         if(alloc_hint == 0) {
3013              fragment_set_tot_len(pinfo, frame,
3014                   dcerpc_co_reassemble_table, tot_len + tvb_length(decrypted_tvb));
3015         }
3016
3017         goto end_cn_stub;
3018     }
3019
3020     /* this was the last fragment add it to reassembly
3021     */
3022     tot_len = fragment_get_tot_len(pinfo, frame,
3023                 dcerpc_co_reassemble_table);
3024     fd_head = fragment_add(decrypted_tvb, 0, pinfo,
3025                 frame,
3026                 dcerpc_co_reassemble_table,
3027                 tot_len-alloc_hint, tvb_length(decrypted_tvb),
3028                 TRUE);
3029         if(alloc_hint == 0) {           
3030             fragment_set_tot_len(pinfo, frame,
3031                   dcerpc_co_reassemble_table, tot_len + tvb_length(decrypted_tvb));
3032     }
3033
3034 end_cn_stub:
3035
3036     /* if reassembly is complete, dissect the full PDU
3037     */
3038     if(fd_head && (fd_head->flags&FD_DEFRAGMENTED) ){
3039
3040         if(pinfo->fd->num==fd_head->reassembled_in){
3041             tvbuff_t *next_tvb;
3042
3043             next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
3044             tvb_set_child_real_data_tvbuff(decrypted_tvb, next_tvb);
3045             add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3046             show_fragment_tree(fd_head, &dcerpc_frag_items,
3047                 dcerpc_tree, pinfo, next_tvb);
3048
3049             pinfo->fragmented = FALSE;
3050
3051             dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
3052                 next_tvb, hdr->drep, di, auth_info);
3053
3054         } else {
3055             pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
3056                                 decrypted_tvb, 0, 0, fd_head->reassembled_in);
3057         PROTO_ITEM_SET_GENERATED(pi);
3058             if (check_col(pinfo->cinfo, COL_INFO)) {
3059                 col_append_fstr(pinfo->cinfo, COL_INFO,
3060                         " [DCE/RPC %s fragment, reas: #%u]", fragment_type(hdr->flags), fd_head->reassembled_in);
3061             }
3062         }
3063     } else {
3064         /* Reassembly not complete - some fragments
3065            are missing.  Just show the stub data. */
3066
3067         if (check_col(pinfo->cinfo, COL_INFO)) {
3068             col_append_fstr(pinfo->cinfo, COL_INFO,
3069                         " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
3070         }
3071
3072         if(decrypted_tvb){
3073                 show_stub_data (decrypted_tvb, 0, tree, auth_info, FALSE);
3074         } else {
3075                 show_stub_data (payload_tvb, 0, tree, auth_info, TRUE);
3076         }
3077     }
3078
3079     pinfo->fragmented = save_fragmented;
3080 }
3081
3082 /**
3083  *  Registers a conversation/UUID binding association, so that
3084  *  we can invoke the proper sub-dissector for a given DCERPC
3085  *  conversation.
3086  *