1 /* packet-dcerpc-mapi.c
2 * Routines for MS Exchange MAPI
3 * Copyright 2002, Ronnie Sahlberg
5 * $Id: packet-dcerpc-mapi.c,v 1.9 2002/05/31 00:31:13 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(!pinfo->fd->flags.visited){
161 mmd=g_mem_chunk_alloc(mapi_decrypted_data_chunk);
162 mmd->callid=di->call_id;
163 mmd->frame=pinfo->fd->num;
164 mmd->data=g_malloc(len);
165 ptr=(unsigned char *)tvb_get_ptr(tvb, offset, len);
167 mmd->data[i]=ptr[i]^0xa5;
169 mmd->tvb=tvb_new_real_data(mmd->data, len, len);
170 g_hash_table_insert(mapi_decrypted_table, mmd, mmd);
174 mapi_decrypted_data_t mmd_key;
175 mmd_key.callid=di->call_id;
176 mmd_key.frame=pinfo->fd->num;
177 mmd=g_hash_table_lookup(mapi_decrypted_table, &mmd_key);
180 add_new_data_source(pinfo->fd, mmd->tvb, "Decrypted MAPI");
184 /* All from 10 minutes eyeballing. This may be wrong.
185 The PDU is NOT NDR encoded. So this completely new marshalling
186 used by MAPI needs to be figured out.
188 It seems that ASCII text strings always are NULL terminated,
189 also no obvious string-length-byte can be seen so it seems the
190 length of strings are determined by searching the terminating null
193 The first two bytes of the PDU is the length of the PDU including
194 the two length bytes.
195 The third byte may be a subcommand byte ?
197 After the PDU comes, in requests a 4 byte thing. Which is either
198 (not very often) 0xffffffff or something else. If it is
199 'something else' these four bytes are repeated for the matching
201 In some repsonse packets, this 4 byte trailer are sometimes followed
202 by some other data. Unclear if this is just random padding or actual
203 data. Seems a bit non-random for padding though.
205 Some response packets have a PDU of 2 bytes only, ie only the
206 2 byte length field followed by the 4 byte trailer.
208 perhaps the 4 byte trailers, and the extra trailers have some
210 More work needs to be done in this area.
212 it=proto_tree_add_text(tree, mmd->tvb, 0, len, "Decrypted MAPI PDU");
213 tr=proto_item_add_subtree(it, ett_mapi_decrypted_pdu);
215 pdu_len=tvb_get_letohs(mmd->tvb, 0);
216 proto_tree_add_uint(tr, hf_mapi_pdu_len, mmd->tvb, 0, 2, pdu_len);
218 /*XXX call dissector here */
219 proto_tree_add_item(tr, hf_mapi_decrypted_data, mmd->tvb, 2, pdu_len-2, FALSE);
221 proto_tree_add_item(tr, hf_mapi_pdu_trailer, mmd->tvb, pdu_len, 4, FALSE);
222 if(len>((guint32)pdu_len+4)){
223 proto_tree_add_item(tr, hf_mapi_pdu_extra_trailer, mmd->tvb, pdu_len+4, len-(pdu_len+4), FALSE);
233 mapi_logon_rqst(tvbuff_t *tvb, int offset,
234 packet_info *pinfo, proto_tree *tree, char *drep)
236 offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
237 dissect_ndr_nt_STRING_string, NDR_POINTER_REF,
238 "unknown string", hf_mapi_unknown_string, -1);
240 DISSECT_UNKNOWN(tvb_length_remaining(tvb, offset));
245 /* The strings in this function are decoded properly on seen captures.
246 There might be offsets/padding mismatched due to potential pointer expansions
247 or padding bytes. Captures where this code breaks will tell us about that */
249 mapi_logon_reply(tvbuff_t *tvb, int offset,
250 packet_info *pinfo, proto_tree *tree, char *drep)
252 offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep,
253 hf_mapi_hnd, NULL, FALSE, FALSE);
255 DISSECT_UNKNOWN(20); /* this is 20 bytes, unless there are pointers */
257 offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
258 dissect_ndr_nt_STRING_string, NDR_POINTER_REF,
259 "unknown string", hf_mapi_unknown_string, -1);
261 DISSECT_UNKNOWN(6); /* possibly 1 or 2 bytes padding here */
263 offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
264 dissect_ndr_nt_STRING_string, NDR_POINTER_REF,
265 "unknown string", hf_mapi_unknown_string, -1);
267 DISSECT_UNKNOWN( tvb_length_remaining(tvb, offset)-4 );
269 offset = dissect_ntstatus(tvb, offset, pinfo, tree, drep,
276 mapi_unknown_02_request(tvbuff_t *tvb, int offset,
277 packet_info *pinfo, proto_tree *tree, char *drep)
279 offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep,
280 hf_mapi_hnd, NULL, FALSE, FALSE);
283 /* this is a unidimensional varying and conformant array of
285 offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
286 dissect_ndr_nt_STRING_string, NDR_POINTER_REF,
287 "unknown data", hf_mapi_unknown_data, -1);
289 offset = mapi_decrypt_pdu(tvb, offset, pinfo, tree, drep);
292 /* length of encrypted data. */
293 offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
294 hf_mapi_encap_datalen, NULL);
296 offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
297 hf_mapi_unknown_short, NULL);
302 mapi_unknown_02_reply(tvbuff_t *tvb, int offset,
303 packet_info *pinfo, proto_tree *tree, char *drep)
305 offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep,
306 hf_mapi_hnd, NULL, FALSE, FALSE);
309 /* this is a unidimensional varying and conformant array of
311 offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
312 dissect_ndr_nt_STRING_string, NDR_POINTER_REF,
313 "unknown data", hf_mapi_unknown_data, -1);
315 offset = mapi_decrypt_pdu(tvb, offset, pinfo, tree, drep);
318 /* length of encrypted data */
319 offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
320 hf_mapi_encap_datalen, NULL);
322 offset = dissect_ntstatus(tvb, offset, pinfo, tree, drep,
329 mapi_logoff_rqst(tvbuff_t *tvb, int offset,
330 packet_info *pinfo, proto_tree *tree, char *drep)
332 offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep,
333 hf_mapi_hnd, NULL, FALSE, FALSE);
339 mapi_logoff_reply(tvbuff_t *tvb, int offset,
340 packet_info *pinfo, proto_tree *tree, char *drep)
342 offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep,
343 hf_mapi_hnd, NULL, FALSE, FALSE);
345 offset = dissect_ntstatus(tvb, offset, pinfo, tree, drep,
352 static dcerpc_sub_dissector dcerpc_mapi_dissectors[] = {
353 { MAPI_LOGON, "Logon",
356 { MAPI_LOGOFF, "Logoff",
359 { MAPI_UNKNOWN_02, "unknown_02",
360 mapi_unknown_02_request,
361 mapi_unknown_02_reply },
363 {0, NULL, NULL, NULL }
367 proto_register_dcerpc_mapi(void)
370 static hf_register_info hf[] = {
372 { "Context Handle", "mapi.hnd", FT_BYTES, BASE_NONE,
373 NULL, 0x0, "", HFILL }},
376 { "Return code", "mapi.rc", FT_UINT32, BASE_HEX,
377 VALS (NT_errors), 0x0, "", HFILL }},
379 { &hf_mapi_unknown_string,
380 { "Unknown string", "mapi.unknown_string", FT_STRING, BASE_NONE,
381 NULL, 0, "Unknown string. If you know what this is, contact ethereal developers.", HFILL }},
383 { &hf_mapi_unknown_short,
384 { "Unknown short", "mapi.unknown_short", FT_UINT16, BASE_HEX,
385 NULL, 0, "Unknown short. If you know what this is, contact ethereal developers.", HFILL }},
387 { &hf_mapi_unknown_data,
388 { "unknown encrypted data", "mapi.unknown_data", FT_BYTES, BASE_HEX,
389 NULL, 0, "Unknown data. If you know what this is, contact ethereal developers.", HFILL }},
391 { &hf_mapi_encap_datalen,
392 { "Length", "mapi.encap_len", FT_UINT16, BASE_DEC,
393 NULL, 0x0, "Length of encapsulated/encrypted data", HFILL }},
395 { &hf_mapi_decrypted_data_maxlen,
396 { "Max Length", "mapi.decrypted.data.maxlen", FT_UINT32, BASE_DEC,
397 NULL, 0x0, "Maximum size of buffer for decrypted data", HFILL }},
399 { &hf_mapi_decrypted_data_offset,
400 { "Offset", "mapi.decrypted.data.offset", FT_UINT32, BASE_DEC,
401 NULL, 0x0, "Offset into buffer for decrypted data", HFILL }},
403 { &hf_mapi_decrypted_data_len,
404 { "Length", "mapi.decrypted.data.len", FT_UINT32, BASE_DEC,
405 NULL, 0x0, "Used size of buffer for decrypted data", HFILL }},
407 { &hf_mapi_decrypted_data,
408 { "Decrypted data", "mapi.decrypted.data", FT_BYTES, BASE_HEX,
409 NULL, 0x0, "Decrypted data", HFILL }},
412 { "Length", "mapi.pdu.len", FT_UINT16, BASE_DEC,
413 NULL, 0x0, "Size of the command PDU", HFILL }},
415 { &hf_mapi_pdu_trailer,
416 { "Trailer", "mapi.pdu.trailer", FT_UINT32, BASE_HEX,
417 NULL, 0x0, "If you know what this is, contact ethereal developers", HFILL }},
419 { &hf_mapi_pdu_extra_trailer,
420 { "unknown", "mapi.pdu.extra_trailer", FT_BYTES, BASE_HEX,
421 NULL, 0x0, "If you know what this is, contact ethereal developers", HFILL }}
425 static gint *ett[] = {
427 &ett_mapi_decrypted_pdu
429 module_t *mapi_module;
431 proto_dcerpc_mapi = proto_register_protocol(
432 "Microsoft Exchange MAPI", "MAPI", "mapi");
434 proto_register_field_array(proto_dcerpc_mapi, hf,
436 proto_register_subtree_array(ett, array_length(ett));
437 mapi_module = prefs_register_protocol(proto_dcerpc_mapi, NULL);
438 prefs_register_bool_preference(mapi_module, "mapi_decrypt",
440 "Whether the dissector should decrypt MAPI PDUs",
442 register_init_routine(mapi_decrypt_init);
446 proto_reg_handoff_dcerpc_mapi(void)
448 /* Register protocol as dcerpc */
450 dcerpc_init_uuid(proto_dcerpc_mapi, ett_dcerpc_mapi,
451 &uuid_dcerpc_mapi, ver_dcerpc_mapi,
452 dcerpc_mapi_dissectors);