1 /* packet-dcerpc-mapi.c
2 * Routines for MS Exchange MAPI
3 * Copyright 2002, Ronnie Sahlberg
5 * $Id: packet-dcerpc-mapi.c,v 1.12 2002/06/24 00:03:17 tpot Exp $
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@ethereal.com>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 #include <epan/packet.h>
32 #include "packet-dcerpc.h"
33 #include "packet-dcerpc-nt.h"
34 #include "packet-dcerpc-mapi.h"
35 #include "smb.h" /* for "NT_errors[]" */
38 static int proto_dcerpc_mapi = -1;
39 static int hf_mapi_unknown_string = -1;
40 static int hf_mapi_unknown_data = -1;
41 static int hf_mapi_unknown_short = -1;
42 static int hf_mapi_hnd = -1;
43 static int hf_mapi_rc = -1;
44 static int hf_mapi_encap_datalen = -1;
45 static int hf_mapi_decrypted_data_maxlen = -1;
46 static int hf_mapi_decrypted_data_offset = -1;
47 static int hf_mapi_decrypted_data_len = -1;
48 static int hf_mapi_decrypted_data = -1;
49 static int hf_mapi_pdu_len = -1;
50 static int hf_mapi_pdu_trailer = -1;
51 static int hf_mapi_pdu_extra_trailer = -1;
53 static gint ett_dcerpc_mapi = -1;
54 static gint ett_mapi_decrypted_pdu = -1;
56 static e_uuid_t uuid_dcerpc_mapi = {
57 0xa4f1db00, 0xca47, 0x1067,
58 { 0xb3, 0x1f, 0x00, 0xdd, 0x01, 0x06, 0x62, 0xda }
61 static guint16 ver_dcerpc_mapi = 0;
63 #define DISSECT_UNKNOWN(len) \
65 proto_tree_add_text(tree, tvb, offset, len,\
66 "unknown data (%d byte%s)", len,\
67 plurality(len, "", "s"));\
72 static gboolean mapi_decrypt = FALSE;
73 static GMemChunk *mapi_decrypted_data_chunk = NULL;
74 static int mapi_decrypted_data_init_count = 200;
75 static GHashTable *mapi_decrypted_table = NULL;
81 } mapi_decrypted_data_t;
84 free_all_decrypted(gpointer key_arg, gpointer value _U_, gpointer user_data _U_)
86 mapi_decrypted_data_t *mdd=(mapi_decrypted_data_t *)key_arg;
99 mapi_decrypt_hash(gconstpointer k)
101 mapi_decrypted_data_t *mdd=(mapi_decrypted_data_t *)k;
105 mapi_decrypt_equal(gconstpointer k1, gconstpointer k2)
107 mapi_decrypted_data_t *mdd1=(mapi_decrypted_data_t *)k1;
108 mapi_decrypted_data_t *mdd2=(mapi_decrypted_data_t *)k2;
110 return ( (mdd1->frame==mdd2->frame)
111 &&(mdd1->callid==mdd2->callid) );
114 mapi_decrypt_init(void)
116 if(mapi_decrypted_table){
117 g_hash_table_foreach_remove(mapi_decrypted_table,
118 free_all_decrypted, NULL);
120 mapi_decrypted_table=g_hash_table_new(mapi_decrypt_hash,
124 if(mapi_decrypted_data_chunk){
125 g_mem_chunk_destroy(mapi_decrypted_data_chunk);
126 mapi_decrypted_data_chunk=NULL;
130 mapi_decrypted_data_chunk=g_mem_chunk_new("mapi_decrypt_chunk",
131 sizeof(mapi_decrypted_data_t),
132 mapi_decrypted_data_init_count*sizeof(mapi_decrypted_data_t),
139 mapi_decrypt_pdu(tvbuff_t *tvb, int offset,
140 packet_info *pinfo, proto_tree *tree, char *drep)
143 mapi_decrypted_data_t *mmd=NULL;
148 proto_item *it = NULL;
149 proto_tree *tr = NULL;
151 di=pinfo->private_data;
152 if(di->conformant_run){
156 offset=dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_mapi_decrypted_data_maxlen, NULL);
157 offset=dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_mapi_decrypted_data_offset, NULL);
158 offset=dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_mapi_decrypted_data_len, &len);
160 if(len>(guint32)tvb_length_remaining(tvb, offset)){
161 len=tvb_length_remaining(tvb, offset);
164 if(!pinfo->fd->flags.visited){
165 mmd=g_mem_chunk_alloc(mapi_decrypted_data_chunk);
166 mmd->callid=di->call_id;
167 mmd->frame=pinfo->fd->num;
168 mmd->data=g_malloc(len);
169 ptr=(unsigned char *)tvb_get_ptr(tvb, offset, len);
171 mmd->data[i]=ptr[i]^0xa5;
173 mmd->tvb=tvb_new_real_data(mmd->data, len, len);
174 g_hash_table_insert(mapi_decrypted_table, mmd, mmd);
178 mapi_decrypted_data_t mmd_key;
179 mmd_key.callid=di->call_id;
180 mmd_key.frame=pinfo->fd->num;
181 mmd=g_hash_table_lookup(mapi_decrypted_table, &mmd_key);
184 add_new_data_source(pinfo, mmd->tvb, "Decrypted MAPI");
187 /* All from 10 minutes eyeballing. This may be wrong.
188 The PDU is NOT NDR encoded. So this completely new marshalling
189 used by MAPI needs to be figured out.
191 It seems that ASCII text strings always are NULL terminated,
192 also no obvious string-length-byte can be seen so it seems the
193 length of strings are determined by searching the terminating null
196 The first two bytes of the PDU is the length of the PDU including
197 the two length bytes.
198 The third byte may be a subcommand byte ?
200 After the PDU comes, in requests a 4 byte thing. Which is either
201 (not very often) 0xffffffff or something else. If it is
202 'something else' these four bytes are repeated for the matching
204 In some repsonse packets, this 4 byte trailer are sometimes followed
205 by some other data. Unclear if this is just random padding or actual
206 data. Seems a bit non-random for padding though.
208 Some response packets have a PDU of 2 bytes only, ie only the
209 2 byte length field followed by the 4 byte trailer.
211 perhaps the 4 byte trailers, and the extra trailers have some
213 More work needs to be done in this area.
215 it=proto_tree_add_text(tree, mmd->tvb, 0, len, "Decrypted MAPI PDU");
216 tr=proto_item_add_subtree(it, ett_mapi_decrypted_pdu);
218 pdu_len=tvb_get_letohs(mmd->tvb, 0);
219 proto_tree_add_uint(tr, hf_mapi_pdu_len, mmd->tvb, 0, 2, pdu_len);
221 /*XXX call dissector here */
222 proto_tree_add_item(tr, hf_mapi_decrypted_data, mmd->tvb, 2, pdu_len-2, FALSE);
224 proto_tree_add_item(tr, hf_mapi_pdu_trailer, mmd->tvb, pdu_len, 4, FALSE);
225 if(len>((guint32)pdu_len+4)){
226 proto_tree_add_item(tr, hf_mapi_pdu_extra_trailer, mmd->tvb, pdu_len+4, len-(pdu_len+4), FALSE);
236 mapi_logon_rqst(tvbuff_t *tvb, int offset,
237 packet_info *pinfo, proto_tree *tree, char *drep)
239 offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
240 dissect_ndr_nt_STRING_string, NDR_POINTER_REF,
241 "unknown string", hf_mapi_unknown_string, -1);
243 DISSECT_UNKNOWN(tvb_length_remaining(tvb, offset));
248 /* The strings in this function are decoded properly on seen captures.
249 There might be offsets/padding mismatched due to potential pointer expansions
250 or padding bytes. Captures where this code breaks will tell us about that */
252 mapi_logon_reply(tvbuff_t *tvb, int offset,
253 packet_info *pinfo, proto_tree *tree, char *drep)
255 offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep,
256 hf_mapi_hnd, NULL, FALSE, FALSE);
258 DISSECT_UNKNOWN(20); /* this is 20 bytes, unless there are pointers */
260 offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
261 dissect_ndr_nt_STRING_string, NDR_POINTER_REF,
262 "unknown string", hf_mapi_unknown_string, -1);
264 DISSECT_UNKNOWN(6); /* possibly 1 or 2 bytes padding here */
266 offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
267 dissect_ndr_nt_STRING_string, NDR_POINTER_REF,
268 "unknown string", hf_mapi_unknown_string, -1);
270 DISSECT_UNKNOWN( tvb_length_remaining(tvb, offset)-4 );
272 offset = dissect_ntstatus(tvb, offset, pinfo, tree, drep,
279 mapi_unknown_02_request(tvbuff_t *tvb, int offset,
280 packet_info *pinfo, proto_tree *tree, char *drep)
282 offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep,
283 hf_mapi_hnd, NULL, FALSE, FALSE);
286 /* this is a unidimensional varying and conformant array of
288 offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
289 dissect_ndr_nt_STRING_string, NDR_POINTER_REF,
290 "unknown data", hf_mapi_unknown_data, -1);
292 offset = mapi_decrypt_pdu(tvb, offset, pinfo, tree, drep);
295 /* length of encrypted data. */
296 offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
297 hf_mapi_encap_datalen, NULL);
299 offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
300 hf_mapi_unknown_short, NULL);
305 mapi_unknown_02_reply(tvbuff_t *tvb, int offset,
306 packet_info *pinfo, proto_tree *tree, char *drep)
308 offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep,
309 hf_mapi_hnd, NULL, FALSE, FALSE);
312 /* this is a unidimensional varying and conformant array of
314 offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
315 dissect_ndr_nt_STRING_string, NDR_POINTER_REF,
316 "unknown data", hf_mapi_unknown_data, -1);
318 offset = mapi_decrypt_pdu(tvb, offset, pinfo, tree, drep);
321 /* length of encrypted data */
322 offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
323 hf_mapi_encap_datalen, NULL);
325 offset = dissect_ntstatus(tvb, offset, pinfo, tree, drep,
332 mapi_logoff_rqst(tvbuff_t *tvb, int offset,
333 packet_info *pinfo, proto_tree *tree, char *drep)
335 offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep,
336 hf_mapi_hnd, NULL, FALSE, FALSE);
342 mapi_logoff_reply(tvbuff_t *tvb, int offset,
343 packet_info *pinfo, proto_tree *tree, char *drep)
345 offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep,
346 hf_mapi_hnd, NULL, FALSE, FALSE);
348 offset = dissect_ntstatus(tvb, offset, pinfo, tree, drep,
355 static dcerpc_sub_dissector dcerpc_mapi_dissectors[] = {
356 { MAPI_LOGON, "Logon",
359 { MAPI_LOGOFF, "Logoff",
362 { MAPI_UNKNOWN_02, "unknown_02",
363 mapi_unknown_02_request,
364 mapi_unknown_02_reply },
366 {0, NULL, NULL, NULL }
370 proto_register_dcerpc_mapi(void)
373 static hf_register_info hf[] = {
375 { "Context Handle", "mapi.hnd", FT_BYTES, BASE_NONE,
376 NULL, 0x0, "", HFILL }},
379 { "Return code", "mapi.rc", FT_UINT32, BASE_HEX,
380 VALS (NT_errors), 0x0, "", HFILL }},
382 { &hf_mapi_unknown_string,
383 { "Unknown string", "mapi.unknown_string", FT_STRING, BASE_NONE,
384 NULL, 0, "Unknown string. If you know what this is, contact ethereal developers.", HFILL }},
386 { &hf_mapi_unknown_short,
387 { "Unknown short", "mapi.unknown_short", FT_UINT16, BASE_HEX,
388 NULL, 0, "Unknown short. If you know what this is, contact ethereal developers.", HFILL }},
390 { &hf_mapi_unknown_data,
391 { "unknown encrypted data", "mapi.unknown_data", FT_BYTES, BASE_HEX,
392 NULL, 0, "Unknown data. If you know what this is, contact ethereal developers.", HFILL }},
394 { &hf_mapi_encap_datalen,
395 { "Length", "mapi.encap_len", FT_UINT16, BASE_DEC,
396 NULL, 0x0, "Length of encapsulated/encrypted data", HFILL }},
398 { &hf_mapi_decrypted_data_maxlen,
399 { "Max Length", "mapi.decrypted.data.maxlen", FT_UINT32, BASE_DEC,
400 NULL, 0x0, "Maximum size of buffer for decrypted data", HFILL }},
402 { &hf_mapi_decrypted_data_offset,
403 { "Offset", "mapi.decrypted.data.offset", FT_UINT32, BASE_DEC,
404 NULL, 0x0, "Offset into buffer for decrypted data", HFILL }},
406 { &hf_mapi_decrypted_data_len,
407 { "Length", "mapi.decrypted.data.len", FT_UINT32, BASE_DEC,
408 NULL, 0x0, "Used size of buffer for decrypted data", HFILL }},
410 { &hf_mapi_decrypted_data,
411 { "Decrypted data", "mapi.decrypted.data", FT_BYTES, BASE_HEX,
412 NULL, 0x0, "Decrypted data", HFILL }},
415 { "Length", "mapi.pdu.len", FT_UINT16, BASE_DEC,
416 NULL, 0x0, "Size of the command PDU", HFILL }},
418 { &hf_mapi_pdu_trailer,
419 { "Trailer", "mapi.pdu.trailer", FT_UINT32, BASE_HEX,
420 NULL, 0x0, "If you know what this is, contact ethereal developers", HFILL }},
422 { &hf_mapi_pdu_extra_trailer,
423 { "unknown", "mapi.pdu.extra_trailer", FT_BYTES, BASE_HEX,
424 NULL, 0x0, "If you know what this is, contact ethereal developers", HFILL }}
428 static gint *ett[] = {
430 &ett_mapi_decrypted_pdu
432 module_t *mapi_module;
434 proto_dcerpc_mapi = proto_register_protocol(
435 "Microsoft Exchange MAPI", "MAPI", "mapi");
437 proto_register_field_array(proto_dcerpc_mapi, hf,
439 proto_register_subtree_array(ett, array_length(ett));
440 mapi_module = prefs_register_protocol(proto_dcerpc_mapi, NULL);
441 prefs_register_bool_preference(mapi_module, "mapi_decrypt",
443 "Whether the dissector should decrypt MAPI PDUs",
445 register_init_routine(mapi_decrypt_init);
449 proto_reg_handoff_dcerpc_mapi(void)
451 /* Register protocol as dcerpc */
453 dcerpc_init_uuid(proto_dcerpc_mapi, ett_dcerpc_mapi,
454 &uuid_dcerpc_mapi, ver_dcerpc_mapi,
455 dcerpc_mapi_dissectors, -1);