char -> const char warning fixes
[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         { 0x00000001, "nca_s_fault_other" },
242         { 0x00000005, "nca_s_fault_access_denied" },
243         { 0x000006f7, "nca_s_fault_ndr" },
244         { 0x000006d8, "nca_s_fault_cant_perform" },
245         { 0x1c000001, "nca_s_fault_int_div_by_zero" },
246         { 0x1c000002, "nca_s_fault_addr_error" },
247         { 0x1c000003, "nca_s_fault_fp_div_zero" },
248         { 0x1c000004, "nca_s_fault_fp_underflow" },
249         { 0x1c000005, "nca_s_fault_fp_overflow" },
250         { 0x1c000006, "nca_s_fault_invalid_tag" },
251         { 0x1c000007, "nca_s_fault_invalid_bound" },
252         { 0x1c000008, "nca_rpc_version_mismatch" },
253         { 0x1c000009, "nca_unspec_reject" },
254         { 0x1c00000a, "nca_s_bad_actid" },
255         { 0x1c00000b, "nca_who_are_you_failed" },
256         { 0x1c00000c, "nca_manager_not_entered" },
257         { 0x1c00000d, "nca_s_fault_cancel" },
258         { 0x1c00000e, "nca_s_fault_ill_inst" },
259         { 0x1c00000f, "nca_s_fault_fp_error" },
260         { 0x1c000010, "nca_s_fault_int_overflow" },
261         { 0x1c000014, "nca_s_fault_pipe_empty" },
262         { 0x1c000015, "nca_s_fault_pipe_closed" },
263         { 0x1c000016, "nca_s_fault_pipe_order" },
264         { 0x1c000017, "nca_s_fault_pipe_discipline" },
265         { 0x1c000018, "nca_s_fault_pipe_comm_error" },
266         { 0x1c000019, "nca_s_fault_pipe_memory" },
267         { 0x1c00001a, "nca_s_fault_context_mismatch" },
268         { 0x1c00001b, "nca_s_fault_remote_no_memory" },
269         { 0x1c00001c, "nca_invalid_pres_context_id" },
270         { 0x1c00001d, "nca_unsupported_authn_level" },
271         { 0x1c00001f, "nca_invalid_checksum" },
272         { 0x1c000020, "nca_invalid_crc" },
273         { 0x1c000021, "ncs_s_fault_user_defined" },
274         { 0x1c000022, "nca_s_fault_tx_open_failed" },
275         { 0x1c000023, "nca_s_fault_codeset_conv_error" },
276         { 0x1c000024, "nca_s_fault_object_not_found" },
277         { 0x1c000025, "nca_s_fault_no_client_stub" },
278         { 0x1c010002, "nca_op_rng_error" },
279         { 0x1c010003, "nca_unk_if"},
280         { 0x1c010006, "nca_wrong_boot_time" },
281         { 0x1c010009, "nca_s_you_crashed" },
282         { 0x1c01000b, "nca_proto_error" },
283         { 0x1c010013, "nca_out_args_too_big" },
284         { 0x1c010014, "nca_server_too_busy" },
285         { 0x1c010017, "nca_unsupported_type" },
286         { 0,          NULL }
287 };
288
289
290 /* we need to keep track of what transport were used, ie what handle we came
291  * in through so we know what kind of pinfo->dce_smb_fid was passed to us.
292  */
293 /* Value of -1 is reserved for "not DCE packet" in packet_info.dcetransporttype. */
294 #define DCE_TRANSPORT_UNKNOWN           0
295 #define DCE_CN_TRANSPORT_SMBPIPE        1
296
297
298 static int proto_dcerpc = -1;
299
300 /* field defines */
301 static int hf_dcerpc_request_in = -1;
302 static int hf_dcerpc_time = -1;
303 static int hf_dcerpc_response_in = -1;
304 static int hf_dcerpc_ver = -1;
305 static int hf_dcerpc_ver_minor = -1;
306 static int hf_dcerpc_packet_type = -1;
307 static int hf_dcerpc_cn_flags = -1;
308 static int hf_dcerpc_cn_flags_first_frag = -1;
309 static int hf_dcerpc_cn_flags_last_frag = -1;
310 static int hf_dcerpc_cn_flags_cancel_pending = -1;
311 static int hf_dcerpc_cn_flags_reserved = -1;
312 static int hf_dcerpc_cn_flags_mpx = -1;
313 static int hf_dcerpc_cn_flags_dne = -1;
314 static int hf_dcerpc_cn_flags_maybe = -1;
315 static int hf_dcerpc_cn_flags_object = -1;
316 static int hf_dcerpc_drep = -1;
317 static int hf_dcerpc_drep_byteorder = -1;
318 static int hf_dcerpc_drep_character = -1;
319 static int hf_dcerpc_drep_fp = -1;
320 static int hf_dcerpc_cn_frag_len = -1;
321 static int hf_dcerpc_cn_auth_len = -1;
322 static int hf_dcerpc_cn_call_id = -1;
323 static int hf_dcerpc_cn_max_xmit = -1;
324 static int hf_dcerpc_cn_max_recv = -1;
325 static int hf_dcerpc_cn_assoc_group = -1;
326 static int hf_dcerpc_cn_num_ctx_items = -1;
327 static int hf_dcerpc_cn_ctx_id = -1;
328 static int hf_dcerpc_cn_num_trans_items = -1;
329 static int hf_dcerpc_cn_bind_if_id = -1;
330 static int hf_dcerpc_cn_bind_if_ver = -1;
331 static int hf_dcerpc_cn_bind_if_ver_minor = -1;
332 static int hf_dcerpc_cn_bind_trans_id = -1;
333 static int hf_dcerpc_cn_bind_trans_ver = -1;
334 static int hf_dcerpc_cn_alloc_hint = -1;
335 static int hf_dcerpc_cn_sec_addr_len = -1;
336 static int hf_dcerpc_cn_sec_addr = -1;
337 static int hf_dcerpc_cn_num_results = -1;
338 static int hf_dcerpc_cn_ack_result = -1;
339 static int hf_dcerpc_cn_ack_reason = -1;
340 static int hf_dcerpc_cn_ack_trans_id = -1;
341 static int hf_dcerpc_cn_ack_trans_ver = -1;
342 static int hf_dcerpc_cn_reject_reason = -1;
343 static int hf_dcerpc_cn_num_protocols = -1;
344 static int hf_dcerpc_cn_protocol_ver_major = -1;
345 static int hf_dcerpc_cn_protocol_ver_minor = -1;
346 static int hf_dcerpc_cn_cancel_count = -1;
347 static int hf_dcerpc_cn_status = -1;
348 static int hf_dcerpc_cn_deseg_req = -1;
349 static int hf_dcerpc_auth_type = -1;
350 static int hf_dcerpc_auth_level = -1;
351 static int hf_dcerpc_auth_pad_len = -1;
352 static int hf_dcerpc_auth_rsrvd = -1;
353 static int hf_dcerpc_auth_ctx_id = -1;
354 static int hf_dcerpc_dg_flags1 = -1;
355 static int hf_dcerpc_dg_flags1_rsrvd_01 = -1;
356 static int hf_dcerpc_dg_flags1_last_frag = -1;
357 static int hf_dcerpc_dg_flags1_frag = -1;
358 static int hf_dcerpc_dg_flags1_nofack = -1;
359 static int hf_dcerpc_dg_flags1_maybe = -1;
360 static int hf_dcerpc_dg_flags1_idempotent = -1;
361 static int hf_dcerpc_dg_flags1_broadcast = -1;
362 static int hf_dcerpc_dg_flags1_rsrvd_80 = -1;
363 static int hf_dcerpc_dg_flags2 = -1;
364 static int hf_dcerpc_dg_flags2_rsrvd_01 = -1;
365 static int hf_dcerpc_dg_flags2_cancel_pending = -1;
366 static int hf_dcerpc_dg_flags2_rsrvd_04 = -1;
367 static int hf_dcerpc_dg_flags2_rsrvd_08 = -1;
368 static int hf_dcerpc_dg_flags2_rsrvd_10 = -1;
369 static int hf_dcerpc_dg_flags2_rsrvd_20 = -1;
370 static int hf_dcerpc_dg_flags2_rsrvd_40 = -1;
371 static int hf_dcerpc_dg_flags2_rsrvd_80 = -1;
372 static int hf_dcerpc_dg_serial_hi = -1;
373 static int hf_dcerpc_obj_id = -1;
374 static int hf_dcerpc_dg_if_id = -1;
375 static int hf_dcerpc_dg_act_id = -1;
376 static int hf_dcerpc_dg_serial_lo = -1;
377 static int hf_dcerpc_dg_ahint = -1;
378 static int hf_dcerpc_dg_ihint = -1;
379 static int hf_dcerpc_dg_frag_len = -1;
380 static int hf_dcerpc_dg_frag_num = -1;
381 static int hf_dcerpc_dg_auth_proto = -1;
382 static int hf_dcerpc_opnum = -1;
383 static int hf_dcerpc_dg_seqnum = -1;
384 static int hf_dcerpc_dg_server_boot = -1;
385 static int hf_dcerpc_dg_if_ver = -1;
386 static int hf_dcerpc_krb5_av_prot_level = -1;
387 static int hf_dcerpc_krb5_av_key_vers_num = -1;
388 static int hf_dcerpc_krb5_av_key_auth_verifier = -1;
389 static int hf_dcerpc_dg_cancel_vers = -1;
390 static int hf_dcerpc_dg_cancel_id = -1;
391 static int hf_dcerpc_dg_server_accepting_cancels = -1;
392 static int hf_dcerpc_dg_fack_vers = -1;
393 static int hf_dcerpc_dg_fack_window_size = -1;
394 static int hf_dcerpc_dg_fack_max_tsdu = -1;
395 static int hf_dcerpc_dg_fack_max_frag_size = -1;
396 static int hf_dcerpc_dg_fack_serial_num = -1;
397 static int hf_dcerpc_dg_fack_selack_len = -1;
398 static int hf_dcerpc_dg_fack_selack = -1;
399 static int hf_dcerpc_dg_status = -1;
400 static int hf_dcerpc_array_max_count = -1;
401 static int hf_dcerpc_array_offset = -1;
402 static int hf_dcerpc_array_actual_count = -1;
403 static int hf_dcerpc_array_buffer = -1;
404 static int hf_dcerpc_op = -1;
405 static int hf_dcerpc_referent_id = -1;
406 static int hf_dcerpc_fragments = -1;
407 static int hf_dcerpc_fragment = -1;
408 static int hf_dcerpc_fragment_overlap = -1;
409 static int hf_dcerpc_fragment_overlap_conflict = -1;
410 static int hf_dcerpc_fragment_multiple_tails = -1;
411 static int hf_dcerpc_fragment_too_long_fragment = -1;
412 static int hf_dcerpc_fragment_error = -1;
413 static int hf_dcerpc_reassembled_in = -1;
414 static int hf_dcerpc_unknown_if_id = -1;
415
416 static gint ett_dcerpc = -1;
417 static gint ett_dcerpc_cn_flags = -1;
418 static gint ett_dcerpc_cn_ctx = -1;
419 static gint ett_dcerpc_cn_iface = -1;
420 static gint ett_dcerpc_drep = -1;
421 static gint ett_dcerpc_dg_flags1 = -1;
422 static gint ett_dcerpc_dg_flags2 = -1;
423 static gint ett_dcerpc_pointer_data = -1;
424 static gint ett_dcerpc_string = -1;
425 static gint ett_dcerpc_fragments = -1;
426 static gint ett_dcerpc_fragment = -1;
427 static gint ett_dcerpc_krb5_auth_verf = -1;
428
429 static const fragment_items dcerpc_frag_items = {
430         &ett_dcerpc_fragments,
431         &ett_dcerpc_fragment,
432
433         &hf_dcerpc_fragments,
434         &hf_dcerpc_fragment,
435         &hf_dcerpc_fragment_overlap,
436         &hf_dcerpc_fragment_overlap_conflict,
437         &hf_dcerpc_fragment_multiple_tails,
438         &hf_dcerpc_fragment_too_long_fragment,
439         &hf_dcerpc_fragment_error,
440         NULL,
441
442         "fragments"
443 };
444
445 /* list of hooks to be called when init_protocols is done */
446 GHookList dcerpc_hooks_init_protos;
447
448 #ifdef _WIN32
449 int ResolveWin32UUID(e_uuid_t if_id, char *UUID_NAME, int UUID_NAME_MAX_LEN)
450 {
451         char REG_UUID_NAME[MAX_PATH];
452         HKEY hKey = NULL;
453         DWORD UUID_MAX_SIZE = MAX_PATH;
454         char REG_UUID_STR[MAX_PATH];
455         
456         if(UUID_NAME_MAX_LEN < 2)
457                 return 0;
458         REG_UUID_NAME[0] = '\0';
459         snprintf(REG_UUID_STR, MAX_PATH, "SOFTWARE\\Classes\\Interface\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
460                         if_id.Data1, if_id.Data2, if_id.Data3,
461                         if_id.Data4[0], if_id.Data4[1],
462                         if_id.Data4[2], if_id.Data4[3],
463                         if_id.Data4[4], if_id.Data4[5],
464                         if_id.Data4[6], if_id.Data4[7]);
465         if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCSTR)REG_UUID_STR, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
466         {
467                 if (RegQueryValueEx(hKey, NULL, NULL, NULL, (LPBYTE)REG_UUID_NAME, &UUID_MAX_SIZE) == ERROR_SUCCESS && UUID_MAX_SIZE <= MAX_PATH)
468                         {
469                         snprintf(UUID_NAME, UUID_NAME_MAX_LEN, "%s", REG_UUID_NAME);
470                         RegCloseKey(hKey);
471                         return strlen(REG_UUID_NAME);
472                 }
473                 RegCloseKey(hKey);
474         }
475         return 0; /* we didn't find anything anyhow. Please don't use the string! */
476         
477 }
478 #endif
479
480 static dcerpc_info *
481 get_next_di(void)
482 {
483         static dcerpc_info di[20];
484         static int di_counter=0;
485
486         di_counter++;
487         if(di_counter>=20){
488                 di_counter=0;
489         }
490         return &di[di_counter];
491 }
492
493 /* try to desegment big DCE/RPC packets over TCP? */
494 static gboolean dcerpc_cn_desegment = TRUE;
495
496 /* reassemble DCE/RPC fragments */
497 /* reassembly of dcerpc fragments will not work for the case where ONE frame
498    might contain multiple dcerpc fragments for different PDUs.
499    this case would be so unusual/weird so if you got captures like that:
500         too bad
501 */
502 static gboolean dcerpc_reassemble = FALSE;
503 static GHashTable *dcerpc_co_reassemble_table = NULL;
504 static GHashTable *dcerpc_cl_reassemble_table = NULL;
505
506 static void
507 dcerpc_reassemble_init(void)
508 {
509   fragment_table_init(&dcerpc_co_reassemble_table);
510   dcerpc_fragment_table_init(&dcerpc_cl_reassemble_table);
511 }
512
513 /*
514  * Authentication subdissectors.  Used to dissect authentication blobs in
515  * DCERPC binds, requests and responses.
516  */
517
518 typedef struct _dcerpc_auth_subdissector {
519         guint8 auth_level;
520         guint8 auth_type;
521         dcerpc_auth_subdissector_fns auth_fns;
522 } dcerpc_auth_subdissector;
523
524 static GSList *dcerpc_auth_subdissector_list;
525
526 static dcerpc_auth_subdissector_fns *get_auth_subdissector_fns(
527         guint8 auth_level, guint8 auth_type)
528 {
529         gpointer data;
530         int i;
531
532         for (i = 0; (data = g_slist_nth_data(dcerpc_auth_subdissector_list, i)); i++) {
533                 dcerpc_auth_subdissector *asd = (dcerpc_auth_subdissector *)data;
534
535                 if (asd->auth_level == auth_level && 
536                     asd->auth_type == auth_type)
537                         return &asd->auth_fns;
538         }
539
540         return NULL;
541 }
542
543 void register_dcerpc_auth_subdissector(guint8 auth_level, guint8 auth_type,
544                                        dcerpc_auth_subdissector_fns *fns)
545 {
546         dcerpc_auth_subdissector *d;
547
548         if (get_auth_subdissector_fns(auth_level, auth_type))
549                 return;
550
551         d = (dcerpc_auth_subdissector *)g_malloc(sizeof(dcerpc_auth_subdissector));
552
553         d->auth_level = auth_level;
554         d->auth_type = auth_type;
555         memcpy(&d->auth_fns, fns, sizeof(dcerpc_auth_subdissector_fns));
556
557         dcerpc_auth_subdissector_list = g_slist_append(dcerpc_auth_subdissector_list, d);
558 }
559
560 /* Hand off verifier data to a registered dissector */
561
562 static void dissect_auth_verf(tvbuff_t *auth_tvb, packet_info *pinfo,
563                               proto_tree *tree, 
564                               dcerpc_auth_subdissector_fns *auth_fns,
565                               e_dce_cn_common_hdr_t *hdr, 
566                               dcerpc_auth_info *auth_info)
567 {
568         dcerpc_dissect_fnct_t *volatile fn = NULL;
569
570         switch (hdr->ptype) {
571         case PDU_BIND:
572         case PDU_ALTER:
573                 fn = auth_fns->bind_fn;
574                 break;
575         case PDU_BIND_ACK:
576         case PDU_ALTER_ACK:
577                 fn = auth_fns->bind_ack_fn;
578                 break;
579         case PDU_AUTH3:
580                 fn = auth_fns->auth3_fn;
581                 break;
582         case PDU_REQ:
583                 fn = auth_fns->req_verf_fn;
584                 break;
585         case PDU_RESP:
586                 fn = auth_fns->resp_verf_fn;
587                 break;
588
589                 /* Don't know how to handle authentication data in this 
590                    pdu type. */
591
592         default:
593                 g_warning("attempt to dissect %s pdu authentication data",
594                           val_to_str(hdr->ptype, pckt_vals, "Unknown (%u)"));
595                 break;
596         }
597
598         if (fn)
599                 fn(auth_tvb, 0, pinfo, tree, hdr->drep);
600         else {
601                 tvb_ensure_bytes_exist(auth_tvb, 0, hdr->auth_len);
602                 proto_tree_add_text(tree, auth_tvb, 0, hdr->auth_len,
603                                     "%s Verifier", 
604                                     val_to_str(auth_info->auth_type, 
605                                                authn_protocol_vals,
606                                                "Unknown (%u)"));
607         }
608 }
609
610 /* Hand off payload data to a registered dissector */
611
612 static tvbuff_t *decode_encrypted_data(tvbuff_t *data_tvb, 
613                                        tvbuff_t *auth_tvb,
614                                        packet_info *pinfo,
615                                        dcerpc_auth_subdissector_fns *auth_fns,
616                                        gboolean is_request, 
617                                        dcerpc_auth_info *auth_info)
618 {
619         dcerpc_decode_data_fnct_t *fn;
620
621         if (is_request)
622                 fn = auth_fns->req_data_fn;
623         else
624                 fn = auth_fns->resp_data_fn;
625
626         if (fn)
627                 return fn(data_tvb, auth_tvb, 0, pinfo, auth_info);
628
629         return NULL;
630 }
631
632 /*
633  * Subdissectors
634  */
635
636 /* the registered subdissectors */
637 GHashTable *dcerpc_uuids=NULL;
638
639 static gint
640 dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2)
641 {
642     const dcerpc_uuid_key *key1 = (const dcerpc_uuid_key *)k1;
643     const dcerpc_uuid_key *key2 = (const dcerpc_uuid_key *)k2;
644     return ((memcmp (&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
645             && (key1->ver == key2->ver));
646 }
647
648 static guint
649 dcerpc_uuid_hash (gconstpointer k)
650 {
651     const dcerpc_uuid_key *key = (const dcerpc_uuid_key *)k;
652     /* This isn't perfect, but the Data1 part of these is almost always
653        unique. */
654     return key->uuid.Data1;
655 }
656
657 void
658 dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver,
659                   dcerpc_sub_dissector *procs, int opnum_hf)
660 {
661     dcerpc_uuid_key *key = g_malloc (sizeof (*key));
662     dcerpc_uuid_value *value = g_malloc (sizeof (*value));
663     header_field_info *hf_info;
664
665     key->uuid = *uuid;
666     key->ver = ver;
667
668     value->proto = find_protocol_by_id(proto);
669     value->proto_id = proto;
670     value->ett = ett;
671     value->name = proto_get_protocol_short_name (value->proto);
672     value->procs = procs;
673     value->opnum_hf = opnum_hf;
674
675     g_hash_table_insert (dcerpc_uuids, key, value);
676
677     hf_info = proto_registrar_get_nth(opnum_hf);
678     hf_info->strings = value_string_from_subdissectors(procs);
679 }
680
681
682 /* try to get registered name for this uuid */
683 const gchar *dcerpc_get_uuid_name(e_uuid_t *uuid, guint16 ver)
684 {
685     dcerpc_uuid_key key;
686     dcerpc_uuid_value *sub_proto;
687
688
689         /* try to get registered uuid "name" of if_id */
690         key.uuid = *uuid;
691         key.ver = ver;
692
693         if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) != NULL
694                  && proto_is_protocol_enabled(sub_proto->proto)) {
695
696                 return sub_proto->name;
697         }
698
699         return NULL;
700 }
701
702
703 /* Function to find the name of a registered protocol
704  * or NULL if the protocol/version is not known to ethereal.
705  */
706 const char *
707 dcerpc_get_proto_name(e_uuid_t *uuid, guint16 ver)
708 {
709     dcerpc_uuid_key key;
710     dcerpc_uuid_value *sub_proto;
711
712     key.uuid = *uuid;
713     key.ver = ver;
714     if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
715         return NULL;
716     }
717     return sub_proto->name;
718 }
719
720 /* Function to find the opnum hf-field of a registered protocol
721  * or -1 if the protocol/version is not known to ethereal.
722  */
723 int
724 dcerpc_get_proto_hf_opnum(e_uuid_t *uuid, guint16 ver)
725 {
726     dcerpc_uuid_key key;
727     dcerpc_uuid_value *sub_proto;
728
729     key.uuid = *uuid;
730     key.ver = ver;
731     if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
732         return -1;
733     }
734     return sub_proto->opnum_hf;
735 }
736
737 /* Create a value_string consisting of DCERPC opnum and name from a
738    subdissector array. */
739
740 value_string *value_string_from_subdissectors(dcerpc_sub_dissector *sd)
741 {
742         value_string *vs = NULL;
743         int i, num_sd = 0;
744
745  again:
746         for (i = 0; sd[i].name; i++) {
747                 if (vs) {
748                         vs[i].value = sd[i].num;
749                         vs[i].strptr = sd[i].name;
750                 } else
751                         num_sd++;
752         }
753
754         if (!vs) {
755                 vs = g_malloc((num_sd + 1) * sizeof(value_string));
756                 goto again;
757         }
758
759         vs[num_sd].value = 0;
760         vs[num_sd].strptr = NULL;
761
762         return vs;
763 }
764
765 /* Function to find the subdissector table of a registered protocol
766  * or NULL if the protocol/version is not known to ethereal.
767  */
768 dcerpc_sub_dissector *
769 dcerpc_get_proto_sub_dissector(e_uuid_t *uuid, guint16 ver)
770 {
771     dcerpc_uuid_key key;
772     dcerpc_uuid_value *sub_proto;
773
774     key.uuid = *uuid;
775     key.ver = ver;
776     if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
777         return NULL;
778     }
779     return sub_proto->procs;
780 }
781
782
783 /*
784  * To keep track of ctx_id mappings.
785  *
786  * Everytime we see a bind call we update this table.
787  * Note that we always specify a SMB FID. For non-SMB transports this
788  * value is 0.
789  */
790 static GHashTable *dcerpc_binds=NULL;
791
792 typedef struct _dcerpc_bind_key {
793     conversation_t *conv;
794     guint16 ctx_id;
795     guint16 smb_fid;
796 } dcerpc_bind_key;
797
798 typedef struct _dcerpc_bind_value {
799         e_uuid_t uuid;
800         guint16 ver;
801 } dcerpc_bind_value;
802
803 static GMemChunk *dcerpc_bind_key_chunk=NULL;
804 static GMemChunk *dcerpc_bind_value_chunk=NULL;
805
806 static gint
807 dcerpc_bind_equal (gconstpointer k1, gconstpointer k2)
808 {
809     const dcerpc_bind_key *key1 = (const dcerpc_bind_key *)k1;
810     const dcerpc_bind_key *key2 = (const dcerpc_bind_key *)k2;
811     return (key1->conv == key2->conv
812             && key1->ctx_id == key2->ctx_id
813             && key1->smb_fid == key2->smb_fid);
814 }
815
816 static guint
817 dcerpc_bind_hash (gconstpointer k)
818 {
819     const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
820     guint hash;
821
822     hash=GPOINTER_TO_UINT(key->conv) + key->ctx_id + key->smb_fid;
823     return hash;
824
825 }
826
827 /*
828  * To keep track of callid mappings.  Should really use some generic
829  * conversation support instead.
830  */
831 static GHashTable *dcerpc_cn_calls=NULL;
832 static GHashTable *dcerpc_dg_calls=NULL;
833
834 typedef struct _dcerpc_cn_call_key {
835     conversation_t *conv;
836     guint32 call_id;
837     guint16 smb_fid;
838 } dcerpc_cn_call_key;
839
840 typedef struct _dcerpc_dg_call_key {
841     conversation_t *conv;
842     guint32 seqnum;
843     e_uuid_t act_id ;
844 } dcerpc_dg_call_key;
845
846 static GMemChunk *dcerpc_cn_call_key_chunk=NULL;
847
848 static GMemChunk *dcerpc_dg_call_key_chunk=NULL;
849
850 static GMemChunk *dcerpc_call_value_chunk=NULL;
851
852
853 static gint
854 dcerpc_cn_call_equal (gconstpointer k1, gconstpointer k2)
855 {
856     const dcerpc_cn_call_key *key1 = (const dcerpc_cn_call_key *)k1;
857     const dcerpc_cn_call_key *key2 = (const dcerpc_cn_call_key *)k2;
858     return (key1->conv == key2->conv
859             && key1->call_id == key2->call_id
860             && key1->smb_fid == key2->smb_fid);
861 }
862
863 static gint
864 dcerpc_dg_call_equal (gconstpointer k1, gconstpointer k2)
865 {
866     const dcerpc_dg_call_key *key1 = (const dcerpc_dg_call_key *)k1;
867     const dcerpc_dg_call_key *key2 = (const dcerpc_dg_call_key *)k2;
868     return (key1->conv == key2->conv
869             && key1->seqnum == key2->seqnum
870             && (memcmp (&key1->act_id, &key2->act_id, sizeof (e_uuid_t)) == 0));
871 }
872
873 static guint
874 dcerpc_cn_call_hash (gconstpointer k)
875 {
876     const dcerpc_cn_call_key *key = (const dcerpc_cn_call_key *)k;
877     return GPOINTER_TO_UINT(key->conv) + key->call_id + key->smb_fid;
878 }
879
880 static guint
881 dcerpc_dg_call_hash (gconstpointer k)
882 {
883     const dcerpc_dg_call_key *key = (const dcerpc_dg_call_key *)k;
884     return (GPOINTER_TO_UINT(key->conv) + key->seqnum + key->act_id.Data1
885             + (key->act_id.Data2 << 16) + key->act_id.Data3
886             + (key->act_id.Data4[0] << 24) + (key->act_id.Data4[1] << 16)
887             + (key->act_id.Data4[2] << 8) + (key->act_id.Data4[3] << 0)
888             + (key->act_id.Data4[4] << 24) + (key->act_id.Data4[5] << 16)
889             + (key->act_id.Data4[6] << 8) + (key->act_id.Data4[7] << 0));
890 }
891
892 /* to keep track of matched calls/responses
893    this one uses the same value struct as calls, but the key is the frame id
894    and call id; there can be more than one call in a frame.
895
896    XXX - why not just use the same keys as are used for calls?
897 */
898
899 static GHashTable *dcerpc_matched=NULL;
900
901 typedef struct _dcerpc_matched_key {
902     guint32 frame;
903     guint32 call_id;
904 } dcerpc_matched_key;
905
906 static GMemChunk *dcerpc_matched_key_chunk=NULL;
907
908 static gint
909 dcerpc_matched_equal (gconstpointer k1, gconstpointer k2)
910 {
911     const dcerpc_matched_key *key1 = (const dcerpc_matched_key *)k1;
912     const dcerpc_matched_key *key2 = (const dcerpc_matched_key *)k2;
913     return (key1->frame == key2->frame
914             && key1->call_id == key2->call_id);
915 }
916
917 static guint
918 dcerpc_matched_hash (gconstpointer k)
919 {
920     const dcerpc_matched_key *key = (const dcerpc_matched_key *)k;
921     return key->frame;
922 }
923
924
925
926 /*
927  * Utility functions.  Modeled after packet-rpc.c
928  */
929
930 int
931 dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
932                       proto_tree *tree, guint8 *drep,
933                       int hfindex, guint8 *pdata)
934 {
935     guint8 data;
936
937     data = tvb_get_guint8 (tvb, offset);
938     if (tree) {
939         proto_tree_add_item (tree, hfindex, tvb, offset, 1, (drep[0] & 0x10));
940     }
941     if (pdata)
942         *pdata = data;
943     return offset + 1;
944 }
945
946 int
947 dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
948                        proto_tree *tree, guint8 *drep,
949                        int hfindex, guint16 *pdata)
950 {
951     guint16 data;
952
953     data = ((drep[0] & 0x10)
954             ? tvb_get_letohs (tvb, offset)
955             : tvb_get_ntohs (tvb, offset));
956
957     if (tree) {
958         proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10));
959     }
960     if (pdata)
961         *pdata = data;
962     return offset + 2;
963 }
964
965 int
966 dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
967                        proto_tree *tree, guint8 *drep,
968                        int hfindex, guint32 *pdata)
969 {
970     guint32 data;
971
972     data = ((drep[0] & 0x10)
973             ? tvb_get_letohl (tvb, offset)
974             : tvb_get_ntohl (tvb, offset));
975
976     if (tree) {
977         proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10));
978     }
979     if (pdata)
980         *pdata = data;
981     return offset+4;
982 }
983
984 /* handles 32 bit unix time_t */
985 int
986 dissect_dcerpc_time_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
987                        proto_tree *tree, guint8 *drep,
988                        int hfindex, guint32 *pdata)
989 {
990     guint32 data;
991     nstime_t tv;
992
993     data = ((drep[0] & 0x10)
994             ? tvb_get_letohl (tvb, offset)
995             : tvb_get_ntohl (tvb, offset));
996
997     tv.secs=data;
998     tv.nsecs=0;
999     if (tree) {
1000         if(data==0xffffffff){
1001             /* special case,   no time specified */
1002             proto_tree_add_time_format(tree, hfindex, tvb, offset, 4, &tv, "%s: No time specified", proto_registrar_get_nth(hfindex)->name);
1003         } else {
1004             proto_tree_add_time (tree, hfindex, tvb, offset, 4, &tv);
1005         }
1006     }
1007     if (pdata)
1008         *pdata = data;
1009
1010     return offset+4;
1011 }
1012
1013 int
1014 dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1015                        proto_tree *tree, guint8 *drep,
1016                        int hfindex, guint64 *pdata)
1017 {
1018     guint64 data;
1019
1020     data = ((drep[0] & 0x10)
1021             ? tvb_get_letoh64 (tvb, offset)
1022             : tvb_get_ntoh64 (tvb, offset));
1023
1024     if (tree) {
1025         proto_tree_add_item(tree, hfindex, tvb, offset, 8, (drep[0] & 0x10));
1026     }
1027     if (pdata)
1028         *pdata = data;
1029     return offset+8;
1030 }
1031
1032
1033 int
1034 dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1035                     proto_tree *tree, guint8 *drep, 
1036                     int hfindex, gfloat *pdata)
1037 {
1038         gfloat data;
1039
1040
1041         switch(drep[1]) {
1042                 case(DCE_RPC_DREP_FP_IEEE):
1043                         data = ((drep[0] & 0x10)
1044                                         ? tvb_get_letohieee_float(tvb, offset)
1045                                         : tvb_get_ntohieee_float(tvb, offset));
1046                         if (tree) {
1047                                 proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
1048                         }
1049                         break;
1050                 case(DCE_RPC_DREP_FP_VAX):  /* (fall trough) */
1051                 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1052                 case(DCE_RPC_DREP_FP_IBM):  /* (fall trough) */
1053                 default:
1054                         /* ToBeDone: non IEEE floating formats */
1055                         /* Set data to a negative infinity value */
1056                         data = -G_MAXFLOAT;
1057                         if (tree) {
1058                                 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep[1]);
1059                         }
1060         }
1061     if (pdata)
1062         *pdata = data;
1063     return offset + 4;
1064 }
1065
1066
1067 int
1068 dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1069                     proto_tree *tree, guint8 *drep, 
1070                     int hfindex, gdouble *pdata)
1071 {
1072     gdouble data;
1073
1074
1075         switch(drep[1]) {
1076                 case(DCE_RPC_DREP_FP_IEEE):
1077                         data = ((drep[0] & 0x10)
1078                                         ? tvb_get_letohieee_double(tvb, offset)
1079                                         : tvb_get_ntohieee_double(tvb, offset));
1080                         if (tree) {
1081                                 proto_tree_add_double(tree, hfindex, tvb, offset, 8, data);
1082                         }
1083                         break;
1084                 case(DCE_RPC_DREP_FP_VAX):  /* (fall trough) */
1085                 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1086                 case(DCE_RPC_DREP_FP_IBM):  /* (fall trough) */
1087                 default:
1088                         /* ToBeDone: non IEEE double formats */
1089                         /* Set data to a negative infinity value */
1090                         data = -G_MAXDOUBLE;
1091                         if (tree) {
1092                                 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep[1]);
1093                         }
1094         }
1095     if (pdata)
1096         *pdata = data;
1097     return offset + 8;
1098 }
1099
1100
1101 int
1102 dissect_dcerpc_uuid_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1103                     proto_tree *tree, char *drep,
1104                     int hfindex, e_uuid_t *pdata)
1105 {
1106     e_uuid_t uuid;
1107         header_field_info* hfi;
1108 #if 0
1109         gchar *uuid_name;
1110 #endif
1111
1112
1113     dcerpc_tvb_get_uuid (tvb, offset, drep, &uuid);
1114     if (tree) {
1115                 /* get name of protocol field to prepend it later */
1116                 hfi = proto_registrar_get_nth(hfindex);
1117
1118 #if 0
1119         /* XXX - get the name won't work correct, as we don't know the version of this uuid (if it has one) */
1120                 /* look for a registered uuid name */
1121                 uuid_name = dcerpc_get_uuid_name(&uuid, 0);
1122
1123                 if (uuid_name) {
1124                         /* we know the name of this uuid */
1125                         proto_tree_add_string_format (tree, hfindex, tvb, offset, 16, "",
1126                                       "%s: %s (%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x)",
1127                                                                           hfi->name, uuid_name,
1128                                       uuid.Data1, uuid.Data2, uuid.Data3,
1129                                       uuid.Data4[0], uuid.Data4[1],
1130                                       uuid.Data4[2], uuid.Data4[3],
1131                                       uuid.Data4[4], uuid.Data4[5],
1132                                       uuid.Data4[6], uuid.Data4[7]);
1133                 } else {
1134 #endif
1135                         /* GUID have changed from FT_STRING to FT_GUID
1136                            but we havent changed all dissectors yet.
1137                          */
1138                         if(hfi->type==FT_GUID){
1139                                 proto_tree_add_item(tree, hfindex, tvb, offset, 16, (drep[0] & 0x10));
1140                         } else {
1141                                 /* we don't know the name of this uuid */
1142                                 proto_tree_add_string_format (tree, hfindex, tvb, offset, 16, "",
1143                                       "%s: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1144                                       hfi->name,
1145                                       uuid.Data1, uuid.Data2, uuid.Data3,
1146                                       uuid.Data4[0], uuid.Data4[1],
1147                                       uuid.Data4[2], uuid.Data4[3],
1148                                       uuid.Data4[4], uuid.Data4[5],
1149                                       uuid.Data4[6], uuid.Data4[7]);
1150                         }
1151 #if 0
1152                 }
1153 #endif
1154     }
1155     if (pdata) {
1156         *pdata = uuid;
1157     }
1158     return offset + 16;
1159 }
1160
1161
1162 /*
1163  * a couple simpler things
1164  */
1165 guint16
1166 dcerpc_tvb_get_ntohs (tvbuff_t *tvb, gint offset, guint8 *drep)
1167 {
1168     if (drep[0] & 0x10) {
1169         return tvb_get_letohs (tvb, offset);
1170     } else {
1171         return tvb_get_ntohs (tvb, offset);
1172     }
1173 }
1174
1175 guint32
1176 dcerpc_tvb_get_ntohl (tvbuff_t *tvb, gint offset, guint8 *drep)
1177 {
1178     if (drep[0] & 0x10) {
1179         return tvb_get_letohl (tvb, offset);
1180     } else {
1181         return tvb_get_ntohl (tvb, offset);
1182     }
1183 }
1184
1185 void
1186 dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, guint8 *drep, e_uuid_t *uuid)
1187 {
1188     unsigned int i;
1189     uuid->Data1 = dcerpc_tvb_get_ntohl (tvb, offset, drep);
1190     uuid->Data2 = dcerpc_tvb_get_ntohs (tvb, offset+4, drep);
1191     uuid->Data3 = dcerpc_tvb_get_ntohs (tvb, offset+6, drep);
1192
1193     for (i=0; i<sizeof (uuid->Data4); i++) {
1194         uuid->Data4[i] = tvb_get_guint8 (tvb, offset+8+i);
1195     }
1196 }
1197
1198
1199
1200 /* NDR arrays */
1201 /* function to dissect a unidimensional conformant array */
1202 int
1203 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1204                 proto_tree *tree, guint8 *drep,
1205                 dcerpc_dissect_fnct_t *fnct)
1206 {
1207         guint32 i;
1208         dcerpc_info *di;
1209         int old_offset;
1210
1211         di=pinfo->private_data;
1212         if(di->conformant_run){
1213                 /* conformant run, just dissect the max_count header */
1214                 old_offset=offset;
1215                 di->conformant_run=0;
1216                 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1217                                 hf_dcerpc_array_max_count, &di->array_max_count);
1218                 di->array_max_count_offset=offset-4;
1219                 di->conformant_run=1;
1220                 di->conformant_eaten=offset-old_offset;
1221         } else {
1222                 /* we don't remember where in the bytestream this field was */
1223                 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1224
1225                 /* real run, dissect the elements */
1226                 for(i=0;i<di->array_max_count;i++){
1227                         offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1228                 }
1229         }
1230
1231         return offset;
1232 }
1233 /* function to dissect a unidimensional conformant and varying array */
1234 int
1235 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1236                 proto_tree *tree, guint8 *drep,
1237                 dcerpc_dissect_fnct_t *fnct)
1238 {
1239         guint32 i;
1240         dcerpc_info *di;
1241         int old_offset;
1242
1243         di=pinfo->private_data;
1244         if(di->conformant_run){
1245                 /* conformant run, just dissect the max_count header */
1246                 old_offset=offset;
1247                 di->conformant_run=0;
1248                 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1249                                 hf_dcerpc_array_max_count, &di->array_max_count);
1250                 di->array_max_count_offset=offset-4;
1251                 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1252                                 hf_dcerpc_array_offset, &di->array_offset);
1253                 di->array_offset_offset=offset-4;
1254                 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1255                                 hf_dcerpc_array_actual_count, &di->array_actual_count);
1256                 di->array_actual_count_offset=offset-4;
1257                 di->conformant_run=1;
1258                 di->conformant_eaten=offset-old_offset;
1259         } else {
1260                 /* we dont dont remember where  in the bytestream these fields were */
1261                 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1262                 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
1263                 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
1264
1265                 /* real run, dissect the elements */
1266                 for(i=0;i<di->array_actual_count;i++){
1267                         offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1268                 }
1269         }
1270
1271         return offset;
1272 }
1273 /* function to dissect a unidimensional varying array */
1274 int
1275 dissect_ndr_uvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1276                 proto_tree *tree, guint8 *drep,
1277                 dcerpc_dissect_fnct_t *fnct)
1278 {
1279         guint32 i;
1280         dcerpc_info *di;
1281         int old_offset;
1282
1283         di=pinfo->private_data;
1284         if(di->conformant_run){
1285                 /* conformant run, just dissect the max_count header */
1286                 old_offset=offset;
1287                 di->conformant_run=0;
1288                 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1289                                 hf_dcerpc_array_offset, &di->array_offset);
1290                 di->array_offset_offset=offset-4;
1291                 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1292                                 hf_dcerpc_array_actual_count, &di->array_actual_count);
1293                 di->array_actual_count_offset=offset-4;
1294                 di->conformant_run=1;
1295                 di->conformant_eaten=offset-old_offset;
1296         } else {
1297                 /* we dont dont remember where  in the bytestream these fields were */
1298                 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
1299                 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
1300
1301                 /* real run, dissect the elements */
1302                 for(i=0;i<di->array_actual_count;i++){
1303                         offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1304                 }
1305         }
1306
1307         return offset;
1308 }
1309
1310 /* Dissect an string of bytes.  This corresponds to
1311    IDL of the form '[string] byte *foo'.
1312
1313    It can also be used for a conformant varying array of bytes if
1314    the contents of the array should be shown as a big blob, rather
1315    than showing each byte as an individual element.
1316
1317    XXX - which of those is really the IDL type for, for example,
1318    the encrypted data in some MAPI packets?  (Microsoft haven't
1319    released that IDL.)
1320
1321    XXX - does this need to do all the conformant array stuff that
1322    "dissect_ndr_ucvarray()" does?  These are presumably for strings
1323    that are conformant and varying - they're stored like conformant
1324    varying arrays of bytes.  */
1325 int
1326 dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1327                             proto_tree *tree, guint8 *drep)
1328 {
1329     dcerpc_info *di;
1330     guint32 len;
1331
1332     di=pinfo->private_data;
1333     if(di->conformant_run){
1334       /* just a run to handle conformant arrays, no scalars to dissect */
1335       return offset;
1336     }
1337
1338     /* NDR array header */
1339
1340     offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1341                                 hf_dcerpc_array_max_count, NULL);
1342
1343     offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1344                                 hf_dcerpc_array_offset, NULL);
1345
1346     offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1347                                 hf_dcerpc_array_actual_count, &len);
1348
1349     if (tree && len) {
1350         tvb_ensure_bytes_exist(tvb, offset, len);
1351         proto_tree_add_item(tree, hf_dcerpc_array_buffer,
1352                             tvb, offset, len, drep[0] & 0x10);
1353     }
1354
1355     offset += len;
1356
1357     return offset;
1358 }
1359
1360 /* For dissecting arrays that are to be interpreted as strings.  */
1361
1362 /* Dissect an NDR conformant varying string of elements.
1363    The length of each element is given by the 'size_is' parameter;
1364    the elements are assumed to be characters or wide characters.
1365
1366    XXX - does this need to do all the conformant array stuff that
1367    "dissect_ndr_ucvarray()" does?  */
1368 int
1369 dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1370                      proto_tree *tree, guint8 *drep, int size_is,
1371                      int hfindex, gboolean add_subtree, char **data)
1372 {
1373     dcerpc_info *di;
1374     proto_item *string_item;
1375     proto_tree *string_tree;
1376     guint32 len, buffer_len;
1377     char *s;
1378     header_field_info *hfinfo;
1379
1380     di=pinfo->private_data;
1381     if(di->conformant_run){
1382       /* just a run to handle conformant arrays, no scalars to dissect */
1383       return offset;
1384     }
1385
1386     if (add_subtree) {
1387         string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1388                                           proto_registrar_get_name(hfindex));
1389         string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1390     } else {
1391         string_item = NULL;
1392         string_tree = tree;
1393     }
1394
1395     /* NDR array header */
1396
1397     offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1398                                 hf_dcerpc_array_max_count, NULL);
1399
1400     offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1401                                 hf_dcerpc_array_offset, NULL);
1402
1403     offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1404                                 hf_dcerpc_array_actual_count, &len);
1405
1406     buffer_len = size_is * len;
1407
1408     /* Adjust offset */
1409     if (offset % size_is)
1410         offset += size_is - (offset % size_is);
1411
1412     if (size_is == sizeof(guint16)) {
1413         /* XXX - use drep to determine the byte order? */
1414         s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
1415         /*
1416          * XXX - we don't support a string type with Unicode
1417          * characters, so if this is a string item, we make
1418          * its value be the "fake Unicode" string.
1419          */
1420         if (tree && buffer_len) {
1421             hfinfo = proto_registrar_get_nth(hfindex);
1422             tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1423             if (hfinfo->type == FT_STRING) {
1424                 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1425                                       buffer_len, s);
1426             } else {
1427                 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1428                                     buffer_len, drep[0] & 0x10);
1429             }
1430         }
1431     } else {
1432         /*
1433          * "tvb_get_string()" throws an exception if the entire string
1434          * isn't in the tvbuff.  If the length is bogus, this should
1435          * keep us from trying to allocate an immensely large buffer.
1436          * (It won't help if the length is *valid* but immensely large,
1437          * but that's another matter; in any case, that would happen only
1438          * if we had an immensely large tvbuff....)
1439          */
1440         tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1441         s = tvb_get_string(tvb, offset, buffer_len);
1442         if (tree && buffer_len)
1443             proto_tree_add_item(string_tree, hfindex, tvb, offset,
1444                                 buffer_len, drep[0] & 0x10);
1445     }
1446
1447     if (string_item != NULL)
1448         proto_item_append_text(string_item, ": %s", s);
1449
1450     if (data)
1451             *data = s;
1452     else
1453             g_free(s);
1454     
1455     offset += buffer_len;
1456
1457     proto_item_set_end(string_item, tvb, offset);
1458
1459     return offset;
1460 }
1461
1462 /* Dissect an conformant varying string of chars.
1463    This corresponds to IDL of the form '[string] char *foo'.
1464
1465    XXX - at least according to the DCE RPC 1.1 spec, a string has
1466    a null terminator, which isn't necessary as a terminator for
1467    the transfer language (as there's a length), but is presumably
1468    there for the benefit of null-terminated-string languages
1469    such as C.  Is this ever used for purely counted strings?
1470    (Not that it matters if it is.) */
1471 int
1472 dissect_ndr_char_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1473                         proto_tree *tree, guint8 *drep)
1474 {
1475     dcerpc_info *di;
1476     di=pinfo->private_data;
1477
1478     return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1479                                 sizeof(guint8), di->hf_index,
1480                                 FALSE, NULL);
1481 }
1482
1483 /* Dissect a conformant varying string of wchars (wide characters).
1484    This corresponds to IDL of the form '[string] wchar *foo'
1485
1486    XXX - at least according to the DCE RPC 1.1 spec, a string has
1487    a null terminator, which isn't necessary as a terminator for
1488    the transfer language (as there's a length), but is presumably
1489    there for the benefit of null-terminated-string languages
1490    such as C.  Is this ever used for purely counted strings?
1491    (Not that it matters if it is.) */
1492 int
1493 dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1494                         proto_tree *tree, guint8 *drep)
1495 {
1496     dcerpc_info *di;
1497     di=pinfo->private_data;
1498
1499     return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1500                                 sizeof(guint16), di->hf_index,
1501                                 FALSE, NULL);
1502 }
1503
1504 /* Dissect an NDR varying string of elements.
1505    The length of each element is given by the 'size_is' parameter;
1506    the elements are assumed to be characters or wide characters.
1507 */
1508 int
1509 dissect_ndr_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1510                      proto_tree *tree, guint8 *drep, int size_is,
1511                      int hfindex, gboolean add_subtree, char **data)
1512 {
1513     dcerpc_info *di;
1514     proto_item *string_item;
1515     proto_tree *string_tree;
1516     guint32 len, buffer_len;
1517     char *s;
1518     header_field_info *hfinfo;
1519
1520     di=pinfo->private_data;
1521     if(di->conformant_run){
1522       /* just a run to handle conformant arrays, no scalars to dissect */
1523       return offset;
1524     }
1525
1526     if (add_subtree) {
1527         string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1528                                           proto_registrar_get_name(hfindex));
1529         string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1530     } else {
1531         string_item = NULL;
1532         string_tree = tree;
1533     }
1534
1535     /* NDR array header */
1536     offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1537                                 hf_dcerpc_array_offset, NULL);
1538
1539     offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1540                                 hf_dcerpc_array_actual_count, &len);
1541
1542     buffer_len = size_is * len;
1543
1544     /* Adjust offset */
1545     if (offset % size_is)
1546         offset += size_is - (offset % size_is);
1547
1548     if (size_is == sizeof(guint16)) {
1549         /* XXX - use drep to determine the byte order? */
1550         s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
1551         /*
1552          * XXX - we don't support a string type with Unicode
1553          * characters, so if this is a string item, we make
1554          * its value be the "fake Unicode" string.
1555          */
1556         if (tree && buffer_len) {
1557             hfinfo = proto_registrar_get_nth(hfindex);
1558             tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1559             if (hfinfo->type == FT_STRING) {
1560                 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1561                                       buffer_len, s);
1562             } else {
1563                 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1564                                     buffer_len, drep[0] & 0x10);
1565             }
1566         }
1567     } else {
1568         /*
1569          * "tvb_get_string()" throws an exception if the entire string
1570          * isn't in the tvbuff.  If the length is bogus, this should
1571          * keep us from trying to allocate an immensely large buffer.
1572          * (It won't help if the length is *valid* but immensely large,
1573          * but that's another matter; in any case, that would happen only
1574          * if we had an immensely large tvbuff....)
1575          */
1576         tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1577         s = tvb_get_string(tvb, offset, buffer_len);
1578         if (tree && buffer_len)
1579             proto_tree_add_item(string_tree, hfindex, tvb, offset,
1580                                 buffer_len, drep[0] & 0x10);
1581     }
1582
1583     if (string_item != NULL)
1584         proto_item_append_text(string_item, ": %s", s);
1585
1586     if (data)
1587             *data = s;
1588     else
1589             g_free(s);
1590     
1591     offset += buffer_len;
1592
1593     proto_item_set_end(string_item, tvb, offset);
1594
1595     return offset;
1596 }
1597 /* Dissect an varying string of chars.
1598    This corresponds to IDL of the form '[string] char *foo'.
1599
1600    XXX - at least according to the DCE RPC 1.1 spec, a string has
1601    a null terminator, which isn't necessary as a terminator for
1602    the transfer language (as there's a length), but is presumably
1603    there for the benefit of null-terminated-string languages
1604    such as C.  Is this ever used for purely counted strings?
1605    (Not that it matters if it is.) */
1606 int
1607 dissect_ndr_char_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1608                         proto_tree *tree, guint8 *drep)
1609 {
1610     dcerpc_info *di;
1611     di=pinfo->private_data;
1612
1613     return dissect_ndr_vstring(tvb, offset, pinfo, tree, drep,
1614                                 sizeof(guint8), di->hf_index,
1615                                 FALSE, NULL);
1616 }
1617
1618 /* Dissect a varying string of wchars (wide characters).
1619    This corresponds to IDL of the form '[string] wchar *foo'
1620
1621    XXX - at least according to the DCE RPC 1.1 spec, a string has
1622    a null terminator, which isn't necessary as a terminator for
1623    the transfer language (as there's a length), but is presumably
1624    there for the benefit of null-terminated-string languages
1625    such as C.  Is this ever used for purely counted strings?
1626    (Not that it matters if it is.) */
1627 int
1628 dissect_ndr_wchar_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo, 
1629                         proto_tree *tree, guint8 *drep)
1630 {
1631     dcerpc_info *di;
1632     di=pinfo->private_data;
1633
1634     return dissect_ndr_vstring(tvb, offset, pinfo, tree, drep,
1635                                 sizeof(guint16), di->hf_index,
1636                                 FALSE, NULL);
1637 }
1638
1639
1640 /* ndr pointer handling */
1641 /* list of pointers encountered so far */
1642 static GSList *ndr_pointer_list = NULL;
1643
1644 /* position where in the list to insert newly encountered pointers */
1645 static int ndr_pointer_list_pos=0;
1646
1647 /* boolean controlling whether pointers are top-level or embedded */
1648 static gboolean pointers_are_top_level = TRUE;
1649
1650 /* as a kludge, we represent all embedded reference pointers as id==-1
1651    hoping that his will not collide with any non-ref pointers */
1652 typedef struct ndr_pointer_data {
1653         guint32 id;
1654         proto_item *item;       /* proto_item for pointer */
1655         proto_tree *tree;       /* subtree of above item */
1656         dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
1657         int hf_index;
1658         dcerpc_callback_fnct_t *callback;
1659         void *callback_args;
1660 } ndr_pointer_data_t;
1661
1662 void
1663 init_ndr_pointer_list(packet_info *pinfo)
1664 {
1665         dcerpc_info *di;
1666
1667         di=pinfo->private_data;
1668         di->conformant_run=0;
1669
1670         while(ndr_pointer_list){
1671                 ndr_pointer_data_t *npd;
1672
1673                 npd=g_slist_nth_data(ndr_pointer_list, 0);
1674                 ndr_pointer_list=g_slist_remove(ndr_pointer_list, npd);
1675                 if(npd){
1676                         g_free(npd);
1677                 }
1678         }
1679
1680         ndr_pointer_list=NULL;
1681         ndr_pointer_list_pos=0;
1682         pointers_are_top_level=TRUE;
1683 }
1684
1685 int
1686 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, guint8 *drep)
1687 {
1688         int found_new_pointer;
1689         dcerpc_info *di;
1690         int old_offset;
1691         int next_pointer;
1692
1693         next_pointer=0;
1694         di=pinfo->private_data;
1695         do{
1696                 int i, len;
1697
1698                 found_new_pointer=0;
1699                 len=g_slist_length(ndr_pointer_list);
1700                 for(i=next_pointer;i<len;i++){
1701                         ndr_pointer_data_t *tnpd;
1702                         tnpd=g_slist_nth_data(ndr_pointer_list, i);
1703                         if(tnpd->fnct){
1704                                 dcerpc_dissect_fnct_t *fnct;
1705
1706                                 next_pointer=i+1;
1707                                 found_new_pointer=1;
1708                                 fnct=tnpd->fnct;
1709                                 tnpd->fnct=NULL;
1710                                 ndr_pointer_list_pos=i+1;
1711                                 di->hf_index=tnpd->hf_index;
1712                                 /* first a run to handle any conformant
1713                                    array headers */
1714                                 di->conformant_run=1;
1715                                 di->conformant_eaten=0;
1716                                 old_offset = offset;
1717                                 offset = (*(fnct))(tvb, offset, pinfo, NULL, drep);
1718
1719                                 DISSECTOR_ASSERT((offset-old_offset)==di->conformant_eaten);
1720                                 /* This is to check for any bugs in the dissectors.
1721                                  *
1722                                  * Basically, the NDR representation will store all
1723                                  * arrays in two blocks, one block with the dimension
1724                                  * discreption, like size, number of elements and such,
1725                                  * and another block that contains the actual data stored
1726                                  * in the array.
1727                                  * If the array is embedded directly inside another,
1728                                  * encapsulating aggregate type, like a union or struct,
1729                                  * then these two blocks will be stored at different places
1730                                  * in the bytestream, with other data between the blocks.
1731                                  *
1732                                  * For this reason, all pointers to types (both aggregate
1733                                  * and scalar, for simplicity no distinction is made)
1734                                  * will have its dissector called twice.
1735                                  * The dissector will first be called with conformant_run==1
1736                                  * in which mode the dissector MUST NOT consume any data from
1737                                  * the tvbuff (i.e. may not dissect anything) except the
1738                                  * initial control block for arrays.
1739                                  * The second time the dissector is called, with
1740                                  * conformant_run==0, all other data for the type will be
1741                                  * dissected.
1742                                  *
1743                                  * All dissect_ndr_<type> dissectors are already prepared
1744                                  * for this and knows when it should eat data from the tvb
1745                                  * and when not to, so implementors of dissectors will
1746                                  * normally not need to worry about this or even know about
1747                                  * it. However, if a dissector for an aggregate type calls
1748                                  * a subdissector from outside packet-dcerpc.c, such as
1749                                  * the dissector in packet-smb.c for NT Security Descriptors
1750                                  * as an example, then it is VERY important to encapsulate
1751                                  * this call to an external subdissector with the appropriate
1752                                  * test for conformant_run, i.e. it will need something like
1753                                  *
1754                                  *      dcerpc_info *di;
1755                                  *
1756                                  *      di=pinfo->private_data;
1757                                  *      if(di->conformant_run){
1758                                  *              return offset;
1759                                  *      }
1760                                  *
1761                                  * to make sure it makes the right thing.
1762                                  * This assert will signal when someone has forgotten to
1763                                  * make the dissector aware of this requirement.
1764                                  */
1765
1766                                 /* now we dissect the actual pointer */
1767                                 di->conformant_run=0;
1768                                 old_offset = offset;
1769                                 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, drep);
1770                                 if (tnpd->callback)
1771                                         tnpd->callback(pinfo, tnpd->tree, tnpd->item, tvb, old_offset, offset, tnpd->callback_args);
1772                                 break;
1773                         }
1774                 }
1775         } while(found_new_pointer);
1776
1777         return offset;
1778 }
1779
1780
1781 static void
1782 add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
1783                     dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index, 
1784                     dcerpc_callback_fnct_t *callback, void *callback_args)
1785 {
1786         ndr_pointer_data_t *npd;
1787
1788         /* check if this pointer is valid */
1789         if(id!=0xffffffff){
1790                 dcerpc_info *di;
1791                 dcerpc_call_value *value;
1792
1793                 di=pinfo->private_data;
1794                 value=di->call_data;
1795
1796                 if(di->ptype == PDU_REQ){
1797                         if(!(pinfo->fd->flags.visited)){
1798                                 if(id>value->max_ptr){
1799                                         value->max_ptr=id;
1800                                 }
1801                         }
1802                 } else {
1803                         /* if we havent seen the request bail out since we cant
1804                            know whether this is the first non-NULL instance
1805                            or not */
1806                         if(value->req_frame==0){
1807                                 /* XXX THROW EXCEPTION */
1808                         }
1809
1810                         /* We saw this one in the request frame, nothing to
1811                            dissect later */
1812                         if(id<=value->max_ptr){
1813                                 return;
1814                         }
1815                 }
1816         }
1817
1818         npd=g_malloc(sizeof(ndr_pointer_data_t));
1819         npd->id=id;
1820         npd->tree=tree;
1821         npd->item=item;
1822         npd->fnct=fnct;
1823         npd->hf_index=hf_index;
1824         npd->callback=callback;
1825         npd->callback_args=callback_args;
1826         ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
1827                                         ndr_pointer_list_pos);
1828         ndr_pointer_list_pos++;
1829 }
1830
1831
1832 static int
1833 find_pointer_index(guint32 id)
1834 {
1835         ndr_pointer_data_t *npd;
1836         int i,len;
1837
1838         len=g_slist_length(ndr_pointer_list);
1839         for(i=0;i<len;i++){
1840                 npd=g_slist_nth_data(ndr_pointer_list, i);
1841                 if(npd){
1842                         if(npd->id==id){
1843                                 return i;
1844                         }
1845                 }
1846         }
1847
1848         return -1;
1849 }
1850
1851 /* This function dissects an NDR pointer and stores the callback for later
1852  * deferred dissection.
1853  *
1854  *   fnct is the callback function for when we have reached this object in
1855  *   the bytestream.
1856  *
1857  *   type is what type of pointer.
1858  *
1859  *   this is text is what text we should put in any created tree node.
1860  *
1861  *   hf_index is what hf value we want to pass to the callback function when
1862  *   it is called, the callback can later pich this one up from di->hf_index.
1863  *
1864  *   callback is executed after the pointer has been dereferenced.
1865  *
1866  *   callback_args is passed as an argument to the callback function
1867  *
1868  * See packet-dcerpc-samr.c for examples
1869  */
1870 int
1871 dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1872                     proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
1873                     int type, const char *text, int hf_index, 
1874                     dcerpc_callback_fnct_t *callback, void *callback_args)
1875 {
1876         dcerpc_info *di;
1877         proto_tree *tr = NULL;
1878         gint start_offset = offset;
1879
1880         di=pinfo->private_data;
1881         if(di->conformant_run){
1882                 /* this call was only for dissecting the header for any
1883                    embedded conformant array. we will not parse any
1884                    pointers in this mode.
1885                 */
1886                 return offset;
1887         }
1888
1889         /*TOP LEVEL REFERENCE POINTER*/
1890         if( pointers_are_top_level
1891         &&(type==NDR_POINTER_REF) ){
1892                 proto_item *item;
1893
1894                 /* we must find out a nice way to do the length here */
1895                 item=proto_tree_add_text(tree, tvb, offset, 0,
1896                         "%s", text);
1897                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1898
1899                 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff, 
1900                                     hf_index, callback, callback_args);
1901                 goto after_ref_id;
1902         }
1903
1904         /*TOP LEVEL FULL POINTER*/
1905         if( pointers_are_top_level
1906         && (type==NDR_POINTER_PTR) ){
1907                 int idx;
1908                 guint32 id;
1909                 proto_item *item;
1910
1911                 /* get the referent id */
1912                 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1913
1914                 tvb_ensure_bytes_exist(tvb, offset-4, 4);
1915                 /* we got a NULL pointer */
1916                 if(id==0){
1917                         proto_tree_add_text(tree, tvb, offset-4, 4,
1918                                 "(NULL pointer) %s",text);
1919                         goto after_ref_id;
1920                 }
1921
1922                 /* see if we have seen this pointer before */
1923                 idx=find_pointer_index(id);
1924
1925                 /* we have seen this pointer before */
1926                 if(idx>=0){
1927                         proto_tree_add_text(tree, tvb, offset-4, 4,
1928                                 "(duplicate PTR) %s",text);
1929                         goto after_ref_id;
1930                 }
1931
1932                 /* new pointer */
1933                 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1934                         "%s", text);
1935                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1936                 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1937                 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index, 
1938                                     callback, callback_args);
1939                 goto after_ref_id;
1940         }
1941         /*TOP LEVEL UNIQUE POINTER*/
1942         if( pointers_are_top_level
1943         && (type==NDR_POINTER_UNIQUE) ){
1944                 guint32 id;
1945                 proto_item *item;
1946
1947                 /* get the referent id */
1948                 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1949
1950                 tvb_ensure_bytes_exist(tvb, offset-4, 4);
1951                 /* we got a NULL pointer */
1952                 if(id==0){
1953                         proto_tree_add_text(tree, tvb, offset-4, 4,
1954                                 "(NULL pointer) %s",text);
1955                         goto after_ref_id;
1956                 }
1957
1958                 /* new pointer */
1959                 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1960                         "%s", text);
1961                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1962                 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1963                 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff, 
1964                                     hf_index, callback, callback_args);
1965                 goto after_ref_id;
1966         }
1967
1968         /*EMBEDDED REFERENCE POINTER*/
1969         if( (!pointers_are_top_level)
1970         && (type==NDR_POINTER_REF) ){
1971                 guint32 id;
1972                 proto_item *item;
1973
1974                 /* get the referent id */
1975                 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1976
1977                 tvb_ensure_bytes_exist(tvb, offset-4, 4);
1978                 /* new pointer */
1979                 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1980                         "%s",text);
1981                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1982                 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1983                 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff, 
1984                                     hf_index, callback, callback_args);
1985                 goto after_ref_id;
1986         }
1987
1988         /*EMBEDDED UNIQUE POINTER*/
1989         if( (!pointers_are_top_level)
1990         && (type==NDR_POINTER_UNIQUE) ){
1991                 guint32 id;
1992                 proto_item *item;
1993
1994                 /* get the referent id */
1995                 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1996
1997                 tvb_ensure_bytes_exist(tvb, offset-4, 4);
1998                 /* we got a NULL pointer */
1999                 if(id==0){
2000                         proto_tree_add_text(tree, tvb, offset-4, 4,
2001                                 "(NULL pointer) %s", text);
2002                         goto after_ref_id;
2003                 }
2004
2005                 /* new pointer */
2006                 item=proto_tree_add_text(tree, tvb, offset-4, 4,
2007                         "%s",text);
2008                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2009                 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
2010                 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff, 
2011                                     hf_index, callback, callback_args);
2012                 goto after_ref_id;
2013         }
2014
2015         /*EMBEDDED FULL POINTER*/
2016         if( (!pointers_are_top_level)
2017         && (type==NDR_POINTER_PTR) ){
2018                 int idx;
2019                 guint32 id;
2020                 proto_item *item;
2021
2022                 /* get the referent id */
2023                 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
2024
2025                 tvb_ensure_bytes_exist(tvb, offset-4, 4);
2026                 /* we got a NULL pointer */
2027                 if(id==0){
2028                         proto_tree_add_text(tree, tvb, offset-4, 4,
2029                                 "(NULL pointer) %s",text);
2030                         goto after_ref_id;
2031                 }
2032
2033                 /* see if we have seen this pointer before */
2034                 idx=find_pointer_index(id);
2035
2036                 /* we have seen this pointer before */
2037                 if(idx>=0){
2038                         proto_tree_add_text(tree, tvb, offset-4, 4,
2039                                 "(duplicate PTR) %s",text);
2040                         goto after_ref_id;
2041                 }
2042
2043                 /* new pointer */
2044                 item=proto_tree_add_text(tree, tvb, offset-4, 4,
2045                         "%s", text);
2046                 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2047                 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
2048                 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index, 
2049                                     callback, callback_args);
2050                 goto after_ref_id;
2051         }
2052
2053
2054 after_ref_id:
2055         /* After each top level pointer we have dissected we have to
2056            dissect all deferrals before we move on to the next top level
2057            argument */
2058         if(pointers_are_top_level==TRUE){
2059                 pointers_are_top_level=FALSE;
2060                 offset = dissect_deferred_pointers(pinfo, tvb, offset, drep);
2061                 pointers_are_top_level=TRUE;
2062         }
2063
2064         /* Set the length for the new subtree */
2065         if (tr){
2066                 proto_item_set_len(tr, offset-start_offset);
2067         }
2068         return offset;
2069 }
2070
2071 int
2072 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2073                     proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2074                     int type, const char *text, int hf_index)
2075 {
2076         return dissect_ndr_pointer_cb(
2077                 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
2078                 NULL, NULL);
2079 }
2080 int
2081 dissect_ndr_toplevel_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2082                     proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2083                     int type, const char *text, int hf_index)
2084 {
2085         int ret;
2086
2087         pointers_are_top_level=TRUE;
2088         ret=dissect_ndr_pointer_cb(
2089                 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
2090                 NULL, NULL);
2091         return ret;
2092 }
2093 int
2094 dissect_ndr_embedded_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2095                     proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2096                     int type, const char *text, int hf_index)
2097 {
2098         int ret;
2099
2100         pointers_are_top_level=FALSE;
2101         ret=dissect_ndr_pointer_cb(
2102                 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
2103                 NULL, NULL);
2104         return ret;
2105 }
2106
2107 static void
2108 show_stub_data (tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
2109                 dcerpc_auth_info *auth_info, gboolean is_encrypted)
2110 {
2111     int length, plain_length, auth_pad_len;
2112     guint auth_pad_offset;
2113
2114     /*
2115      * We don't show stub data unless we have some in the tvbuff;
2116      * however, in the protocol tree, we show, as the number of
2117      * bytes, the reported number of bytes, not the number of bytes
2118      * that happen to be in the tvbuff.
2119      */
2120     if (tvb_length_remaining (tvb, offset) > 0) {
2121         auth_pad_len = auth_info?auth_info->auth_pad_len:0;
2122         length = tvb_reported_length_remaining (tvb, offset);
2123
2124         /* if auth_pad_len is larger than length then we ignore auth_pad_len totally */
2125         plain_length = length - auth_pad_len;
2126         if (plain_length < 1) {
2127             plain_length = length;
2128             auth_pad_len = 0;
2129         }
2130         auth_pad_offset = offset + plain_length;
2131
2132         if (auth_info != NULL &&
2133             auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
2134             if (is_encrypted) {
2135                 tvb_ensure_bytes_exist(tvb, offset, length);
2136                 proto_tree_add_text(dcerpc_tree, tvb, offset, length,
2137                                     "Encrypted stub data (%d byte%s)",
2138                                     length, plurality(length, "", "s"));
2139                 /* is the padding is still inside the encrypted blob, don't display it explicit */
2140                 auth_pad_len = 0;
2141             } else {
2142                 tvb_ensure_bytes_exist(tvb, offset, plain_length);
2143                 proto_tree_add_text(dcerpc_tree, tvb, offset, plain_length,
2144                                     "Decrypted stub data (%d byte%s)",
2145                                     plain_length, plurality(plain_length, "", "s"));
2146             }
2147         } else {
2148             tvb_ensure_bytes_exist(tvb, offset, plain_length);
2149             proto_tree_add_text (dcerpc_tree, tvb, offset, plain_length,
2150                                  "Stub data (%d byte%s)", plain_length,
2151                                  plurality(plain_length, "", "s"));
2152         }
2153         /* If there is auth padding at the end of the stub, display it */
2154         if (auth_pad_len != 0) {
2155                 tvb_ensure_bytes_exist(tvb, auth_pad_offset, auth_pad_len);
2156                 proto_tree_add_text (dcerpc_tree, tvb, auth_pad_offset,
2157                                      auth_pad_len,
2158                                      "Auth Padding (%u byte%s)",
2159                                      auth_pad_len,
2160                                      plurality(auth_pad_len, "", "s"));
2161             }
2162     }
2163 }
2164
2165 static int
2166 dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
2167                     proto_tree *dcerpc_tree,
2168                     tvbuff_t *volatile tvb, tvbuff_t *decrypted_tvb,
2169                     guint8 *drep, dcerpc_info *info,
2170                     dcerpc_auth_info *auth_info)
2171 {
2172     volatile gint offset = 0;
2173     dcerpc_uuid_key key;
2174     dcerpc_uuid_value *sub_proto;
2175     proto_tree *volatile sub_tree = NULL;
2176     dcerpc_sub_dissector *proc;
2177     const gchar *name = NULL;
2178     dcerpc_dissect_fnct_t *volatile sub_dissect;
2179     const char *volatile saved_proto;
2180     void *volatile saved_private_data;
2181     guint length, reported_length;
2182     tvbuff_t *volatile stub_tvb;
2183     volatile guint auth_pad_len;
2184     volatile int auth_pad_offset;
2185 #ifdef _WIN32
2186     char UUID_NAME[MAX_PATH];
2187 #endif
2188     proto_item *sub_item;
2189
2190     key.uuid = info->call_data->uuid;
2191     key.ver = info->call_data->ver;
2192
2193
2194     if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == NULL
2195          || !proto_is_protocol_enabled(sub_proto->proto)) {
2196         /*
2197          * We don't have a dissector for this UUID, or the protocol
2198          * for that UUID is disabled.
2199          */
2200
2201         proto_tree_add_boolean_hidden(dcerpc_tree, hf_dcerpc_unknown_if_id,
2202                                           tvb, offset, 0, TRUE);
2203         if (check_col (pinfo->cinfo, COL_INFO)) {
2204 #ifdef _WIN32
2205                 if(ResolveWin32UUID(info->call_data->uuid, UUID_NAME, MAX_PATH))
2206                         col_append_fstr (pinfo->cinfo, COL_INFO, " [%s] UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x rpcver: %u",
2207                                 UUID_NAME, info->call_data->uuid.Data1, info->call_data->uuid.Data2, info->call_data->uuid.Data3, info->call_data->uuid.Data4[0],
2208                                 info->call_data->uuid.Data4[1], info->call_data->uuid.Data4[2], info->call_data->uuid.Data4[3],
2209                                 info->call_data->uuid.Data4[4], info->call_data->uuid.Data4[5], info->call_data->uuid.Data4[6],
2210                                 info->call_data->uuid.Data4[7], info->call_data->ver);
2211 else
2212 #endif
2213                 col_append_fstr (pinfo->cinfo, COL_INFO, " UNKUUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x rpcver: %u",
2214                         info->call_data->uuid.Data1, info->call_data->uuid.Data2, info->call_data->uuid.Data3, info->call_data->uuid.Data4[0],
2215                         info->call_data->uuid.Data4[1], info->call_data->uuid.Data4[2], info->call_data->uuid.Data4[3],
2216                         info->call_data->uuid.Data4[4], info->call_data->uuid.Data4[5], info->call_data->uuid.Data4[6],
2217                         info->call_data->uuid.Data4[7], info->call_data->ver);
2218         }
2219
2220         if (decrypted_tvb != NULL) {
2221             show_stub_data (decrypted_tvb, 0, dcerpc_tree, auth_info,
2222                             FALSE);
2223         } else
2224             show_stub_data (tvb, 0, dcerpc_tree, auth_info, TRUE);
2225         return -1;
2226     }
2227
2228     for (proc = sub_proto->procs; proc->name; proc++) {
2229         if (proc->num == info->call_data->opnum) {
2230             name = proc->name;
2231             break;
2232         }
2233     }
2234
2235     if (!name)
2236         name = "Unknown?!";
2237
2238     if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
2239         col_set_str (pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
2240     }
2241
2242     if (check_col (pinfo->cinfo, COL_INFO)) {
2243         col_add_fstr (pinfo->cinfo, COL_INFO, "%s %s",
2244                       name, (info->ptype == PDU_REQ) ? "request" : "response");
2245     }
2246
2247     if (tree) {
2248         sub_item = proto_tree_add_item (tree, sub_proto->proto_id, tvb, 0,
2249                                         -1, FALSE);
2250
2251         if (sub_item) {
2252             sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
2253             proto_item_append_text(sub_item, ", %s", name);
2254         }
2255
2256         /*
2257          * Put the operation number into the tree along with
2258          * the operation's name.
2259          */
2260
2261         if (sub_proto->opnum_hf != -1)
2262             proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
2263                                        tvb, 0, 0, info->call_data->opnum,
2264                                        "Operation: %s (%u)",
2265                                        name, info->call_data->opnum);
2266         else
2267             proto_tree_add_uint_format(sub_tree, hf_dcerpc_op, tvb,
2268                                        0, 0, info->call_data->opnum,
2269                                        "Operation: %s (%u)",
2270                                        name, info->call_data->opnum);
2271     }
2272
2273     sub_dissect = (info->ptype == PDU_REQ) ? 
2274             proc->dissect_rqst : proc->dissect_resp;
2275
2276     if (decrypted_tvb != NULL) {
2277         /* Either there was no encryption or we successfully decrypted
2278            the entrypted payload. */
2279         if (sub_dissect) {
2280             /* We have a subdissector - call it. */
2281             saved_proto = pinfo->current_proto;
2282             saved_private_data = pinfo->private_data;
2283             pinfo->current_proto = sub_proto->name;
2284             pinfo->private_data = (void *)info;
2285             
2286             init_ndr_pointer_list(pinfo);
2287
2288             /*
2289              * Remove the authentication padding from the stub data.
2290              */
2291             if (auth_info != NULL && auth_info->auth_pad_len != 0) {
2292                 length = tvb_length(decrypted_tvb);
2293                 reported_length = tvb_reported_length(decrypted_tvb);
2294                 if (reported_length >= auth_info->auth_pad_len) {
2295                     /*
2296                      * OK, the padding length isn't so big that it
2297                      * exceeds the stub length.  Trim the reported
2298                      * length of the tvbuff.
2299                      */
2300                     reported_length -= auth_info->auth_pad_len;
2301
2302                     /*
2303                      * If that exceeds the actual amount of data in
2304                      * the tvbuff (which means we have at least one
2305                      * byte of authentication padding in the tvbuff),
2306                      * trim the actual amount.
2307                      */
2308                     if (length > reported_length)
2309                         length = reported_length;
2310
2311                     stub_tvb = tvb_new_subset(tvb, 0, length, reported_length);
2312                     auth_pad_len = auth_info->auth_pad_len;
2313                     auth_pad_offset = reported_length;
2314                 } else {
2315                     /*
2316                      * The padding length exceeds the stub length.
2317                      * Don't bother dissecting the stub, trim the padding
2318                      * length to what's in the stub data, and show the
2319                      * entire stub as authentication padding.
2320                      */
2321                     stub_tvb = NULL;
2322                     auth_pad_len = reported_length;
2323                     auth_pad_offset = 0;
2324                 }
2325             } else {
2326                 /*
2327                  * No authentication padding.
2328                  */
2329                 stub_tvb = decrypted_tvb;
2330                 auth_pad_len = 0;
2331                 auth_pad_offset = 0;
2332             }
2333
2334             if (stub_tvb != NULL) {
2335                 /*
2336                  * Catch all exceptions other than BoundsError, so that even
2337                  * if the stub data is bad, we still show the authentication
2338                  * padding, if any.
2339                  *
2340                  * If we get BoundsError, it means the frame was cut short
2341                  * by a snapshot length, so there's nothing more to
2342                  * dissect; just re-throw that exception.
2343                  */
2344                 TRY {
2345                     offset = sub_dissect (decrypted_tvb, 0, pinfo, sub_tree,
2346                                           drep);
2347                     if(tree) {
2348                         proto_item_set_len(sub_item, offset);
2349                     }
2350
2351                     /* If we have a subdissector and it didn't dissect all
2352                        data in the tvb, make a note of it. */
2353                     /* XXX - don't do this, as this could be just another RPC Req./Resp. in this PDU */
2354                     /*if (tvb_reported_length_remaining(stub_tvb, offset) > 0) {
2355                         if (check_col(pinfo->cinfo, COL_INFO))
2356                             col_append_fstr(pinfo->cinfo, COL_INFO,
2357                                             "[Long frame (%d bytes)]",
2358                                             tvb_reported_length_remaining(stub_tvb, offset));
2359                     }*/
2360                 } CATCH(BoundsError) {
2361                     RETHROW;
2362                 } CATCH_ALL {
2363                     show_exception(decrypted_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
2364                 } ENDTRY;
2365             }
2366
2367             /* If there is auth padding at the end of the stub, display it */
2368             if (auth_pad_len != 0) {
2369                 tvb_ensure_bytes_exist(tvb, auth_pad_offset, auth_pad_len);
2370                 proto_tree_add_text (sub_tree, decrypted_tvb, auth_pad_offset,
2371                                      auth_pad_len,
2372                                      "Auth Padding (%u byte%s)",
2373                                      auth_pad_len,
2374                                      plurality(auth_pad_len, "", "s"));
2375             }
2376
2377             pinfo->current_proto = saved_proto;
2378             pinfo->private_data = saved_private_data;
2379         } else {
2380             /* No subdissector - show it as stub data. */
2381             if(decrypted_tvb){
2382                show_stub_data (decrypted_tvb, 0, sub_tree, auth_info, FALSE);
2383             } else {
2384                show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
2385             }
2386         }
2387     } else
2388         show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
2389
2390     tap_queue_packet(dcerpc_tap, pinfo, info);
2391     return 0;
2392 }
2393
2394 static int
2395 dissect_dcerpc_verifier (tvbuff_t *tvb, packet_info *pinfo, 
2396                          proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
2397                          dcerpc_auth_info *auth_info)
2398 {
2399     int auth_offset;
2400
2401     auth_info->auth_data = NULL;
2402
2403     if (auth_info->auth_size != 0) {
2404         dcerpc_auth_subdissector_fns *auth_fns;
2405         tvbuff_t *auth_tvb;
2406
2407         auth_offset = hdr->frag_len - hdr->auth_len;
2408
2409         auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
2410                                   hdr->auth_len);
2411
2412         auth_info->auth_data = auth_tvb;
2413
2414         if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
2415                                                   auth_info->auth_type))) {
2416             /*
2417              * Catch all exceptions, so that even if the verifier is bad
2418              * or we don't have all of it, we still show the stub data.
2419              */
2420             TRY {
2421                 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
2422                                   hdr, auth_info);
2423             } CATCH_ALL {
2424                 show_exception(auth_tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
2425             } ENDTRY;
2426         } else {
2427             tvb_ensure_bytes_exist(tvb, 0, hdr->auth_len);
2428             proto_tree_add_text (dcerpc_tree, auth_tvb, 0, hdr->auth_len,
2429                                  "Auth Verifier");
2430         }
2431     }
2432
2433     return hdr->auth_len;
2434 }
2435
2436 static void
2437 dissect_dcerpc_cn_auth (tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
2438                         proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
2439                         gboolean are_credentials, dcerpc_auth_info *auth_info)
2440 {
2441     volatile int offset;
2442
2443     /*
2444      * Initially set auth_level and auth_type to zero to indicate that we 
2445      * haven't yet seen any authentication level information.
2446      */
2447     auth_info->auth_level = 0;
2448     auth_info->auth_type = 0;
2449     auth_info->auth_size = 0;
2450     auth_info->auth_pad_len = 0;
2451     
2452     /*
2453      * The authentication information is at the *end* of the PDU; in
2454      * request and response PDUs, the request and response stub data
2455      * come before it.
2456      *
2457      * Is there any authentication data (i.e., is the authentication length
2458      * non-zero), and is the authentication length valid (i.e., is it, plus
2459      * 8 bytes for the type/level/pad length/reserved/context id, less than
2460      * or equal to the fragment length minus the starting offset of the
2461      * stub data?)
2462      */
2463
2464     if (hdr->auth_len
2465         && (hdr->auth_len + 8 <= hdr->frag_len - stub_offset)) {
2466
2467         /*
2468          * Yes, there is authentication data, and the length is valid.
2469          * Do we have all the bytes of stub data?
2470          * (If not, we'd throw an exception dissecting *that*, so don't
2471          * bother trying to dissect the authentication information and
2472          * throwing another exception there.)
2473          */
2474         offset = hdr->frag_len - (hdr->auth_len + 8);
2475         if (offset == 0 || tvb_offset_exists(tvb, offset - 1)) {
2476             /*
2477              * Either there's no stub data, or the last byte of the stub
2478              * data is present in the captured data, so we shouldn't
2479              * get a BoundsError dissecting the stub data.
2480              *
2481              * Try dissecting the authentication data.
2482              * Catch all exceptions, so that even if the auth info is bad
2483              * or we don't have all of it, we still show the stuff we
2484              * dissect after this, such as stub data.
2485              */
2486             TRY {
2487                 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2488                                                hf_dcerpc_auth_type, 
2489                                                &auth_info->auth_type);
2490                 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2491                                                hf_dcerpc_auth_level, 
2492                                                &auth_info->auth_level);
2493
2494                 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2495                                                hf_dcerpc_auth_pad_len, 
2496                                                &auth_info->auth_pad_len);
2497                 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2498                                                hf_dcerpc_auth_rsrvd, NULL);
2499                 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2500                                                 hf_dcerpc_auth_ctx_id, NULL);
2501
2502                 /*
2503                  * Dissect the authentication data.
2504                  */
2505                 if (are_credentials) {
2506                     tvbuff_t *auth_tvb;
2507                     dcerpc_auth_subdissector_fns *auth_fns;
2508
2509                     auth_tvb = tvb_new_subset(tvb, offset, hdr->auth_len,
2510                                               hdr->auth_len);
2511
2512                     if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
2513                                                               auth_info->auth_type)))
2514                         dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns, 
2515                                           hdr, auth_info);
2516                     else
2517                         proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len,
2518                                              "Auth Credentials");
2519                 }
2520         
2521                 /* Compute the size of the auth block.  Note that this should not 
2522                    include auth padding, since when NTLMSSP encryption is used, the
2523                    padding is actually inside the encrypted stub */
2524                    auth_info->auth_size = hdr->auth_len + 8;
2525             } CATCH_ALL {
2526                 show_exception(tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
2527             } ENDTRY;
2528         }
2529     }
2530 }
2531
2532
2533 /* We need to hash in the SMB fid number to generate a unique hash table
2534  * key as DCERPC over SMB allows several pipes over the same TCP/IP
2535  * socket. 
2536  * We pass this function the transport type here to make sure we only look
2537  * at this function if it came across an SMB pipe.
2538  * Other transports might need to mix in their own extra multiplexing data
2539  * as well in the future.
2540  */
2541
2542 guint16 dcerpc_get_transport_salt (packet_info *pinfo)
2543 {
2544     switch(pinfo->dcetransporttype){
2545         case DCE_CN_TRANSPORT_SMBPIPE:
2546             /* DCERPC over smb */
2547             return pinfo->dcetransportsalt;
2548     }
2549
2550     /* Some other transport... */
2551     return 0;
2552 }
2553
2554 /*
2555  * Connection oriented packet types
2556  */
2557
2558 static void
2559 dissect_dcerpc_cn_bind (tvbuff_t *tvb, gint offset, packet_info *pinfo, 
2560                         proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2561 {
2562     conversation_t *conv = NULL;
2563     guint8 num_ctx_items = 0;
2564     guint i;
2565     gboolean saw_ctx_item = FALSE;
2566     guint16 ctx_id;
2567     guint8 num_trans_items;
2568     guint j;
2569     e_uuid_t if_id;
2570     e_uuid_t trans_id;
2571     guint32 trans_ver;
2572     guint16 if_ver, if_ver_minor;
2573     char uuid_str[DCERPC_UUID_STR_LEN]; 
2574     int uuid_str_len;
2575     dcerpc_auth_info auth_info;
2576 #ifdef _WIN32
2577     char UUID_NAME[MAX_PATH];
2578 #endif
2579
2580     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2581                                     hf_dcerpc_cn_max_xmit, NULL);
2582
2583     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2584                                     hf_dcerpc_cn_max_recv, NULL);
2585
2586     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2587                                     hf_dcerpc_cn_assoc_group, NULL);
2588
2589     offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2590                                     hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
2591
2592     /* padding */
2593     offset += 3;
2594
2595     for (i = 0; i < num_ctx_items; i++) {
2596             proto_tree *ctx_tree = NULL, *iface_tree = NULL;
2597
2598       offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, NULL, hdr->drep,
2599                                       hf_dcerpc_cn_ctx_id, &ctx_id);
2600
2601       /* save context ID for use with dcerpc_add_conv_to_bind_table() */
2602       /* (if we have multiple contexts, this might cause "decode as"
2603        *  to behave unpredictably) */
2604       pinfo->dcectxid = ctx_id;
2605
2606       if (dcerpc_tree) {
2607               proto_item *ctx_item;
2608
2609               ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_id,
2610                                              tvb, offset - 2, 2, 
2611                                              hdr->drep[0] & 0x10);
2612
2613               ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
2614       }
2615
2616       offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, ctx_tree, hdr->drep,
2617                                       hf_dcerpc_cn_num_trans_items, &num_trans_items);
2618
2619       /* padding */
2620       offset += 1;
2621
2622       /* XXX - use "dissect_ndr_uuid_t()"? */
2623       dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
2624       if (ctx_tree) {
2625           proto_item *iface_item;
2626
2627           uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, 
2628                                   "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2629                                   if_id.Data1, if_id.Data2, if_id.Data3,
2630                                   if_id.Data4[0], if_id.Data4[1],
2631                                   if_id.Data4[2], if_id.Data4[3],
2632                                   if_id.Data4[4], if_id.Data4[5],
2633                                   if_id.Data4[6], if_id.Data4[7]);
2634
2635           if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2636                   memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2637 #ifdef _WIN32
2638           if(ResolveWin32UUID(if_id, UUID_NAME, MAX_PATH))
2639                   iface_item = proto_tree_add_string_format (ctx_tree, hf_dcerpc_cn_bind_if_id, tvb,
2640                                         offset, 16, uuid_str, "Interface [%s] UUID: %s", UUID_NAME, uuid_str);
2641           else
2642 #endif
2643           iface_item = proto_tree_add_string_format (ctx_tree, hf_dcerpc_cn_bind_if_id, tvb,
2644                                         offset, 16, uuid_str, "Interface UUID: %s", uuid_str);
2645           iface_tree = proto_item_add_subtree(iface_item, ett_dcerpc_cn_iface);
2646       }
2647       offset += 16;
2648
2649       if (hdr->drep[0] & 0x10) {
2650           offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2651                                           hf_dcerpc_cn_bind_if_ver, &if_ver);
2652           offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2653                                           hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2654       } else {
2655           offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2656                                           hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2657           offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2658                                           hf_dcerpc_cn_bind_if_ver, &if_ver);
2659       }
2660
2661       if (!saw_ctx_item) {
2662         conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
2663                                   pinfo->srcport, pinfo->destport, 0);
2664         if (conv == NULL) {
2665             conv = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
2666                                      pinfo->srcport, pinfo->destport, 0);
2667         }
2668
2669
2670         /* if this is the first time we see this packet, we need to
2671            update the dcerpc_binds table so that any later calls can
2672            match to the interface.
2673            XXX We assume that BINDs will NEVER be fragmented.
2674         */
2675         if(!(pinfo->fd->flags.visited)){
2676                 dcerpc_bind_key *key;
2677                 dcerpc_bind_value *value;
2678
2679                 key = g_mem_chunk_alloc (dcerpc_bind_key_chunk);
2680                 key->conv = conv;
2681                 key->ctx_id = ctx_id;
2682                 key->smb_fid = dcerpc_get_transport_salt(pinfo);
2683
2684                 value = g_mem_chunk_alloc (dcerpc_bind_value_chunk);
2685                 value->uuid = if_id;
2686                 value->ver = if_ver;
2687
2688                 /* add this entry to the bind table, first removing any
2689                    previous ones that are identical
2690                  */
2691                 if(g_hash_table_lookup(dcerpc_binds, key)){
2692                         g_hash_table_remove(dcerpc_binds, key);
2693                 }
2694                 g_hash_table_insert (dcerpc_binds, key, value);
2695         }
2696
2697         if (check_col (pinfo->cinfo, COL_INFO)) {
2698           dcerpc_uuid_key key;
2699           dcerpc_uuid_value *value;
2700
2701           key.uuid = if_id;
2702           key.ver = if_ver;
2703
2704           if (num_ctx_items > 1)
2705                   col_append_fstr(pinfo->cinfo, COL_INFO, ", %u context items, 1st", num_ctx_items);
2706                 
2707           if ((value = g_hash_table_lookup(dcerpc_uuids, &key)))
2708                   col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %s", value->name);
2709           else
2710 #ifdef _WIN32
2711                 if(ResolveWin32UUID(if_id, UUID_NAME, MAX_PATH))
2712                         col_append_fstr(pinfo->cinfo, COL_INFO, " [%s] UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
2713                            UUID_NAME, if_id.Data1, if_id.Data2, if_id.Data3,
2714                            if_id.Data4[0], if_id.Data4[1],
2715                            if_id.Data4[2], if_id.Data4[3],
2716                            if_id.Data4[4], if_id.Data4[5],
2717                            if_id.Data4[6], if_id.Data4[7],
2718                            if_ver, if_ver_minor);
2719           else
2720 #endif
2721                         col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
2722                            if_id.Data1, if_id.Data2, if_id.Data3,
2723                            if_id.Data4[0], if_id.Data4[1],
2724                            if_id.Data4[2], if_id.Data4[3],
2725                            if_id.Data4[4], if_id.Data4[5],
2726                            if_id.Data4[6], if_id.Data4[7],
2727                            if_ver, if_ver_minor);
2728         }
2729         saw_ctx_item = TRUE;
2730       }
2731
2732       for (j = 0; j < num_trans_items; j++) {
2733         /* XXX - use "dissect_ndr_uuid_t()"? */
2734         dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2735         if (iface_tree) {
2736             uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, 
2737                                   "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2738                                   trans_id.Data1, trans_id.Data2, trans_id.Data3,
2739                                   trans_id.Data4[0], trans_id.Data4[1],
2740                                   trans_id.Data4[2], trans_id.Data4[3],
2741                                   trans_id.Data4[4], trans_id.Data4[5],
2742                                   trans_id.Data4[6], trans_id.Data4[7]);
2743             if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2744                 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2745             proto_tree_add_string_format (iface_tree, hf_dcerpc_cn_bind_trans_id, tvb,
2746                                           offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2747         }
2748         offset += 16;
2749
2750         offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, iface_tree, hdr->drep,
2751                                         hf_dcerpc_cn_bind_trans_ver, &trans_ver);
2752       }
2753     }
2754
2755     /*
2756      * XXX - we should save the authentication type *if* we have
2757      * an authentication header, and associate it with an authentication
2758      * context, so subsequent PDUs can use that context.
2759      */
2760     dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2761 }
2762
2763 static void
2764 dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, gint offset, packet_info *pinfo, 
2765                             proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2766 {
2767     guint16 max_xmit, max_recv;
2768     guint16 sec_addr_len;
2769     guint8 num_results;
2770     guint i;
2771     guint16 result;
2772     guint16 reason;
2773     e_uuid_t trans_id;
2774     guint32 trans_ver;
2775     char uuid_str[DCERPC_UUID_STR_LEN]; 
2776     int uuid_str_len;
2777     dcerpc_auth_info auth_info;
2778
2779     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2780                                     hf_dcerpc_cn_max_xmit, &max_xmit);
2781
2782     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2783                                     hf_dcerpc_cn_max_recv, &max_recv);
2784
2785     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2786                                     hf_dcerpc_cn_assoc_group, NULL);
2787
2788     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2789                                     hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
2790     if (sec_addr_len != 0) {
2791         tvb_ensure_bytes_exist(tvb, offset, sec_addr_len);
2792         proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
2793                              sec_addr_len, FALSE);
2794         offset += sec_addr_len;
2795     }
2796
2797     if (offset % 4) {
2798         offset += 4 - offset % 4;
2799     }
2800
2801     offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2802                                    hf_dcerpc_cn_num_results, &num_results);
2803
2804     /* padding */
2805     offset += 3;
2806
2807     for (i = 0; i < num_results; i++) {
2808         offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2809                                         hdr->drep, hf_dcerpc_cn_ack_result,
2810                                         &result);
2811         if (result != 0) {
2812             offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2813                                             hdr->drep, hf_dcerpc_cn_ack_reason,
2814                                             &reason);
2815         } else {
2816             /*
2817              * The reason for rejection isn't meaningful, and often isn't
2818              * set, when the syntax was accepted.
2819              */
2820             offset += 2;
2821         }
2822
2823         /* XXX - use "dissect_ndr_uuid_t()"? */
2824         dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2825         if (dcerpc_tree) {
2826             uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, 
2827                                   "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2828                                   trans_id.Data1, trans_id.Data2, trans_id.Data3,
2829                                   trans_id.Data4[0], trans_id.Data4[1],
2830                                   trans_id.Data4[2], trans_id.Data4[3],
2831                                   trans_id.Data4[4], trans_id.Data4[5],
2832                                   trans_id.Data4[6], trans_id.Data4[7]);
2833             if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2834                   memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2835             proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_ack_trans_id, tvb,
2836                                           offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2837         }
2838         offset += 16;
2839
2840         offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2841                                         hf_dcerpc_cn_ack_trans_ver, &trans_ver);
2842     }
2843
2844     /*
2845      * XXX - do we need to do anything with the authentication level
2846      * we get back from this?
2847      */
2848     dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2849
2850     if (check_col (pinfo->cinfo, COL_INFO)) {
2851         if (num_results != 0 && result == 0) {
2852             /* XXX - only checks the last result */
2853             col_append_fstr (pinfo->cinfo, COL_INFO,
2854                              " accept max_xmit: %u max_recv: %u",
2855                              max_xmit, max_recv);
2856         } else {
2857             /* XXX - only shows the last result and reason */
2858             col_append_fstr (pinfo->cinfo, COL_INFO, " %s, reason: %s",
2859                              val_to_str(result, p_cont_result_vals,
2860                                         "Unknown result (%u)"),
2861                              val_to_str(reason, p_provider_reason_vals,
2862                                         "Unknown (%u)"));
2863         }
2864     }
2865 }
2866
2867 static void
2868 dissect_dcerpc_cn_bind_nak (tvbuff_t *tvb, gint offset, packet_info *pinfo, 
2869                             proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2870 {
2871     guint16 reason;
2872     guint8 num_protocols;
2873     guint i;
2874
2875     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2876                                     hdr->drep, hf_dcerpc_cn_reject_reason,
2877                                     &reason);
2878
2879     if (check_col (pinfo->cinfo, COL_INFO)) {
2880         col_append_fstr (pinfo->cinfo, COL_INFO, " reason: %s",
2881                       val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
2882     }
2883
2884     if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
2885         offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2886                                        hf_dcerpc_cn_num_protocols,
2887                                        &num_protocols);
2888
2889         for (i = 0; i < num_protocols; i++) {
2890             offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2891                                         hdr->drep, hf_dcerpc_cn_protocol_ver_major,
2892                                         NULL);
2893             offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2894                                         hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
2895                                         NULL);
2896         }
2897     }
2898 }
2899
2900 /* Return a string describing a DCE/RPC fragment as first, middle, or end
2901    fragment. */
2902
2903 #define PFC_FRAG_MASK  0x03
2904
2905 static const char *
2906 fragment_type(guint8 flags)
2907 {
2908         flags = flags & PFC_FRAG_MASK;
2909
2910         if (flags == PFC_FIRST_FRAG)
2911                 return "first";
2912
2913         if (flags == 0)
2914                 return "middle";
2915
2916         if (flags == PFC_LAST_FRAG)
2917                 return "last";
2918
2919         if (flags == (PFC_FIRST_FRAG | PFC_LAST_FRAG))
2920                 return "whole";
2921
2922         return "unknown";
2923 }
2924
2925 /* Dissect stub data (payload) of a DCERPC packet. */
2926
2927 static void
2928 dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
2929                         proto_tree *dcerpc_tree, proto_tree *tree,
2930                         e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
2931                         dcerpc_auth_info *auth_info, guint32 alloc_hint,
2932                         guint32 frame)
2933 {
2934     gint length, reported_length;
2935     gboolean save_fragmented;
2936     fragment_data *fd_head=NULL;
2937     guint32 tot_len;
2938     tvbuff_t *auth_tvb, *payload_tvb, *decrypted_tvb;
2939     proto_item *pi;
2940     proto_item *parent_pi;
2941
2942     save_fragmented = pinfo->fragmented;
2943
2944     length = tvb_length_remaining(tvb, offset);
2945     reported_length = tvb_reported_length_remaining(tvb, offset);
2946     if (reported_length < 0 ||
2947         (guint32)reported_length < auth_info->auth_size) {
2948         /* We don't even have enough bytes for the authentication
2949            stuff. */
2950         return;
2951     }
2952     reported_length -= auth_info->auth_size;
2953     if (length > reported_length)
2954         length = reported_length;
2955     payload_tvb = tvb_new_subset(tvb, offset, length, reported_length);
2956
2957     auth_tvb=NULL;
2958     /*dont bother if we dont have the entire tvb */
2959     /*XXX we should really make sure we calculate auth_info->auth_data
2960         and use that one instead of this auth_tvb hack
2961     */
2962     if(tvb_length(tvb)==tvb_reported_length(tvb)){
2963         if(tvb_length_remaining(tvb, offset+length)>8){
2964             auth_tvb = tvb_new_subset(tvb, offset+length+8, -1, -1);
2965         }
2966     }
2967
2968     /* Decrypt the PDU if it is encrypted */
2969
2970     if (auth_info->auth_type &&
2971         auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
2972             /*
2973              * We know the authentication type, and the authentication
2974              * level is "Packet privacy", meaning the payload is
2975              * encrypted; attempt to decrypt it.
2976              */
2977             dcerpc_auth_subdissector_fns *auth_fns;
2978             
2979             /* Start out assuming we won't succeed in decrypting. */
2980             decrypted_tvb = NULL;
2981
2982             if ((auth_fns = get_auth_subdissector_fns(
2983                          auth_info->auth_level, auth_info->auth_type))) {
2984                     tvbuff_t *result;
2985
2986                     result = decode_encrypted_data(
2987                             payload_tvb, auth_tvb, pinfo, auth_fns,
2988                             hdr->ptype == PDU_REQ, auth_info);      
2989                     
2990                     if (result) {
2991                             if (dcerpc_tree)
2992                                 proto_tree_add_text(
2993                                             dcerpc_tree, payload_tvb, 0, -1,
2994                                             "Encrypted stub data (%d byte%s)",
2995                                             tvb_reported_length(payload_tvb),
2996
2997                             plurality(tvb_length(payload_tvb), "", "s"));
2998
2999                             add_new_data_source(
3000                                     pinfo, result, "Decrypted stub data");
3001                             
3002                             /* We succeeded. */
3003                             decrypted_tvb = result;
3004                     }
3005             }
3006     } else
3007             decrypted_tvb = payload_tvb;
3008
3009     /* if this packet is not fragmented, just dissect it and exit */
3010     if(PFC_NOT_FRAGMENTED(hdr)){
3011         pinfo->fragmented = FALSE;
3012
3013         dcerpc_try_handoff(
3014                 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
3015                 hdr->drep, di, auth_info);
3016         
3017         pinfo->fragmented = save_fragmented;
3018         return;
3019     }
3020
3021     /* The packet is fragmented. */
3022     pinfo->fragmented = TRUE;
3023
3024     /* if we are not doing reassembly and this is the first fragment
3025        then just dissect it and exit
3026        XXX - if we're not doing reassembly, can we decrypt an
3027        encrypted stub?
3028     */
3029     if( (!dcerpc_reassemble) && hdr->flags&PFC_FIRST_FRAG ){
3030
3031         dcerpc_try_handoff(
3032                 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
3033                 hdr->drep, di, auth_info);
3034         
3035         if (check_col(pinfo->cinfo, COL_INFO)) {
3036             col_append_fstr(pinfo->cinfo, COL_INFO,
3037                             " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
3038         }
3039         pinfo->fragmented = save_fragmented;
3040         return;
3041     }
3042
3043     /* if we have already seen this packet, see if it was reassembled
3044        and if so dissect the full pdu.
3045        then exit 
3046     */
3047     if(pinfo->fd->flags.visited){
3048         fd_head=fragment_get(pinfo, frame, dcerpc_co_reassemble_table);
3049         goto end_cn_stub;
3050     }
3051
3052     /* if we are not doing reassembly and it was neither a complete PDU
3053        nor the first fragment then there is nothing more we can do
3054        so we just have to exit
3055     */
3056     if( !dcerpc_reassemble )
3057         goto end_cn_stub;
3058
3059     /* if we didnt get 'frame' we dont know where the PDU started and thus
3060        it is pointless to continue 
3061     */
3062     if(!frame)
3063         goto end_cn_stub;
3064
3065     /* from now on we must attempt to reassemble the PDU 
3066     */
3067
3068     /* if we get here we know it is the first time we see the packet
3069        and we also know it is only a fragment and not a full PDU,
3070        thus we must reassemble it.
3071     */
3072
3073     /* Do we have any non-encrypted data to reassemble? */
3074     if (decrypted_tvb == NULL) {
3075       /* No.  We can't even try to reassemble.  */
3076       goto end_cn_stub;
3077     }
3078
3079     /* defragmentation is a bit tricky here, as there's no offset of the fragment 
3080      * in the protocol data.
3081      *
3082      * Currently two possible ways:
3083      * - the transmitter sends an alloc_hint != 0, use it
3084      * - the transmitter sends an alloc_hint == 0, simply append fragments
3085      */
3086
3087     /* if this is the first fragment we need to start reassembly
3088     */
3089     if(hdr->flags&PFC_FIRST_FRAG){
3090         fragment_add(decrypted_tvb, 0, pinfo, frame, dcerpc_co_reassemble_table,
3091                      0, tvb_length(decrypted_tvb), TRUE);
3092         fragment_set_tot_len(pinfo, frame,
3093         dcerpc_co_reassemble_table, alloc_hint ? alloc_hint : tvb_length(decrypted_tvb));
3094
3095         goto end_cn_stub;
3096     }
3097
3098     /* if this is a middle fragment, just add it and exit */
3099     if(!(hdr->flags&PFC_LAST_FRAG)){
3100         tot_len = fragment_get_tot_len(pinfo, frame,
3101                  dcerpc_co_reassemble_table);
3102     tvb_ensure_bytes_exist(tvb, tot_len-alloc_hint, tvb_length(decrypted_tvb));
3103         fragment_add(decrypted_tvb, 0, pinfo, frame,
3104                  dcerpc_co_reassemble_table,
3105                  tot_len-alloc_hint, tvb_length(decrypted_tvb),
3106                  TRUE);
3107         if(alloc_hint == 0) {
3108              fragment_set_tot_len(pinfo, frame,
3109                   dcerpc_co_reassemble_table, tot_len + tvb_length(decrypted_tvb));
3110         }
3111
3112         goto end_cn_stub;
3113     }
3114
3115     /* this was the last fragment add it to reassembly
3116     */
3117     tot_len = fragment_get_tot_len(pinfo, frame,
3118                 dcerpc_co_reassemble_table);
3119     tvb_ensure_bytes_exist(tvb, tot_len-alloc_hint, tvb_length(decrypted_tvb));
3120     fd_head = fragment_add(decrypted_tvb, 0, pinfo,
3121                 frame,
3122                 dcerpc_co_reassemble_table,
3123                 tot_len-alloc_hint, tvb_length(decrypted_tvb),
3124                 TRUE);
3125         if(alloc_hint == 0) {           
3126             fragment_set_tot_len(pinfo, frame,
3127                   dcerpc_co_reassemble_table, tot_len + tvb_length(decrypted_tvb));
3128     }
3129
3130 end_cn_stub:
3131
3132     /* if reassembly is complete, dissect the full PDU
3133     */
3134     if(fd_head && (fd_head->flags&FD_DEFRAGMENTED) ){
3135
3136         if(pinfo->fd->num==fd_head->reassembled_in){
3137             tvbuff_t *next_tvb;
3138         proto_item *frag_tree_item;
3139
3140             next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
3141             tvb_set_child_real_data_tvbuff(decrypted_tvb, next_tvb);
3142             add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3143             show_fragment_tree(fd_head, &dcerpc_frag_items,
3144                 dcerpc_tree, pinfo, next_tvb, &frag_tree_item);
3145
3146             pinfo->fragmented = FALSE;
3147
3148             dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
3149                 next_tvb, hdr->drep, di, auth_info);
3150
3151         } else {
3152             pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
3153                                 decrypted_tvb, 0, 0, fd_head->reassembled_in);
3154         PROTO_ITEM_SET_GENERATED(pi);
3155         parent_pi = proto_tree_get_parent(dcerpc_tree);
3156         if(parent_pi != NULL) {
3157             proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
3158         }
3159             if (check_col(pinfo->cinfo, COL_INFO)) {
3160                 col_append_fstr(pinfo->cinfo, COL_INFO,
3161                         " [DCE/RPC %s fragment, reas: #%u]", fragment_type(hdr->flags), fd_head->reassembled_in);
3162             }
3163         }
3164     } else {
3165         /* Reassembly not complete - some fragments
3166            are missing.  Just show the stub data. */
3167         if (check_col(pinfo->cinfo, COL_INFO)) {
3168             col_append_fstr(pinfo->cinfo, COL_INFO,
3169                         " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
3170         }
3171
3172         if(decrypted_tvb){
3173                 show_stub_data (decrypted_tvb, 0, tree, auth_info, FALSE);
3174         } else {
3175                 show_stub_data (payload_tvb, 0, tree, auth_info, TRUE);
3176         }
3177     }
3178
3179     pinfo->fragmented = save_fragmented;
3180 }
3181
3182 /**
3183  *  Registers a conversation/UUID binding association, so that
3184  *  we can invoke the proper sub-dissector for a given DCERPC
3185  *  conversation.
3186  * 
3187  *  @param binding all values needed to create and bind a new conversation
3188  * 
3189  *  @return Pointer to newly-added UUID/conversation binding.
3190  */
3191 struct _dcerpc_bind_value *
3192 dcerpc_add_conv_to_bind_table(decode_dcerpc_bind_values_t *binding)
3193 {
3194     dcerpc_bind_value *bind_value;
3195     dcerpc_bind_key *key;
3196     conversation_t *conv;
3197
3198     conv = find_conversation (
3199         0, 
3200         &binding->addr_a, 
3201         &binding->addr_b, 
3202         binding->ptype, 
3203         binding->port_a, 
3204         binding->port_b, 
3205         0);
3206
3207     if (!conv) {
3208         conv = conversation_new (
3209             0, 
3210             &binding->addr_a, 
3211             &binding->addr_b, 
3212             binding->ptype, 
3213             binding->port_a, 
3214             binding->port_b, 
3215             0);
3216     }
3217     
3218     bind_value = g_mem_chunk_alloc (dcerpc_bind_value_chunk);
3219     bind_value->uuid = binding->uuid;
3220     bind_value->ver = binding->ver;
3221
3222     key = g_mem_chunk_alloc(dcerpc_bind_key_chunk);
3223     key->conv = conv;
3224     key->ctx_id = binding->ctx_id;
3225     key->smb_fid = binding->smb_fid;
3226  
3227     /* add this entry to the bind table, first removing any
3228        previous ones that are identical
3229      */
3230     if(g_hash_table_lookup(dcerpc_binds, key)){
3231             g_hash_table_remove(dcerpc_binds, key);
3232     }
3233     g_hash_table_insert(dcerpc_binds, key, bind_value);
3234
3235     return bind_value;
3236
3237 }
3238
3239 static void
3240 dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo, 
3241                         proto_tree *dcerpc_tree, proto_tree *tree,
3242                         e_dce_cn_common_hdr_t *hdr)
3243 {
3244     conversation_t *conv;
3245     guint16 ctx_id;
3246     guint16 opnum;
3247     e_uuid_t obj_id;
3248     dcerpc_auth_info auth_info;
3249     guint32 alloc_hint;
3250     char uuid_str[DCERPC_UUID_STR_LEN]; 
3251     int uuid_str_len;
3252     proto_item *pi;
3253     proto_item *parent_pi;
3254
3255     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3256                                     hf_dcerpc_cn_alloc_hint, &alloc_hint);
3257
3258     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3259                                     hf_dcerpc_cn_ctx_id, &ctx_id);
3260     parent_pi = proto_tree_get_parent(dcerpc_tree);
3261     if(parent_pi != NULL) {
3262         proto_item_append_text(parent_pi, " Ctx: %u", ctx_id);
3263     }
3264
3265     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3266                                     hf_dcerpc_opnum, &opnum);
3267
3268     /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3269     pinfo->dcectxid = ctx_id;
3270
3271     if (check_col (pinfo->cinfo, COL_INFO)) {
3272         col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u ctx_id: %u",
3273                          opnum, ctx_id);
3274     }
3275
3276     if (hdr->flags & PFC_OBJECT_UUID) {
3277         /* XXX - use "dissect_ndr_uuid_t()"? */
3278         dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id);
3279         if (dcerpc_tree) {
3280             uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, 
3281                                     "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3282                                     obj_id.Data1, obj_id.Data2, obj_id.Data3,
3283                                     obj_id.Data4[0],
3284                                     obj_id.Data4[1],
3285                                     obj_id.Data4[2],
3286                                     obj_id.Data4[3],
3287                                     obj_id.Data4[4],
3288                                     obj_id.Data4[5],
3289                                     obj_id.Data4[6],
3290                                     obj_id.Data4[7]);
3291             if (uuid_str_len >= DCERPC_UUID_STR_LEN)
3292                   memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
3293             proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
3294                                           offset, 16, uuid_str, "Object UUID: %s", uuid_str);
3295         }
3296         offset += 16;
3297     }
3298
3299     /*
3300      * XXX - what if this was set when the connection was set up,
3301      * and we just have a security context?
3302      */
3303     dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3304
3305     conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3306                               pinfo->srcport, pinfo->destport, 0);
3307     if (!conv)
3308         show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3309     else {
3310         dcerpc_matched_key matched_key, *new_matched_key;
3311         dcerpc_call_value *value;
3312
3313         /* !!! we can NOT check flags.visited here since this will interact
3314            badly with when SMB handles (i.e. calls the subdissector)
3315            and desegmented pdu's .
3316            Instead we check if this pdu is already in the matched table or not
3317         */
3318         matched_key.frame = pinfo->fd->num;
3319         matched_key.call_id = hdr->call_id;
3320         value = g_hash_table_lookup(dcerpc_matched, &matched_key);
3321         if(!value){
3322                 dcerpc_bind_key bind_key;
3323                 dcerpc_bind_value *bind_value;
3324
3325                 bind_key.conv=conv;
3326                 bind_key.ctx_id=ctx_id;
3327                 bind_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3328
3329                 if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key)) ){
3330                         if(!(hdr->flags&PFC_FIRST_FRAG)){
3331                                 dcerpc_cn_call_key call_key;
3332                                 dcerpc_call_value *call_value;
3333
3334                                 call_key.conv=conv;
3335                                 call_key.call_id=hdr->call_id;
3336                                 call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3337                                 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3338                                         new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3339                                         *new_matched_key = matched_key;
3340                                         g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3341                                         value = call_value;
3342                                 }
3343                         } else {
3344                                 dcerpc_cn_call_key *call_key;
3345                                 dcerpc_call_value *call_value;
3346
3347                                 /* We found the binding and it is the first fragment 
3348                                    (or a complete PDU) of a dcerpc pdu so just add 
3349                                    the call to both the call table and the 
3350                                    matched table
3351                                 */
3352                                 call_key=g_mem_chunk_alloc (dcerpc_cn_call_key_chunk);
3353                                 call_key->conv=conv;
3354                                 call_key->call_id=hdr->call_id;
3355                                 call_key->smb_fid=dcerpc_get_transport_salt(pinfo);
3356
3357                                 /* if there is already a matching call in the table
3358                                    remove it so it is replaced with the new one */
3359                                 if(g_hash_table_lookup(dcerpc_cn_calls, call_key)){
3360                                         g_hash_table_remove(dcerpc_cn_calls, call_key);
3361                                 }
3362
3363                                 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
3364                                 call_value->uuid = bind_value->uuid;
3365                                 call_value->ver = bind_value->ver;
3366                                 call_value->opnum = opnum;
3367                                 call_value->req_frame=pinfo->fd->num;
3368                                 call_value->req_time.secs=pinfo->fd->abs_secs;
3369                                 call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000;
3370                                 call_value->rep_frame=0;
3371                                 call_value->max_ptr=0;
3372                                 call_value->private_data = NULL;
3373                                 g_hash_table_insert (dcerpc_cn_calls, call_key, call_value);
3374
3375                                 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3376                                 *new_matched_key = matched_key;
3377                                 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3378                                 value = call_value;
3379                         }
3380                 }
3381         }
3382
3383         if (value) {
3384             dcerpc_info *di;
3385
3386             di=get_next_di();
3387             /* handoff this call */
3388             di->conv = conv;
3389             di->call_id = hdr->call_id;
3390             di->smb_fid = dcerpc_get_transport_salt(pinfo);
3391             di->ptype = PDU_REQ;
3392             di->call_data = value;
3393                 di->hf_index = -1;
3394
3395             if(value->rep_frame!=0){
3396                 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
3397                                     tvb, 0, 0, value->rep_frame);
3398         PROTO_ITEM_SET_GENERATED(pi);
3399         if(parent_pi != NULL) {
3400             proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
3401         }
3402             }
3403
3404             dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
3405                                     hdr, di, &auth_info, alloc_hint,
3406                                     value->req_frame);
3407         } else
3408             show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3409     }
3410
3411     /* Dissect the verifier */
3412     dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
3413
3414 }
3415
3416 static void
3417 dissect_dcerpc_cn_resp (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3418                         proto_tree *dcerpc_tree, proto_tree *tree,
3419                         e_dce_cn_common_hdr_t *hdr)
3420 {
3421     dcerpc_call_value *value = NULL;
3422     conversation_t *conv;
3423     guint16 ctx_id;
3424     dcerpc_auth_info auth_info;
3425     guint32 alloc_hint;
3426     proto_item *pi;
3427     proto_item *parent_pi;
3428
3429     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3430                                     hf_dcerpc_cn_alloc_hint, &alloc_hint);
3431
3432     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3433                                     hf_dcerpc_cn_ctx_id, &ctx_id);
3434     parent_pi = proto_tree_get_parent(dcerpc_tree);
3435     if(parent_pi != NULL) {
3436         proto_item_append_text(parent_pi, " Ctx: %u", ctx_id);
3437     }
3438
3439     /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3440     pinfo->dcectxid = ctx_id;
3441
3442     if (check_col (pinfo->cinfo, COL_INFO)) {
3443         col_append_fstr (pinfo->cinfo, COL_INFO, " ctx_id: %u", ctx_id);
3444     }
3445
3446     offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3447                                    hf_dcerpc_cn_cancel_count, NULL);
3448     /* padding */
3449     offset++;
3450
3451     /*
3452      * XXX - what if this was set when the connection was set up,
3453      * and we just have a security context?
3454      */
3455     dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3456
3457     conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3458                               pinfo->srcport, pinfo->destport, 0);
3459
3460     if (!conv) {
3461         /* no point in creating one here, really */
3462         show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3463     } else {
3464         dcerpc_matched_key matched_key, *new_matched_key;
3465
3466         /* !!! we can NOT check flags.visited here since this will interact
3467            badly with when SMB handles (i.e. calls the subdissector)
3468            and desegmented pdu's .
3469            Instead we check if this pdu is already in the matched table or not
3470         */
3471         matched_key.frame = pinfo->fd->num;
3472         matched_key.call_id = hdr->call_id;
3473         value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3474         if(!value){
3475                 dcerpc_cn_call_key call_key;
3476                 dcerpc_call_value *call_value;
3477
3478                 call_key.conv=conv;
3479                 call_key.call_id=hdr->call_id;
3480                 call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3481
3482                 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3483                         /* extra sanity check,  only match them if the reply
3484                            came after the request */
3485                         if(call_value->req_frame<pinfo->fd->num){
3486                                 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3487                                 *new_matched_key = matched_key;
3488                                 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3489                                 value = call_value;
3490                                 if(call_value->rep_frame==0){
3491                                         call_value->rep_frame=pinfo->fd->num;
3492                                 }
3493                         }
3494                 }
3495         }
3496
3497         if (value) {
3498             dcerpc_info *di;
3499
3500             di=get_next_di();
3501             /* handoff this call */
3502             di->conv = conv;
3503             di->call_id = hdr->call_id;
3504             di->smb_fid = dcerpc_get_transport_salt(pinfo);
3505             di->ptype = PDU_RESP;
3506             di->call_data = value;
3507
3508             proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
3509             if(value->req_frame!=0){
3510                 nstime_t ns;
3511                 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3512                                     tvb, 0, 0, value->req_frame);
3513         PROTO_ITEM_SET_GENERATED(pi);
3514         if(parent_pi != NULL) {
3515             proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
3516         }
3517                 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
3518                 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
3519                 if(ns.nsecs<0){
3520                         ns.nsecs+=1000000000;
3521                         ns.secs--;
3522                 }
3523                 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
3524         PROTO_ITEM_SET_GENERATED(pi);
3525             }
3526
3527             dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
3528                                     hdr, di, &auth_info, alloc_hint,
3529                                     value->rep_frame);
3530         } else
3531             show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3532     }
3533
3534     /* Dissect the verifier */
3535     dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
3536 }
3537
3538 static void
3539 dissect_dcerpc_cn_fault (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3540                          proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
3541 {
3542     dcerpc_call_value *value = NULL;
3543     conversation_t *conv;
3544     guint16 ctx_id;
3545     guint32 status;
3546     guint32 alloc_hint;
3547     dcerpc_auth_info auth_info;
3548     proto_item *pi;
3549
3550     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3551                                     hf_dcerpc_cn_alloc_hint, &alloc_hint);
3552
3553     offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3554                                     hf_dcerpc_cn_ctx_id, &ctx_id);
3555
3556     offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3557                                    hf_dcerpc_cn_cancel_count, NULL);
3558     /* padding */
3559     offset++;
3560
3561     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3562                                     hf_dcerpc_cn_status, &status);
3563
3564     /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3565     pinfo->dcectxid = ctx_id;
3566
3567     if (check_col (pinfo->cinfo, COL_INFO)) {
3568         col_append_fstr (pinfo->cinfo, COL_INFO,
3569                       " ctx_id: %u status: %s", ctx_id,
3570                       val_to_str(status, reject_status_vals,
3571                                  "Unknown (0x%08x)"));
3572     }
3573
3574     /* padding */
3575     offset += 4;
3576
3577     /*
3578      * XXX - what if this was set when the connection was set up,
3579      * and we just have a security context?
3580      */
3581     dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3582
3583     conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3584                               pinfo->srcport, pinfo->destport, 0);
3585     if (!conv) {
3586         /* no point in creating one here, really */
3587     } else {
3588         dcerpc_matched_key matched_key, *new_matched_key;
3589
3590         /* !!! we can NOT check flags.visited here since this will interact
3591            badly with when SMB handles (i.e. calls the subdissector)
3592            and desegmented pdu's .
3593            Instead we check if this pdu is already in the matched table or not
3594         */
3595         matched_key.frame = pinfo->fd->num;
3596         matched_key.call_id = hdr->call_id;
3597         value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3598         if(!value){
3599                 dcerpc_cn_call_key call_key;
3600                 dcerpc_call_value *call_value;
3601
3602                 call_key.conv=conv;
3603                 call_key.call_id=hdr->call_id;
3604                 call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3605
3606                 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3607                         new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3608                         *new_matched_key = matched_key;
3609                         g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3610                         value = call_value;
3611                         if(call_value->rep_frame==0){
3612                                 call_value->rep_frame=pinfo->fd->num;
3613                         }
3614
3615                 }
3616         }
3617
3618         if (value) {
3619             int length, reported_length, stub_length;
3620             dcerpc_info *di;
3621             proto_item *parent_pi;
3622
3623             di=get_next_di();
3624             /* handoff this call */
3625             di->conv = conv;
3626             di->call_id = hdr->call_id;
3627             di->smb_fid = dcerpc_get_transport_salt(pinfo);
3628             di->ptype = PDU_FAULT;
3629             di->call_data = value;
3630
3631             proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
3632             if(value->req_frame!=0){
3633                 nstime_t ns;
3634                 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3635                                     tvb, 0, 0, value->req_frame);
3636         PROTO_ITEM_SET_GENERATED(pi);
3637         parent_pi = proto_tree_get_parent(dcerpc_tree);
3638         if(parent_pi != NULL) {
3639             proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
3640         }
3641                 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
3642                 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
3643                 if(ns.nsecs<0){
3644                         ns.nsecs+=1000000000;
3645                         ns.secs--;
3646                 }
3647                 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
3648         PROTO_ITEM_SET_GENERATED(pi);
3649             }
3650
3651             length = tvb_length_remaining(tvb, offset);
3652             reported_length = tvb_reported_length_remaining(tvb, offset);
3653             stub_length = hdr->frag_len - offset - auth_info.auth_size;
3654             if (length > stub_length)
3655               length = stub_length;
3656             if (reported_length > stub_length)
3657               reported_length = stub_length;
3658
3659             /* If we don't have reassembly enabled, or this packet contains
3660                the entire PDU, or if we don't have all the data in this
3661                fragment, just call the handoff directly if this is the
3662                first fragment or the PDU isn't fragmented. */
3663             if( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
3664                         !tvb_bytes_exist(tvb, offset, stub_length) ){
3665                 if(hdr->flags&PFC_FIRST_FRAG){
3666                     /* First fragment, possibly the only fragment */
3667                     /*
3668                      * XXX - should there be a third routine for each
3669                      * function in an RPC subdissector, to handle
3670                      * fault responses?  The DCE RPC 1.1 spec says
3671                      * three's "stub data" here, which I infer means
3672                      * that it's protocol-specific and call-specific.
3673                      *
3674                      * It should probably get passed the status code
3675                      * as well, as that might be protocol-specific.
3676                      */
3677                     if (dcerpc_tree) {
3678                         if (stub_length > 0) {
3679                             tvb_ensure_bytes_exist(tvb, offset, stub_length);
3680                             proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3681                                                  "Fault stub data (%d byte%s)",
3682                                                  stub_length,
3683                                                  plurality(stub_length, "", "s"));
3684                         }
3685                     }
3686                 } else {
3687                     /* PDU is fragmented and this isn't the first fragment */
3688                     if (check_col(pinfo->cinfo, COL_INFO)) {
3689                         col_append_fstr(pinfo->cinfo, COL_INFO,
3690                                         " [DCE/RPC fragment]");
3691                     }
3692                     if (dcerpc_tree) {
3693                         if (stub_length > 0) {
3694                             tvb_ensure_bytes_exist(tvb, offset, stub_length);
3695                             proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3696                                                  "Fragment data (%d byte%s)",
3697                                                  stub_length,
3698                                                  plurality(stub_length, "", "s"));
3699                         }
3700                     }
3701                 }
3702             } else {
3703                 /* Reassembly is enabled, the PDU is fragmented, and
3704                    we have all the data in the fragment; the first two
3705                    of those mean we should attempt reassembly, and the
3706                    third means we can attempt reassembly. */
3707                 if (dcerpc_tree) {
3708                     if (length > 0) {
3709                         tvb_ensure_bytes_exist(tvb, offset, stub_length);
3710                         proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3711                                              "Fragment data (%d byte%s)",
3712                                              stub_length,
3713                                              plurality(stub_length, "", "s"));
3714                     }
3715                 }
3716                 if(hdr->flags&PFC_FIRST_FRAG){  /* FIRST fragment */
3717                     if( (!pinfo->fd->flags.visited) && value->rep_frame ){
3718                         fragment_add(tvb, offset, pinfo, value->rep_frame,
3719                              dcerpc_co_reassemble_table,
3720                              0,
3721                              stub_length,
3722                              TRUE);
3723                         fragment_set_tot_len(pinfo, value->rep_frame,
3724                              dcerpc_co_reassemble_table, alloc_hint);
3725                     }
3726                     if (check_col(pinfo->cinfo, COL_INFO)) {
3727                         col_append_fstr(pinfo->cinfo, COL_INFO,
3728                                         " [DCE/RPC fragment]");
3729                     }
3730                 } else if(hdr->flags&PFC_LAST_FRAG){  /* LAST fragment */
3731                     if( value->rep_frame ){
3732                         fragment_data *fd_head;
3733                         guint32 tot_len;
3734
3735                         tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
3736                                        dcerpc_co_reassemble_table);
3737                         fd_head = fragment_add(tvb, offset, pinfo,
3738                              value->rep_frame,
3739                              dcerpc_co_reassemble_table,
3740                              tot_len-alloc_hint,
3741                              stub_length,
3742                              TRUE);
3743
3744                         if(fd_head){
3745                             /* We completed reassembly */
3746                             tvbuff_t *next_tvb;
3747                 proto_item *frag_tree_item;
3748
3749                             next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
3750                             tvb_set_child_real_data_tvbuff(tvb, next_tvb);
3751                             add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3752                             show_fragment_tree(fd_head, &dcerpc_frag_items,
3753                                 dcerpc_tree, pinfo, next_tvb, &frag_tree_item);
3754
3755                             /*
3756                              * XXX - should there be a third routine for each
3757                              * function in an RPC subdissector, to handle
3758                              * fault responses?  The DCE RPC 1.1 spec says
3759                              * three's "stub data" here, which I infer means
3760                              * that it's protocol-specific and call-specific.
3761                              *
3762                              * It should probably get passed the status code
3763                              * as well, as that might be protocol-specific.
3764                              */
3765                             if (dcerpc_tree) {
3766                                 if (length > 0) {
3767                                     tvb_ensure_bytes_exist(tvb, offset, stub_length);
3768                                      proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3769                                                           "Fault stub data (%d byte%s)",
3770                                                           stub_length,
3771                                                           plurality(stub_length, "", "s"));
3772                                 }
3773                             }
3774                         } else {
3775                             /* Reassembly not complete - some fragments
3776                                are missing */
3777                             if (check_col(pinfo->cinfo, COL_INFO)) {
3778                                 col_append_fstr(pinfo->cinfo, COL_INFO,
3779                                                 " [DCE/RPC fragment]");
3780                             }
3781                         }
3782                     }
3783                 } else {  /* MIDDLE fragment(s) */
3784                     if( (!pinfo->fd->flags.visited) && value->rep_frame ){
3785                         guint32 tot_len;
3786                         tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
3787                                        dcerpc_co_reassemble_table);
3788                         fragment_add(tvb, offset, pinfo, value->rep_frame,
3789                              dcerpc_co_reassemble_table,
3790                              tot_len-alloc_hint,
3791                              stub_length,
3792                              TRUE);
3793                     }
3794                     if (check_col(pinfo->cinfo, COL_INFO)) {
3795                         col_append_fstr(pinfo->cinfo, COL_INFO,
3796                                         " [DCE/RPC fragment]");
3797                     }
3798                 }
3799             }
3800         }
3801     }
3802 }
3803
3804 /*
3805  * DCERPC dissector for connection oriented calls.
3806  * We use transport type to later multiplex between what kind of
3807  * pinfo->private_data structure to expect.
3808  */
3809 static gboolean
3810 dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
3811                    proto_tree *tree, gboolean can_desegment, int *pkt_len)
3812 {
3813     static const guint8 nulls[4] = { 0 };
3814     int start_offset;
3815     int padding = 0;
3816     proto_item *ti = NULL;
3817     proto_item *tf = NULL;
3818     proto_tree *dcerpc_tree = NULL;
3819     proto_tree *cn_flags_tree = NULL;
3820     proto_tree *drep_tree = NULL;
3821     e_dce_cn_common_hdr_t hdr;
3822     dcerpc_auth_info auth_info;
3823
3824     /*
3825      * when done over nbt, dcerpc requests are padded with 4 bytes of null
3826      * data for some reason.
3827      *
3828      * XXX - if that's always the case, the right way to do this would
3829      * be to have a "dissect_dcerpc_cn_nb" routine which strips off
3830      * the 4 bytes of null padding, and make that the dissector
3831      * used for "netbios".
3832      */
3833     if (tvb_memeql (tvb, offset, nulls, 4) == 0) {
3834
3835         /*
3836          * Skip the padding.
3837          */
3838         offset += 4;
3839         padding += 4;
3840     }
3841
3842     /*
3843      * Check if this looks like a C/O DCERPC call
3844      */
3845     if (!tvb_bytes_exist (tvb, offset, sizeof (hdr))) {
3846         return FALSE;   /* not enough information to check */
3847     }
3848     start_offset = offset;
3849     hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
3850     if (hdr.rpc_ver != 5)
3851         return FALSE;
3852     hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
3853     if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
3854         return FALSE;
3855     hdr.ptype = tvb_get_guint8 (tvb, offset++);
3856     if (hdr.ptype > 19)
3857         return FALSE;
3858
3859     hdr.flags = tvb_get_guint8 (tvb, offset++);
3860     tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
3861     offset += sizeof (hdr.drep);
3862
3863     hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3864     offset += 2;
3865     hdr.auth_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3866     offset += 2;
3867     hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3868     offset += 4;
3869
3870     if (check_col (pinfo->cinfo, COL_DCE_CALL)) {
3871         col_append_fstr (pinfo->cinfo, COL_DCE_CALL, "%u", hdr.call_id);
3872     }
3873
3874     if (can_desegment && pinfo->can_desegment
3875         && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
3876         pinfo->desegment_offset = start_offset;
3877         pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, start_offset);
3878         *pkt_len = 0;   /* desegmentation required */
3879         return TRUE;
3880     }
3881
3882     if (check_col (pinfo->cinfo, COL_PROTOCOL))
3883         col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
3884
3885     if (check_col (pinfo->cinfo, COL_INFO)) {
3886         if(pinfo->dcectxid != 0) {
3887             /* this is not the first DCE-RPC request/response in this (TCP?-)PDU, 
3888              * append a delimiter and set a column fence */
3889             col_append_str (pinfo->cinfo, COL_INFO, " # ");
3890             col_set_fence(pinfo->cinfo,COL_INFO);
3891         }
3892         col_add_fstr (pinfo->cinfo, COL_INFO, "%s: call_id: %u",
3893                 pckt_vals[hdr.ptype].strptr, hdr.call_id);
3894     }
3895
3896     if (tree) {
3897         offset = start_offset;
3898         tvb_ensure_bytes_exist(tvb, offset, hdr.frag_len);
3899         ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE);
3900         if (ti) {
3901             dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
3902         }
3903         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver);
3904         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset++, 1, hdr.rpc_ver_minor);
3905         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype);
3906                 proto_item_append_text(ti, " %s, Fragment:", val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"));
3907
3908         tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
3909         cn_flags_tree = proto_item_add_subtree (tf, ett_dcerpc_cn_flags);
3910         if (cn_flags_tree) {
3911             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
3912             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
3913             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
3914             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
3915             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
3916             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
3917             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
3918             proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
3919             if( (hdr.flags & PFC_FIRST_FRAG) && (hdr.flags & PFC_LAST_FRAG) ) {
3920                             proto_item_append_text(ti, " Single");
3921             } else {
3922                 if(hdr.flags & PFC_FIRST_FRAG) {
3923                             proto_item_append_text(ti, " 1st");
3924                 }
3925                 if(hdr.flags & PFC_LAST_FRAG) {
3926                             proto_item_append_text(ti, " Last");
3927                 }
3928                 if( !(hdr.flags & PFC_FIRST_FRAG) && !(hdr.flags & PFC_LAST_FRAG) ) {
3929                             proto_item_append_text(ti, " Mid");
3930                 }
3931             }
3932         }
3933         offset++;
3934
3935         tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
3936         drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
3937         if (drep_tree) {
3938             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
3939             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
3940             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
3941         }
3942         offset += sizeof (hdr.drep);
3943
3944         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
3945         offset += 2;
3946
3947         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
3948         offset += 2;
3949
3950         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
3951         offset += 4;
3952
3953                 proto_item_append_text(ti, ", FragLen: %u, Call: %u", hdr.frag_len, hdr.call_id);
3954     }
3955
3956     /*
3957      * None of the stuff done above should throw an exception, because
3958      * we would have rejected this as "not DCE RPC" if we didn't have all
3959      * of it.  (XXX - perhaps we should request reassembly if we have
3960      * enough of the header to consider it DCE RPC but not enough to
3961      * get the fragment length; in that case the stuff still wouldn't
3962      * throw an exception.)
3963      *
3964      * The rest of the stuff might, so return the PDU length to our caller.
3965      * XXX - should we construct a tvbuff containing only the PDU and
3966      * use that?  Or should we have separate "is this a DCE RPC PDU",
3967      * "how long is it", and "dissect it" routines - which might let us
3968      * do most of the work in "tcp_dissect_pdus()"?
3969      */
3970     if (pkt_len != NULL)
3971         *pkt_len = hdr.frag_len + padding;
3972
3973     /*
3974      * Packet type specific stuff is next.
3975      */
3976     switch (hdr.ptype) {
3977     case PDU_BIND:
3978     case PDU_ALTER:
3979         dissect_dcerpc_cn_bind (tvb, offset, pinfo, dcerpc_tree, &hdr);
3980         break;
3981
3982     case PDU_BIND_ACK:
3983     case PDU_ALTER_ACK:
3984         dissect_dcerpc_cn_bind_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3985         break;
3986
3987     case PDU_AUTH3:
3988         /*
3989          * Nothing after the common header other than credentials.
3990          */
3991         dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, TRUE, 
3992                                 &auth_info);
3993         break;
3994
3995     case PDU_REQ:
3996         dissect_dcerpc_cn_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
3997         break;
3998
3999     case PDU_RESP:
4000         dissect_dcerpc_cn_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
4001         break;
4002
4003     case PDU_FAULT:
4004         dissect_dcerpc_cn_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
4005         break;
4006
4007     case PDU_BIND_NAK:
4008         dissect_dcerpc_cn_bind_nak (tvb, offset, pinfo, dcerpc_tree, &hdr);
4009         break;
4010
4011     case PDU_CO_CANCEL:
4012     case PDU_ORPHANED:
4013         /*
4014          * Nothing after the common header other than an authentication
4015          * verifier.
4016          */
4017         dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE, 
4018                                 &auth_info);
4019         break;
4020
4021     case PDU_SHUTDOWN:
4022         /*
4023          * Nothing after the common header, not even an authentication
4024          * verifier.
4025          */
4026         break;
4027
4028     default:
4029         /* might as well dissect the auth info */
4030         dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE, 
4031                                 &auth_info);
4032         break;
4033     }
4034     return TRUE;
4035 }
4036
4037 /*
4038  * DCERPC dissector for connection oriented calls over packet-oriented
4039  * transports
4040  */
4041 static gboolean
4042 dissect_dcerpc_cn_pk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4043 {
4044     /*
4045      * Only one PDU per transport packet, and only one transport
4046      * packet per PDU.
4047      */
4048     pinfo->dcetransporttype=DCE_TRANSPORT_UNKNOWN;
4049     if (!dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE, NULL)) {
4050         /*
4051          * It wasn't a DCERPC PDU.
4052          */
4053         return FALSE;
4054     } else {
4055         /*
4056          * It was.
4057          */
4058         return TRUE;
4059     }
4060 }
4061
4062 /*
4063  * DCERPC dissector for connection oriented calls over byte-stream
4064  * transports.
4065  * we need to distinguish here between SMB and non-TCP (more in the future?)
4066  * to be able to know what kind of private_data structure to expect.
4067  */
4068 static gboolean
4069 dissect_dcerpc_cn_bs_body (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4070 {
4071     volatile int offset = 0;
4072     int pdu_len;
4073     volatile gboolean dcerpc_pdus = 0;
4074     volatile gboolean ret = FALSE;
4075
4076     /*
4077      * There may be multiple PDUs per transport packet; keep
4078      * processing them.
4079      */
4080     while (tvb_reported_length_remaining(tvb, offset) != 0) {
4081         /*
4082          * Catch ReportedBoundsError, so that even if the stub data is bad,
4083          * we don't abort the full DCE RPC dissection - there might be more
4084          * than one DCE RPC PDU in the data being dissected.
4085          *
4086          * If we get BoundsError, it means the frame was cut short by a
4087          * snapshot length, so there's nothing more to dissect; just
4088          * re-throw that exception.
4089          */
4090         TRY {
4091             pdu_len = 0;
4092             if(dissect_dcerpc_cn (tvb, offset, pinfo, tree,
4093                 dcerpc_cn_desegment, &pdu_len)) {
4094                 dcerpc_pdus++;
4095             }
4096         } CATCH(BoundsError) {
4097             RETHROW;
4098         } CATCH(ReportedBoundsError) {
4099             show_reported_bounds_error(tvb, pinfo, tree);
4100         } ENDTRY;
4101
4102         if (!dcerpc_pdus) {
4103             /*
4104              * Not a DCERPC PDU.
4105              */
4106             break;
4107         }
4108
4109         /*
4110          * Well, we've seen at least one DCERPC PDU.
4111          */
4112         ret = TRUE;
4113
4114         /* if we had more than one Req/Resp in this PDU change the protocol column */
4115         /* this will formerly contain the last interface name, which may not be the same for all Req/Resp */
4116         if (dcerpc_pdus >= 2 && check_col (pinfo->cinfo, COL_PROTOCOL))
4117             col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "%u*DCERPC", dcerpc_pdus);
4118
4119         if (pdu_len == 0) {
4120             /*
4121              * Desegmentation required - bail now, but give the user a hint that desegmentation might be done later.
4122              */
4123             proto_tree_add_uint_format(tree, hf_dcerpc_cn_deseg_req, tvb, offset, 
4124                 tvb_reported_length_remaining(tvb, offset), 
4125                 tvb_reported_length_remaining(tvb, offset), 
4126                 "[DCE RPC: %u byte%s left, desegmentation might follow]", 
4127                 tvb_reported_length_remaining(tvb, offset), 
4128                 plurality(tvb_reported_length_remaining(tvb, offset), "", "s"));
4129             break;
4130         }
4131
4132         /*
4133          * Step to the next PDU.
4134          */
4135         offset += pdu_len;
4136     }
4137     return ret;
4138 }
4139
4140 static gboolean
4141 dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4142 {
4143         pinfo->dcetransporttype=DCE_TRANSPORT_UNKNOWN;
4144         return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
4145 }
4146
4147 static gboolean
4148 dissect_dcerpc_cn_smbpipe (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4149 {
4150         pinfo->dcetransporttype=DCE_CN_TRANSPORT_SMBPIPE;
4151         return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
4152 }
4153
4154
4155
4156 static void
4157 dissect_dcerpc_dg_auth (tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
4158                         e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
4159 {
4160     proto_item *ti = NULL;
4161     proto_tree *auth_tree = NULL;
4162     guint8 protection_level;
4163
4164     /*
4165      * Initially set "*auth_level_p" to -1 to indicate that we haven't
4166      * yet seen any authentication level information.
4167      */
4168     if (auth_level_p != NULL)
4169         *auth_level_p = -1;
4170
4171     /*
4172      * The authentication information is at the *end* of the PDU; in
4173      * request and response PDUs, the request and response stub data
4174      * come before it.
4175      *
4176      * If the full packet is here, and there's data past the end of the
4177      * packet body, then dissect the auth info.
4178      */
4179     offset += hdr->frag_len;
4180     if (tvb_length_remaining(tvb, offset) > 0) {
4181         switch (hdr->auth_proto) {
4182
4183         case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
4184             ti = proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Kerberos authentication verifier");
4185             auth_tree = proto_item_add_subtree (ti, ett_dcerpc_krb5_auth_verf);
4186             protection_level = tvb_get_guint8 (tvb, offset);
4187             if (auth_level_p != NULL)
4188                 *auth_level_p = protection_level;
4189             proto_tree_add_uint (auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
4190             offset++;
4191             proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, FALSE);
4192             offset++;
4193             if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
4194                 offset += 6;    /* 6 bytes of padding */
4195             else
4196                 offset += 2;    /* 6 bytes of padding */
4197             proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, FALSE);
4198             offset += 16;
4199             break;
4200
4201         default:
4202             proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Authentication verifier");
4203             break;
4204         }
4205     }
4206 }
4207
4208 static void
4209 dissect_dcerpc_dg_cancel_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
4210                               proto_tree *dcerpc_tree,
4211                               e_dce_dg_common_hdr_t *hdr)
4212 {
4213     guint32 version;
4214
4215     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4216                                     hdr->drep, hf_dcerpc_dg_cancel_vers,
4217                                     &version);
4218
4219     switch (version) {
4220
4221     case 0:
4222         /* The only version we know about */
4223         offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4224                                         hdr->drep, hf_dcerpc_dg_cancel_id,
4225                                         NULL);
4226         offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
4227                                        hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
4228                                        NULL);
4229         break;
4230     }
4231 }
4232
4233 static void
4234 dissect_dcerpc_dg_cancel (tvbuff_t *tvb, int offset, packet_info *pinfo,
4235                           proto_tree *dcerpc_tree,
4236                           e_dce_dg_common_hdr_t *hdr)
4237 {
4238     guint32 version;
4239
4240     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4241                                     hdr->drep, hf_dcerpc_dg_cancel_vers,
4242                                     &version);
4243
4244     switch (version) {
4245
4246     case 0:
4247         /* The only version we know about */
4248         offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4249                                         hdr->drep, hf_dcerpc_dg_cancel_id,
4250                                         NULL);
4251         /* XXX - are NDR booleans 32 bits? */
4252
4253         /* XXX - the RPC reference in chapter: "the cancel PDU" doesn't mention
4254            the accepting_cancels field (it's only in the cancel_ack PDU)! */
4255         /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4256                                         hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
4257                                         NULL);*/
4258         break;
4259     }
4260 }
4261
4262 static void
4263 dissect_dcerpc_dg_fack (tvbuff_t *tvb, int offset, packet_info *pinfo,
4264                         proto_tree *dcerpc_tree,
4265                         e_dce_dg_common_hdr_t *hdr)
4266 {
4267     guint8 version;
4268     guint16 serial_num;
4269     guint16 selack_len;
4270     guint i;
4271
4272     offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
4273                                   hdr->drep, hf_dcerpc_dg_fack_vers,
4274                                   &version);
4275     /* padding */
4276     offset++;
4277
4278     switch (version) {
4279
4280     case 0:     /* The only version documented in the DCE RPC 1.1 spec */
4281     case 1:     /* This appears to be the same */
4282         offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
4283                                         hdr->drep, hf_dcerpc_dg_fack_window_size,
4284                                         NULL);
4285         offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4286                                         hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
4287                                         NULL);
4288         offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4289                                         hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
4290                                         NULL);
4291         offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
4292                                         hdr->drep, hf_dcerpc_dg_fack_serial_num,
4293                                         &serial_num);
4294         if (check_col (pinfo->cinfo, COL_INFO)) {
4295             col_append_fstr (pinfo->cinfo, COL_INFO, " serial: %u",
4296                              serial_num);
4297         }
4298         offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
4299                                         hdr->drep, hf_dcerpc_dg_fack_selack_len,
4300                                         &selack_len);
4301         for (i = 0; i < selack_len; i++) {
4302             offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4303                                             hdr->drep, hf_dcerpc_dg_fack_selack,
4304                                             NULL);
4305         }
4306
4307         break;
4308     }
4309 }
4310
4311 static void
4312 dissect_dcerpc_dg_reject_fault (tvbuff_t *tvb, int offset, packet_info *pinfo,
4313                         proto_tree *dcerpc_tree,
4314                         e_dce_dg_common_hdr_t *hdr)
4315 {
4316     guint32 status;
4317
4318     offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4319                                     hdr->drep, hf_dcerpc_dg_status,
4320                                     &status);
4321
4322     if (check_col (pinfo->cinfo, COL_INFO)) {
4323         col_append_fstr (pinfo->cinfo, COL_INFO,
4324                       ": status: %s",
4325                       val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
4326     }
4327 }
4328
4329 static void
4330 dissect_dcerpc_dg_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
4331                         proto_tree *dcerpc_tree, proto_tree *tree,
4332                         e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
4333 {
4334     int length, reported_length, stub_length;
4335     gboolean save_fragmented;
4336     fragment_data *fd_head;
4337     tvbuff_t *next_tvb;
4338     proto_item *pi;
4339     proto_item *parent_pi;
4340
4341     if (check_col (pinfo->cinfo, COL_INFO))
4342         col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u len: %u", 
4343             di->call_data->opnum, hdr->frag_len );
4344
4345     length = tvb_length_remaining (tvb, offset);
4346     reported_length = tvb_reported_length_remaining (tvb, offset);
4347     stub_length = hdr->frag_len;
4348     if (length > stub_length)
4349         length = stub_length;
4350     if (reported_length > stub_length)
4351         reported_length = stub_length;
4352
4353     save_fragmented = pinfo->fragmented;
4354
4355     /* If we don't have reassembly enabled, or this packet contains
4356        the entire PDU, or if this is a short frame (or a frame
4357        not reassembled at a lower layer) that doesn't include all
4358        the data in the fragment, just call the handoff directly if
4359        this is the first fragment or the PDU isn't fragmented. */
4360     if( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
4361                 !tvb_bytes_exist(tvb, offset, stub_length) ){
4362         if(hdr->frag_num == 0) {
4363
4364
4365             /* First fragment, possibly the only fragment */
4366
4367             /*
4368              * XXX - authentication info?
4369              */
4370             pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
4371             next_tvb = tvb_new_subset (tvb, offset, length,
4372                                        reported_length);
4373             dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
4374                                 next_tvb, hdr->drep, di, NULL);
4375         } else {
4376             /* PDU is fragmented and this isn't the first fragment */
4377             if (check_col(pinfo->cinfo, COL_INFO)) {
4378                 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
4379             }
4380             if (dcerpc_tree) {
4381                 if (length > 0) {
4382                     tvb_ensure_bytes_exist(tvb, offset, stub_length);
4383                     proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
4384                                          "Fragment data (%d byte%s)",
4385                                          stub_length,
4386                                          plurality(stub_length, "", "s"));
4387                 }
4388             }
4389         }
4390     } else {
4391         /* Reassembly is enabled, the PDU is fragmented, and
4392            we have all the data in the fragment; the first two
4393            of those mean we should attempt reassembly, and the
4394            third means we can attempt reassembly. */
4395         if (dcerpc_tree) {
4396             if (length > 0) {
4397                 tvb_ensure_bytes_exist(tvb, offset, stub_length);
4398                 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
4399                                      "Fragment data (%d byte%s)", stub_length,
4400                                      plurality(stub_length, "", "s"));
4401             }
4402         }
4403
4404         fd_head = fragment_add_dcerpc(tvb, offset, pinfo,
4405                         hdr->seqnum, &hdr->act_id, dcerpc_cl_reassemble_table,
4406                         hdr->frag_num, stub_length,
4407                         !(hdr->flags1 & PFCL1_LASTFRAG));
4408     if (fd_head != NULL) {
4409             /* We completed reassembly... */
4410         if(pinfo->fd->num==fd_head->reassembled_in) {
4411             /* ...and this is the reassembled RPC PDU */
4412                 next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
4413                 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
4414                 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
4415                 show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
4416                                            tree, pinfo, next_tvb, &pi);
4417
4418                 /*
4419                  * XXX - authentication info?
4420                  */
4421                 pinfo->fragmented = FALSE;
4422                 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
4423                                         next_tvb, hdr->drep, di, NULL);
4424                 } else {
4425             /* ...and this isn't the reassembled RPC PDU */
4426                 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
4427                                     tvb, 0, 0, fd_head->reassembled_in);
4428             PROTO_ITEM_SET_GENERATED(pi);
4429             parent_pi = proto_tree_get_parent(dcerpc_tree);
4430             if(parent_pi != NULL) {
4431                 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
4432             }
4433                 if (check_col(pinfo->cinfo, COL_INFO)) {
4434                     col_append_fstr(pinfo->cinfo, COL_INFO,
4435                             " [DCE/RPC fragment, reas: #%u]", fd_head->reassembled_in);
4436                 }
4437         }
4438         } else {
4439             /* Reassembly isn't completed yet */
4440             if (check_col(pinfo->cinfo, COL_INFO)) {
4441                 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
4442             }
4443         }
4444     }
4445     pinfo->fragmented = save_fragmented;
4446 }
4447
4448 static void
4449 dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo,
4450                         proto_tree *dcerpc_tree, proto_tree *tree,
4451                         e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4452 {
4453     dcerpc_info *di;
4454     dcerpc_call_value *value, v;
4455     dcerpc_matched_key matched_key, *new_matched_key;
4456     proto_item *pi;
4457     proto_item *parent_pi;
4458
4459     di=get_next_di();
4460     if(!(pinfo->fd->flags.visited)){
4461         dcerpc_call_value *call_value;
4462         dcerpc_dg_call_key *call_key;
4463
4464         call_key=g_mem_chunk_alloc (dcerpc_dg_call_key_chunk);
4465         call_key->conv=conv;
4466         call_key->seqnum=hdr->seqnum;
4467         call_key->act_id=hdr->act_id;
4468
4469         call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
4470         call_value->uuid = hdr->if_id;
4471         call_value->ver = hdr->if_ver;
4472         call_value->opnum = hdr->opnum;
4473         call_value->req_frame=pinfo->fd->num;
4474         call_value->req_time.secs=pinfo->fd->abs_secs;
4475         call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000;
4476         call_value->rep_frame=0;
4477         call_value->max_ptr=0;
4478         call_value->private_data = NULL;
4479         g_hash_table_insert (dcerpc_dg_calls, call_key, call_value);
4480
4481         new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
4482         new_matched_key->frame = pinfo->fd->num;
4483         new_matched_key->call_id = hdr->seqnum;
4484         g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
4485     }
4486
4487     matched_key.frame = pinfo->fd->num;
4488     matched_key.call_id = hdr->seqnum;
4489     value=g_hash_table_lookup(dcerpc_matched, &matched_key);
4490     if (!value) {
4491         v.uuid = hdr->if_id;
4492         v.ver = hdr->if_ver;
4493         v.opnum = hdr->opnum;
4494         v.req_frame = pinfo->fd->num;
4495         v.rep_frame = 0;
4496         v.max_ptr = 0;
4497         v.private_data=NULL;
4498         value = &v;
4499     }
4500
4501     di->conv = conv;
4502     di->call_id = hdr->seqnum;
4503     di->smb_fid = -1;
4504     di->ptype = PDU_REQ;
4505     di->call_data = value;
4506
4507     if(value->rep_frame!=0){
4508         pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
4509                             tvb, 0, 0, value->rep_frame);
4510     PROTO_ITEM_SET_GENERATED(pi);
4511     parent_pi = proto_tree_get_parent(dcerpc_tree);
4512     if(parent_pi != NULL) {
4513         proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
4514     }
4515     }
4516     dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
4517 }
4518
4519 static void
4520 dissect_dcerpc_dg_resp (tvbuff_t *tvb, int offset, packet_info *pinfo,
4521                         proto_tree *dcerpc_tree, proto_tree *tree,
4522                         e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4523 {
4524     dcerpc_info *di;
4525     dcerpc_call_value *value, v;
4526     dcerpc_matched_key matched_key, *new_matched_key;
4527     proto_item *pi;
4528     proto_item *parent_pi;
4529
4530     di=get_next_di();
4531     if(!(pinfo->fd->flags.visited)){
4532         dcerpc_call_value *call_value;
4533         dcerpc_dg_call_key call_key;
4534
4535         call_key.conv=conv;
4536         call_key.seqnum=hdr->seqnum;
4537         call_key.act_id=hdr->act_id;
4538
4539         if((call_value=g_hash_table_lookup(dcerpc_dg_calls, &call_key))){
4540             new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
4541             new_matched_key->frame = pinfo->fd->num;
4542             new_matched_key->call_id = hdr->seqnum;
4543             g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
4544             if(call_value->rep_frame==0){
4545                 call_value->rep_frame=pinfo->fd->num;
4546             }
4547         }
4548     }
4549
4550     matched_key.frame = pinfo->fd->num;
4551     matched_key.call_id = hdr->seqnum;
4552     value=g_hash_table_lookup(dcerpc_matched, &matched_key);
4553     if (!value) {
4554         v.uuid = hdr->if_id;
4555         v.ver = hdr->if_ver;
4556         v.opnum = hdr->opnum;
4557         v.req_frame=0;
4558         v.rep_frame=pinfo->fd->num;
4559         v.private_data=NULL;
4560         value = &v;
4561     }
4562
4563     di->conv = conv;
4564     di->call_id = 0;
4565     di->smb_fid = -1;
4566     di->ptype = PDU_RESP;
4567     di->call_data = value;
4568
4569     if(value->req_frame!=0){
4570         nstime_t ns;
4571         pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4572                             tvb, 0, 0, value->req_frame);
4573     PROTO_ITEM_SET_GENERATED(pi);
4574     parent_pi = proto_tree_get_parent(dcerpc_tree);
4575     if(parent_pi != NULL) {
4576         proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
4577     }
4578         ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
4579         ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
4580         if(ns.nsecs<0){
4581                 ns.nsecs+=1000000000;
4582                 ns.secs--;
4583         }
4584         pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
4585     PROTO_ITEM_SET_GENERATED(pi);
4586     }
4587     dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
4588 }
4589
4590 static void
4591 dissect_dcerpc_dg_ping_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
4592                         proto_tree *dcerpc_tree, proto_tree *tree,
4593                         e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4594 {
4595     proto_item *parent_pi;
4596 /*    if(!(pinfo->fd->flags.visited)){*/
4597         dcerpc_call_value *call_value;
4598         dcerpc_dg_call_key call_key;
4599
4600         call_key.conv=conv;
4601         call_key.seqnum=hdr->seqnum;
4602         call_key.act_id=hdr->act_id;
4603
4604         if((call_value=g_hash_table_lookup(dcerpc_dg_calls, &call_key))){
4605         proto_item *pi;
4606                 nstime_t ns;
4607
4608                 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4609                                     tvb, 0, 0, call_value->req_frame);
4610         PROTO_ITEM_SET_GENERATED(pi);
4611         parent_pi = proto_tree_get_parent(dcerpc_tree);
4612         if(parent_pi != NULL) {
4613             proto_item_append_text(parent_pi, ", [Req: #%u]", call_value->req_frame);
4614         }
4615
4616         if (check_col (pinfo->cinfo, COL_INFO))
4617             col_append_fstr(pinfo->cinfo, COL_INFO, " [req: #%u]", call_value->req_frame);
4618
4619                 ns.secs= pinfo->fd->abs_secs-call_value->req_time.secs;
4620                 ns.nsecs=pinfo->fd->abs_usecs*1000-call_value->req_time.nsecs;
4621                 if(ns.nsecs<0){
4622                         ns.nsecs+=1000000000;
4623                         ns.secs--;
4624                 }
4625                 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
4626         PROTO_ITEM_SET_GENERATED(pi);
4627 /*    }*/
4628     }
4629 }
4630
4631 /*
4632  * DCERPC dissector for connectionless calls
4633  */
4634 static gboolean
4635 dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4636 {
4637     proto_item *ti = NULL;
4638     proto_item *tf = NULL;
4639     proto_tree *dcerpc_tree = NULL;
4640     proto_tree *dg_flags1_tree = NULL;
4641     proto_tree *dg_flags2_tree = NULL;
4642     proto_tree *drep_tree = NULL;
4643     e_dce_dg_common_hdr_t hdr;
4644     int offset = 0;
4645     conversation_t *conv;
4646     int auth_level;
4647     char uuid_str[DCERPC_UUID_STR_LEN]; 
4648     int uuid_str_len;
4649
4650     /*
4651      * Check if this looks like a CL DCERPC call.  All dg packets
4652      * have an 80 byte header on them.  Which starts with
4653      * version (4), pkt_type.
4654      */
4655     if (!tvb_bytes_exist (tvb, 0, sizeof (hdr))) {
4656         return FALSE;
4657     }
4658
4659     /* Version must be 4 */
4660     hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
4661     if (hdr.rpc_ver != 4)
4662         return FALSE;
4663
4664     /* Type must be <=19 or its not DCE/RPC */
4665     hdr.ptype = tvb_get_guint8 (tvb, offset++);
4666     if (hdr.ptype > 19)
4667         return FALSE;
4668
4669     /* flags1 has bit 1 and 8 as reserved so if any of them are set, it is 
4670        probably not a DCE/RPC packet 
4671      */
4672     hdr.flags1 = tvb_get_guint8 (tvb, offset++);
4673     if(hdr.flags1&0x81)
4674         return FALSE;
4675
4676     /* flags2 has all bits except bit 2 as reserved so if any of them are set
4677        it is probably not DCE/RPC.
4678      */
4679     hdr.flags2 = tvb_get_guint8 (tvb, offset++);
4680     if(hdr.flags2&0xfd)
4681         return FALSE;
4682
4683
4684     if (check_col (pinfo->cinfo, COL_PROTOCOL))
4685         col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
4686     if (check_col (pinfo->cinfo, COL_INFO))
4687         col_add_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
4688
4689     tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
4690     offset += sizeof (hdr.drep);
4691     hdr.serial_hi = tvb_get_guint8 (tvb, offset++);
4692     dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.obj_id);
4693     offset += 16;
4694     dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.if_id);
4695     offset += 16;
4696     dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.act_id);
4697     offset += 16;
4698     hdr.server_boot = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4699     offset += 4;
4700     hdr.if_ver = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4701     offset += 4;
4702     hdr.seqnum = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4703     offset += 4;
4704     hdr.opnum = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4705     offset += 2;
4706     hdr.ihint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4707     offset += 2;
4708     hdr.ahint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4709     offset += 2;
4710     hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4711     offset += 2;
4712     hdr.frag_num = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4713     offset += 2;
4714     hdr.auth_proto = tvb_get_guint8 (tvb, offset++);
4715     hdr.serial_lo = tvb_get_guint8 (tvb, offset++);
4716
4717     if (tree) {
4718         ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, -1, FALSE);
4719         if (ti) {
4720             dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
4721                     proto_item_append_text(ti, " %s, Seq: %u, Serial: %u, Frag: %u, FragLen: %u", 
4722                 val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"),
4723                 hdr.seqnum, hdr.serial_hi*256+hdr.serial_lo,
4724                 hdr.frag_num, hdr.frag_len);
4725         }
4726     }
4727     offset = 0;
4728
4729     if (tree)
4730         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
4731     offset++;
4732
4733     if (tree)
4734         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
4735     offset++;
4736
4737     if (tree) {
4738         tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
4739         dg_flags1_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags1);
4740         if (dg_flags1_tree) {
4741             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
4742             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
4743             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
4744             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
4745             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
4746             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
4747             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
4748             proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
4749             if(hdr.flags1) {
4750                         proto_item_append_text(tf, " %s%s%s%s%s%s", 
4751                     (hdr.flags1 & PFCL1_BROADCAST) ? "\"Broadcast\" " : "",
4752                     (hdr.flags1 & PFCL1_IDEMPOTENT) ? "\"Idempotent\" " : "",
4753                     (hdr.flags1 & PFCL1_MAYBE) ? "\"Maybe\" " : "",
4754                     (hdr.flags1 & PFCL1_NOFACK) ? "\"No Fack\" " : "",
4755                     (hdr.flags1 & PFCL1_FRAG) ? "\"Fragment\" " : "",
4756                     (hdr.flags1 & PFCL1_LASTFRAG) ? "\"Last Fragment\" " : "");
4757             }
4758         }
4759     }
4760     offset++;
4761
4762     if (tree) {
4763         tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
4764         dg_flags2_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags2);
4765         if (dg_flags2_tree) {
4766             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
4767             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
4768             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
4769             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
4770             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
4771             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
4772             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
4773             proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
4774             if(hdr.flags2) {
4775                         proto_item_append_text(tf, " %s", 
4776                     (hdr.flags2 & PFCL2_CANCEL_PENDING) ? "\"Cancel Pending\" " : "");
4777             }
4778         }
4779     }
4780     offset++;
4781
4782     if (tree) {
4783         tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
4784         drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
4785         if (drep_tree) {
4786             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
4787             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
4788             proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
4789                     proto_item_append_text(tf, " (Order: %s, Char: %s, Float: %s)", 
4790                 val_to_str(hdr.drep[0] >> 4, drep_byteorder_vals, "Unknown"),
4791                 val_to_str(hdr.drep[0] & 0x0f, drep_character_vals, "Unknown"),
4792                 val_to_str(hdr.drep[1], drep_fp_vals, "Unknown"));
4793         }
4794     }
4795     offset += sizeof (hdr.drep);
4796
4797     if (tree)
4798         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
4799     offset++;
4800
4801     if (tree) {
4802         /* XXX - use "dissect_ndr_uuid_t()"? */
4803         uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, 
4804                                 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
4805                                 hdr.obj_id.Data1, hdr.obj_id.Data2, hdr.obj_id.Data3,
4806                                 hdr.obj_id.Data4[0],
4807                                 hdr.obj_id.Data4[1],
4808                                 hdr.obj_id.Data4[2],
4809                                 hdr.obj_id.Data4[3],
4810                                 hdr.obj_id.Data4[4],
4811                                 hdr.obj_id.Data4[5],
4812                                 hdr.obj_id.Data4[6],
4813                                 hdr.obj_id.Data4[7]);
4814         if (uuid_str_len >= DCERPC_UUID_STR_LEN)
4815                 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
4816         proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
4817                                       offset, 16, uuid_str, "Object UUID: %s", uuid_str);
4818     }
4819     offset += 16;
4820
4821     if (tree) {
4822         /* XXX - use "dissect_ndr_uuid_t()"? */
4823         uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, 
4824                                 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
4825                                 hdr.if_id.Data1, hdr.if_id.Data2, hdr.if_id.Data3,
4826                                 hdr.if_id.Data4[0],
4827                                 hdr.if_id.Data4[1],
4828                                 hdr.if_id.Data4[2],
4829                                 hdr.if_id.Data4[3],
4830                                 hdr.if_id.Data4[4],
4831                                 hdr.if_id.Data4[5],
4832                                 hdr.if_id.Data4[6],
4833                                 hdr.if_id.Data4[7]);
4834         if (uuid_str_len >= DCERPC_UUID_STR_LEN)
4835                 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
4836         proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
4837                                       offset, 16, uuid_str, "Interface: %s", uuid_str);
4838     }
4839     offset += 16;
4840
4841     if (tree) {
4842         /* XXX - use "dissect_ndr_uuid_t()"? */
4843         uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, 
4844                                 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
4845                                 hdr.act_id.Data1, hdr.act_id.Data2, hdr.act_id.Data3,
4846                                 hdr.act_id.Data4[0],
4847                                 hdr.act_id.Data4[1],
4848                                 hdr.act_id.Data4[2],
4849                                 hdr.act_id.Data4[3],
4850                                 hdr.act_id.Data4[4],
4851                                 hdr.act_id.Data4[5],
4852                                 hdr.act_id.Data4[6],
4853                                 hdr.act_id.Data4[7]);
4854         if (uuid_str_len >= DCERPC_UUID_STR_LEN)
4855                 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
4856         proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
4857                                       offset, 16, uuid_str, "Activity: %s", uuid_str);
4858     }
4859     offset += 16;
4860
4861     if (tree) {
4862         nstime_t server_boot;
4863
4864         server_boot.secs  = hdr.server_boot;
4865         server_boot.nsecs = 0;
4866
4867         if (hdr.server_boot == 0)
4868             proto_tree_add_time_format (dcerpc_tree, hf_dcerpc_dg_server_boot,
4869                                         tvb, offset, 4, &server_boot,
4870                                         "Server boot time: Unknown (0)");
4871         else
4872             proto_tree_add_time (dcerpc_tree, hf_dcerpc_dg_server_boot,
4873                                  tvb, offset, 4, &server_boot);
4874     }
4875     offset += 4;
4876
4877     if (tree)
4878         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
4879     offset += 4;
4880
4881     if (tree)
4882         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
4883     if (check_col (pinfo->cinfo, COL_INFO)) {
4884         col_append_fstr (pinfo->cinfo, COL_INFO, ": seq: %u", hdr.seqnum);
4885     }
4886     if (check_col (pinfo->cinfo, COL_DCE_CALL)) {
4887         col_append_fstr (pinfo->cinfo, COL_DCE_CALL, "%u", hdr.seqnum);
4888     }
4889     offset += 4;
4890
4891     if (tree)
4892         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
4893     offset += 2;
4894
4895     if (tree)
4896         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
4897     offset += 2;
4898
4899     if (tree)
4900         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
4901     offset += 2;
4902
4903     if (tree)
4904         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
4905     offset += 2;
4906
4907     if (tree)
4908         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
4909     if (check_col (pinfo->cinfo, COL_INFO)) {
4910         if (hdr.flags1 & PFCL1_FRAG) {
4911             /* Fragmented - put the fragment number into the Info column */
4912             col_append_fstr (pinfo->cinfo, COL_INFO, " frag: %u",
4913                              hdr.frag_num);
4914         }
4915     }
4916     offset += 2;
4917
4918     if (tree)
4919         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
4920     offset++;
4921
4922     if (tree)
4923         proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
4924     if (check_col (pinfo->cinfo, COL_INFO)) {
4925         if (hdr.flags1 & PFCL1_FRAG) {
4926             /* Fragmented - put the serial number into the Info column */
4927             col_append_fstr (pinfo->cinfo, COL_INFO, " serial: %u",
4928                              (hdr.serial_hi << 8) | hdr.serial_lo);
4929         }
4930     }
4931     offset++;
4932
4933     if (tree) {
4934         /*
4935          * XXX - for Kerberos, we get a protection level; if it's
4936          * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
4937          * stub data.
4938          */
4939         dissect_dcerpc_dg_auth (tvb, offset, dcerpc_tree, &hdr,
4940                                 &auth_level);
4941     }
4942
4943     /*
4944      * keeping track of the conversation shouldn't really be necessary
4945      * for connectionless packets, because everything we need to know
4946      * to dissect is in the header for each packet.  Unfortunately,
4947      * Microsoft's implementation is buggy and often puts the
4948      * completely wrong if_id in the header.  go figure.  So, keep
4949      * track of the seqnum and use that if possible.  Note: that's not
4950      * completely correct.  It should really be done based on both the
4951      * activity_id and seqnum.  I haven't seen anywhere that it would
4952      * make a difference, but for future reference...
4953      */
4954     conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
4955                               pinfo->srcport, pinfo->destport, 0);
4956     if (!conv) {
4957         conv = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
4958                                  pinfo->srcport, pinfo->destport, 0);
4959     }
4960
4961     /*
4962      * Packet type specific stuff is next.
4963      */
4964
4965     switch (hdr.ptype) {
4966
4967     case PDU_CANCEL_ACK:
4968         /* Body is optional */
4969         /* XXX - we assume "frag_len" is the length of the body */
4970         if (hdr.frag_len != 0)
4971             dissect_dcerpc_dg_cancel_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
4972         break;
4973
4974     case PDU_CL_CANCEL:
4975         /*
4976          * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
4977          * but in at least one capture none of the Cl_cancel PDUs had a
4978          * body.
4979          */
4980         /* XXX - we assume "frag_len" is the length of the body */
4981         if (hdr.frag_len != 0)
4982             dissect_dcerpc_dg_cancel (tvb, offset, pinfo, dcerpc_tree, &hdr);
4983         break;
4984
4985     case PDU_NOCALL:
4986         /* Body is optional; if present, it's the same as PDU_FACK */
4987         /* XXX - we assume "frag_len" is the length of the body */
4988         if (hdr.frag_len != 0)
4989             dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
4990         break;
4991
4992     case PDU_FACK:
4993         dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
4994         break;
4995
4996     case PDU_REJECT:
4997     case PDU_FAULT:
4998         dissect_dcerpc_dg_reject_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
4999         break;
5000
5001     case PDU_REQ:
5002         dissect_dcerpc_dg_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
5003         break;
5004
5005     case PDU_RESP:
5006         dissect_dcerpc_dg_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
5007         break;
5008
5009     /* these requests have no body */
5010     case PDU_ACK:
5011     case PDU_PING:
5012         dissect_dcerpc_dg_ping_ack (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
5013         break;
5014     case PDU_WORKING:
5015     default:
5016         break;
5017     }
5018
5019     return TRUE;
5020 }
5021
5022 static void
5023 dcerpc_init_protocol (void)
5024 {
5025         /* structures and data for BIND */
5026         if (dcerpc_binds){
5027                 g_hash_table_destroy (dcerpc_binds);
5028                 dcerpc_binds=NULL;
5029         } 
5030         if(!dcerpc_binds){
5031                 dcerpc_binds = g_hash_table_new (dcerpc_bind_hash, dcerpc_bind_equal);
5032         }
5033
5034         if (dcerpc_bind_key_chunk){
5035                 g_mem_chunk_destroy (dcerpc_bind_key_chunk);
5036         }
5037         dcerpc_bind_key_chunk = g_mem_chunk_new ("dcerpc_bind_key_chunk",
5038                                              sizeof (dcerpc_bind_key),
5039                                              200 * sizeof (dcerpc_bind_key),
5040                                              G_ALLOC_ONLY);
5041         if (dcerpc_bind_value_chunk){
5042                 g_mem_chunk_destroy (dcerpc_bind_value_chunk);
5043         }
5044         dcerpc_bind_value_chunk = g_mem_chunk_new ("dcerpc_bind_value_chunk",
5045                                              sizeof (dcerpc_bind_value),
5046                                              200 * sizeof (dcerpc_bind_value),
5047                                              G_ALLOC_ONLY);
5048         /* structures and data for CALL */
5049         if (dcerpc_cn_calls){
5050                 g_hash_table_destroy (dcerpc_cn_calls);
5051         }
5052         dcerpc_cn_calls = g_hash_table_new (dcerpc_cn_call_hash, dcerpc_cn_call_equal);
5053         if (dcerpc_dg_calls){
5054                 g_hash_table_destroy (dcerpc_dg_calls);
5055         }
5056         dcerpc_dg_calls = g_hash_table_new (dcerpc_dg_call_hash, dcerpc_dg_call_equal);
5057         if (dcerpc_cn_call_key_chunk){
5058                 g_mem_chunk_destroy (dcerpc_cn_call_key_chunk);
5059         }
5060         dcerpc_cn_call_key_chunk = g_mem_chunk_new ("dcerpc_cn_call_key_chunk",
5061                 sizeof (dcerpc_cn_call_key),
5062                 200 * sizeof (dcerpc_cn_call_key),
5063                 G_ALLOC_ONLY);
5064         if (dcerpc_dg_call_key_chunk){
5065                 g_mem_chunk_destroy (dcerpc_dg_call_key_chunk);
5066         }
5067         dcerpc_dg_call_key_chunk = g_mem_chunk_new ("dcerpc_dg_call_key_chunk",
5068                 sizeof (dcerpc_dg_call_key),
5069                 200 * sizeof (dcerpc_dg_call_key),
5070                 G_ALLOC_ONLY);
5071
5072         if (dcerpc_call_value_chunk){
5073                 g_mem_chunk_destroy (dcerpc_call_value_chunk);
5074         }
5075         dcerpc_call_value_chunk = g_mem_chunk_new ("dcerpc_call_value_chunk",
5076                                              sizeof (dcerpc_call_value),
5077                                              200 * sizeof (dcerpc_call_value),
5078                                              G_ALLOC_ONLY);
5079
5080         /* structure and data for MATCHED */
5081         if (dcerpc_matched){
5082                 g_hash_table_destroy (dcerpc_matched);
5083         }
5084         dcerpc_matched = g_hash_table_new (dcerpc_matched_hash, dcerpc_matched_equal);
5085         if (dcerpc_matched_key_chunk){
5086                 g_mem_chunk_destroy (dcerpc_matched_key_chunk);
5087         }
5088         dcerpc_matched_key_chunk = g_mem_chunk_new ("dcerpc_matched_key_chunk",
5089                                              sizeof (dcerpc_matched_key),
5090                                              200 * sizeof (dcerpc_matched_key),
5091                                              G_ALLOC_ONLY);
5092
5093     /* call the registered hooks */
5094     g_hook_list_invoke(&dcerpc_hooks_init_protos, FALSE /* not may_recurse */);
5095 }
5096
5097 void
5098 proto_register_dcerpc (void)
5099 {
5100     static hf_register_info hf[] = {
5101         { &hf_dcerpc_request_in,
5102                 { "Request in frame", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE,
5103                 NULL, 0, "This packet is a response to the packet with this number", HFILL }},
5104         { &hf_dcerpc_response_in,
5105                 { "Response in frame", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
5106                 NULL, 0, "This packet will be responded in the packet with this number", HFILL }},
5107         { &hf_dcerpc_referent_id,
5108                 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
5109                 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
5110         { &hf_dcerpc_ver,
5111           { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5112         { &hf_dcerpc_ver_minor,
5113           { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5114         { &hf_dcerpc_packet_type,
5115           { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS (pckt_vals), 0x0, "", HFILL }},
5116         { &hf_dcerpc_cn_flags,
5117           { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
5118         { &hf_dcerpc_cn_flags_first_frag,
5119           { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_FIRST_FRAG, "", HFILL }},
5120         { &hf_dcerpc_cn_flags_last_frag,
5121           { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_LAST_FRAG, "", HFILL }},
5122         { &hf_dcerpc_cn_flags_cancel_pending,
5123           { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_PENDING_CANCEL, "", HFILL }},
5124         { &hf_dcerpc_cn_flags_reserved,
5125           { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_RESERVED_1, "", HFILL }},
5126         { &hf_dcerpc_cn_flags_mpx,
5127           { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_CONC_MPX, "", HFILL }},
5128         { &hf_dcerpc_cn_flags_dne,
5129           { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_DID_NOT_EXECUTE, "", HFILL }},
5130         { &hf_dcerpc_cn_flags_maybe,
5131           { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_MAYBE, "", HFILL }},
5132         { &hf_dcerpc_cn_flags_object,
5133           { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_OBJECT_UUID, "", HFILL }},
5134         { &hf_dcerpc_drep,
5135           { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
5136         { &hf_dcerpc_drep_byteorder,
5137           { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS (drep_byteorder_vals), 0x0, "", HFILL }},
5138         { &hf_dcerpc_drep_character,
5139           { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS (drep_character_vals), 0x0, "", HFILL }},
5140         { &hf_dcerpc_drep_fp,
5141           { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS (drep_fp_vals), 0x0, "", HFILL }},
5142         { &hf_dcerpc_cn_frag_len,
5143           { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5144         { &hf_dcerpc_cn_auth_len,
5145           { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5146         { &hf_dcerpc_cn_call_id,
5147           { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5148         { &hf_dcerpc_cn_max_xmit,
5149           { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5150         { &hf_dcerpc_cn_max_recv,
5151           { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5152         { &hf_dcerpc_cn_assoc_group,
5153           { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
5154         { &hf_dcerpc_cn_num_ctx_items,
5155           { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5156         { &hf_dcerpc_cn_ctx_id,
5157           { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5158         { &hf_dcerpc_cn_num_trans_items,
5159           { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5160         { &hf_dcerpc_cn_bind_if_id,
5161           { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
5162         { &hf_dcerpc_cn_bind_if_ver,
5163           { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5164         { &hf_dcerpc_cn_bind_if_ver_minor,
5165           { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5166         { &hf_dcerpc_cn_bind_trans_id,
5167           { "Transfer Syntax", "dcerpc.cn_bind_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
5168         { &hf_dcerpc_cn_bind_trans_ver,
5169           { "Syntax ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5170         { &hf_dcerpc_cn_alloc_hint,
5171           { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5172         { &hf_dcerpc_cn_sec_addr_len,
5173           { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5174         { &hf_dcerpc_cn_sec_addr,
5175           { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, "", HFILL }},
5176         { &hf_dcerpc_cn_num_results,
5177           { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5178         { &hf_dcerpc_cn_ack_result,
5179           { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, "", HFILL }},
5180         { &hf_dcerpc_cn_ack_reason,
5181           { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, "", HFILL }},
5182         { &hf_dcerpc_cn_ack_trans_id,
5183           { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
5184         { &hf_dcerpc_cn_ack_trans_ver,
5185           { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5186         { &hf_dcerpc_cn_reject_reason,
5187           { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, "", HFILL }},
5188         { &hf_dcerpc_cn_num_protocols,
5189           { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5190         { &hf_dcerpc_cn_protocol_ver_major,
5191           { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5192         { &hf_dcerpc_cn_protocol_ver_minor,
5193           { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5194         { &hf_dcerpc_cn_cancel_count,
5195           { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5196         { &hf_dcerpc_cn_status,
5197           { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
5198         { &hf_dcerpc_cn_deseg_req,
5199           { "Desegmentation Required", "dcerpc.cn_deseg_req", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5200         { &hf_dcerpc_auth_type,
5201           { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
5202         { &hf_dcerpc_auth_level,
5203           { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS (authn_level_vals), 0x0, "", HFILL }},
5204         { &hf_dcerpc_auth_pad_len,
5205           { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5206         { &hf_dcerpc_auth_rsrvd,
5207           { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5208         { &hf_dcerpc_auth_ctx_id,
5209           { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5210         { &hf_dcerpc_dg_flags1,
5211           { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
5212         { &hf_dcerpc_dg_flags1_rsrvd_01,
5213           { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_01, "", HFILL }},
5214         { &hf_dcerpc_dg_flags1_last_frag,
5215           { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_LASTFRAG, "", HFILL }},
5216         { &hf_dcerpc_dg_flags1_frag,
5217           { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_FRAG, "", HFILL }},
5218         { &hf_dcerpc_dg_flags1_nofack,
5219           { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_NOFACK, "", HFILL }},
5220         { &hf_dcerpc_dg_flags1_maybe,
5221           { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_MAYBE, "", HFILL }},
5222         { &hf_dcerpc_dg_flags1_idempotent,
5223           { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_IDEMPOTENT, "", HFILL }},
5224         { &hf_dcerpc_dg_flags1_broadcast,
5225           { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_BROADCAST, "", HFILL }},
5226         { &hf_dcerpc_dg_flags1_rsrvd_80,
5227           { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_80, "", HFILL }},
5228         { &hf_dcerpc_dg_flags2,
5229           { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
5230         { &hf_dcerpc_dg_flags2_rsrvd_01,
5231           { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_01, "", HFILL }},
5232         { &hf_dcerpc_dg_flags2_cancel_pending,
5233           { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_CANCEL_PENDING, "", HFILL }},
5234         { &hf_dcerpc_dg_flags2_rsrvd_04,
5235           { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_04, "", HFILL }},
5236         { &hf_dcerpc_dg_flags2_rsrvd_08,
5237           { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_08, "", HFILL }},
5238         { &hf_dcerpc_dg_flags2_rsrvd_10,
5239           { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_10, "", HFILL }},
5240         { &hf_dcerpc_dg_flags2_rsrvd_20,
5241           { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_20, "", HFILL }},
5242         { &hf_dcerpc_dg_flags2_rsrvd_40,
5243           { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_40, "", HFILL }},
5244         { &hf_dcerpc_dg_flags2_rsrvd_80,
5245           { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_80, "", HFILL }},
5246         { &hf_dcerpc_dg_serial_lo,
5247           { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
5248         { &hf_dcerpc_dg_serial_hi,
5249           { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
5250         { &hf_dcerpc_dg_ahint,
5251           { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
5252         { &hf_dcerpc_dg_ihint,
5253           { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
5254         { &hf_dcerpc_dg_frag_len,
5255           { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5256         { &hf_dcerpc_dg_frag_num,
5257           { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5258         { &hf_dcerpc_dg_auth_proto,
5259           { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
5260         { &hf_dcerpc_dg_seqnum,
5261           { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5262         { &hf_dcerpc_dg_server_boot,
5263           { "Server boot time", "dcerpc.dg_server_boot", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0, "", HFILL }},
5264         { &hf_dcerpc_dg_if_ver,
5265           { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5266         { &hf_dcerpc_krb5_av_prot_level,
5267           { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, "", HFILL }},
5268         { &hf_dcerpc_krb5_av_key_vers_num,
5269           { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5270         { &hf_dcerpc_krb5_av_key_auth_verifier,
5271           { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
5272         { &hf_dcerpc_obj_id,
5273           { "Object", "dcerpc.obj_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
5274         { &hf_dcerpc_dg_if_id,
5275           { "Interface", "dcerpc.dg_if_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
5276         { &hf_dcerpc_dg_act_id,
5277           { "Activity", "dcerpc.dg_act_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
5278         { &hf_dcerpc_opnum,
5279           { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5280
5281         { &hf_dcerpc_dg_cancel_vers,
5282           { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5283
5284         { &hf_dcerpc_dg_cancel_id,
5285           { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5286
5287         { &hf_dcerpc_dg_server_accepting_cancels,
5288           { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
5289
5290         { &hf_dcerpc_dg_fack_vers,
5291           { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5292
5293         { &hf_dcerpc_dg_fack_window_size,
5294           { "Window Size", "dcerpc.fack_window_size", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5295
5296         { &hf_dcerpc_dg_fack_max_tsdu,
5297           { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5298
5299         { &hf_dcerpc_dg_fack_max_frag_size,
5300           { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5301
5302         { &hf_dcerpc_dg_fack_serial_num,
5303           { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5304
5305         { &hf_dcerpc_dg_fack_selack_len,
5306           { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5307
5308         { &hf_dcerpc_dg_fack_selack,
5309           { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
5310
5311         { &hf_dcerpc_dg_status,
5312           { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
5313
5314         { &hf_dcerpc_array_max_count,
5315           { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
5316
5317         { &hf_dcerpc_array_offset,
5318           { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
5319
5320         { &hf_dcerpc_array_actual_count,
5321           { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
5322
5323         { &hf_dcerpc_array_buffer,
5324           { "Buffer", "dcerpc.array.buffer", FT_BYTES, BASE_NONE, NULL, 0x0, "Buffer: Buffer containing elements of the array", HFILL }},
5325                 
5326         { &hf_dcerpc_op,
5327           { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5328
5329         { &hf_dcerpc_fragments,
5330           { "Reassembled DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
5331           NULL, 0x0, "DCE/RPC Fragments", HFILL }},
5332
5333         { &hf_dcerpc_fragment,
5334           { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM, BASE_NONE,
5335           NULL, 0x0, "DCE/RPC Fragment", HFILL }},
5336
5337         { &hf_dcerpc_fragment_overlap,
5338           { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE, 
5339       NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
5340
5341         { &hf_dcerpc_fragment_overlap_conflict,
5342           { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE, 
5343       NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
5344
5345         { &hf_dcerpc_fragment_multiple_tails,
5346           { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE, 
5347       NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
5348
5349         { &hf_dcerpc_fragment_too_long_fragment,
5350           { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE, 
5351       NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
5352
5353         { &hf_dcerpc_fragment_error,
5354           { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE, 
5355       NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
5356
5357         { &hf_dcerpc_time, 
5358           { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE, 
5359       NULL, 0, "Time between Request and Response for DCE-RPC calls", HFILL }},
5360
5361         { &hf_dcerpc_reassembled_in,
5362       { "Reassembled PDU in frame", "dcerpc.reassembled_in", FT_FRAMENUM, BASE_NONE, 
5363       NULL, 0x0, "The DCE/RPC PDU is completely reassembled in the packet with this number", HFILL }},
5364
5365         { &hf_dcerpc_unknown_if_id, 
5366           { "Unknown DCERPC interface id", "dcerpc.unknown_if_id", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
5367    };
5368     static gint *ett[] = {
5369         &ett_dcerpc,
5370         &ett_dcerpc_cn_flags,
5371         &ett_dcerpc_cn_ctx,
5372         &ett_dcerpc_cn_iface,
5373         &ett_dcerpc_drep,
5374         &ett_dcerpc_dg_flags1,
5375         &ett_dcerpc_dg_flags2,
5376         &ett_dcerpc_pointer_data,
5377         &ett_dcerpc_string,
5378         &ett_dcerpc_fragments,
5379         &ett_dcerpc_fragment,
5380         &ett_dcerpc_krb5_auth_verf,
5381     };
5382     module_t *dcerpc_module;
5383
5384     proto_dcerpc = proto_register_protocol ("DCE RPC", "DCERPC", "dcerpc");
5385     proto_register_field_array (proto_dcerpc, hf, array_length (hf));
5386     proto_register_subtree_array (ett, array_length (ett));
5387     register_init_routine (dcerpc_init_protocol);
5388     dcerpc_module = prefs_register_protocol (proto_dcerpc, NULL);
5389     prefs_register_bool_preference (dcerpc_module,
5390                                     "desegment_dcerpc",
5391                                     "Reassemble DCE/RPC messages spanning multiple TCP segments",
5392                                     "Whether the DCE/RPC dissector should reassemble messages spanning multiple TCP segments."
5393                                     " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
5394                                     &dcerpc_cn_desegment);
5395     prefs_register_bool_preference (dcerpc_module,
5396                                     "reassemble_dcerpc",
5397                                     "Reassemble DCE/RPC fragments",
5398                                     "Whether the DCE/RPC dissector should reassemble fragmented DCE/RPC PDUs",
5399                                     &dcerpc_reassemble);
5400     register_init_routine(dcerpc_reassemble_init);
5401     dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
5402     dcerpc_tap=register_tap("dcerpc");
5403     
5404     g_hook_list_init(&dcerpc_hooks_init_protos, sizeof(GHook));
5405 }
5406
5407 void
5408 proto_reg_handoff_dcerpc (void)
5409 {
5410     heur_dissector_add ("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
5411     heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
5412     heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
5413     heur_dissector_add ("smb_transact", dissect_dcerpc_cn_smbpipe, proto_dcerpc);
5414     heur_dissector_add ("http", dissect_dcerpc_cn_bs, proto_dcerpc);
5415     dcerpc_smb_init(proto_dcerpc);
5416 }