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