1 /* packet-dcerpc-mapi.c
2 * Routines for MS Exchange MAPI
3 * Copyright 2002, Ronnie Sahlberg
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
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 "packet-windows-common.h" /* for "NT_errors[]" */
36 #include <epan/prefs.h>
38 static int proto_dcerpc_mapi = -1;
39 static int hf_mapi_opnum = -1;
40 static int hf_mapi_unknown_string = -1;
41 static int hf_mapi_unknown_short = -1;
42 static int hf_mapi_unknown_long = -1;
43 static int hf_mapi_hnd = -1;
44 static int hf_mapi_rc = -1;
45 static int hf_mapi_encap_datalen = -1;
46 static int hf_mapi_encrypted_data = -1;
47 static int hf_mapi_decrypted_data_maxlen = -1;
48 static int hf_mapi_decrypted_data_offset = -1;
49 static int hf_mapi_decrypted_data_len = -1;
50 static int hf_mapi_decrypted_data = -1;
51 static int hf_mapi_pdu_len = -1;
52 static int hf_mapi_notification_port = -1;
53 static int hf_mapi_notification_payload = -1;
55 static gint ett_dcerpc_mapi = -1;
56 static gint ett_mapi_decrypted_pdu = -1;
58 static e_uuid_t uuid_dcerpc_mapi = {
59 0xa4f1db00, 0xca47, 0x1067,
60 { 0xb3, 0x1f, 0x00, 0xdd, 0x01, 0x06, 0x62, 0xda }
63 static guint16 ver_dcerpc_mapi = 0;
65 #define DISSECT_UNKNOWN(len) \
67 proto_tree_add_text(tree, tvb, offset, len,\
68 "unknown data (%d byte%s)", len,\
69 plurality(len, "", "s"));\
74 static gboolean mapi_decrypt = FALSE;
77 mapi_decrypt_pdu(tvbuff_t *tvb, int offset,
78 packet_info *pinfo, proto_tree *tree, guint8 *drep)
81 guint8 *decrypted_data;
82 tvbuff_t *decrypted_tvb;
84 gint len, reported_len;
88 proto_item *it = NULL;
89 proto_tree *tr = NULL;
91 di=pinfo->private_data;
92 if(di->conformant_run){
96 offset=dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_mapi_decrypted_data_maxlen, NULL);
97 offset=dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_mapi_decrypted_data_offset, NULL);
98 offset=dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_mapi_decrypted_data_len, &length);
100 len = tvb_length_remaining(tvb, offset);
101 reported_len = tvb_reported_length_remaining(tvb, offset);
102 if((guint32)reported_len > length)
103 reported_len = length;
104 if(len > reported_len)
107 ptr=tvb_get_ptr(tvb, offset, len);
108 decrypted_data=g_malloc(len);
111 * Now *that's* secure encryption!
113 decrypted_data[i]=ptr[i]^0xa5;
116 /* Allocate a new tvbuff, referring to the decrypted data. */
117 decrypted_tvb=tvb_new_real_data(decrypted_data, len, reported_len);
119 /* Arrange that the allocated packet data copy be freed when the
121 tvb_set_free_cb(decrypted_tvb, g_free);
123 /* Add the tvbuff to the list of tvbuffs to which the tvbuff we
124 were handed refers, so it'll get cleaned up when that tvbuff
126 tvb_set_child_real_data_tvbuff(tvb, decrypted_tvb);
128 /* Add the decrypted data to the data source list. */
129 add_new_data_source(pinfo, decrypted_tvb, "Decrypted MAPI");
132 /* All from 10 minutes eyeballing. This may be wrong.
133 The PDU is NOT NDR encoded. So this completely new marshalling
134 used by MAPI needs to be figured out.
136 It seems that ASCII text strings always are NULL terminated,
137 also no obvious string-length-byte can be seen so it seems the
138 length of strings are determined by searching the terminating null
141 The first two bytes of the PDU is the length of the PDU including
142 the two length bytes.
143 The third byte may be a subcommand byte ?
145 After the PDU comes, in requests a 4 byte thing. Which is either
146 (not very often) 0xffffffff or something else. If it is
147 'something else' these four bytes are repeated for the matching
149 In some repsonse packets, this 4 byte trailer are sometimes followed
150 by some other data. Unclear if this is just random padding or actual
151 data. Seems a bit non-random for padding though.
153 Some response packets have a PDU of 2 bytes only, ie only the
154 2 byte length field followed by the 4 byte trailer.
156 perhaps the 4 byte trailers, and the extra trailers have some
158 More work needs to be done in this area.
160 it=proto_tree_add_text(tree, decrypted_tvb, 0, len, "Decrypted MAPI PDU");
161 tr=proto_item_add_subtree(it, ett_mapi_decrypted_pdu);
163 pdu_len=tvb_get_letohs(decrypted_tvb, 0);
164 proto_tree_add_uint(tr, hf_mapi_pdu_len, decrypted_tvb, 0, 2, pdu_len);
166 /*XXX call dissector here */
167 proto_tree_add_item(tr, hf_mapi_decrypted_data, decrypted_tvb, 2, pdu_len-2, FALSE);
175 mapi_logon_rqst(tvbuff_t *tvb, int offset,
176 packet_info *pinfo, proto_tree *tree, guint8 *drep)
178 offset = dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
179 sizeof(guint8), hf_mapi_unknown_string, TRUE, NULL);
181 DISSECT_UNKNOWN(tvb_length_remaining(tvb, offset));
186 /* The strings in this function are decoded properly on seen captures.
187 There might be offsets/padding mismatched due to potential pointer expansions
188 or padding bytes. Captures where this code breaks will tell us about that */
190 mapi_logon_reply(tvbuff_t *tvb, int offset,
191 packet_info *pinfo, proto_tree *tree, guint8 *drep)
193 offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep,
194 hf_mapi_hnd, NULL, NULL, FALSE, FALSE);
196 DISSECT_UNKNOWN(20); /* this is 20 bytes, unless there are pointers */
198 offset = dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
199 sizeof(guint8), hf_mapi_unknown_string, TRUE, NULL);
201 /* Was DISSECT_UNKNOWN(6), but the 1 or 2 bytes the comment that
202 was here referred to probably were padding, if they were seen;
203 in another capture, there are 5 bytes there - it's probably a
204 4-byte quantity, always aligned on a 4-byte boundary. */
205 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
206 hf_mapi_unknown_long, NULL);
208 offset = dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
209 sizeof(guint8), hf_mapi_unknown_string, TRUE, NULL);
211 DISSECT_UNKNOWN( tvb_length_remaining(tvb, offset)-4 );
213 offset = dissect_ntstatus(tvb, offset, pinfo, tree, drep,
220 mapi_ec_do_rpc_request(tvbuff_t *tvb, int offset,
221 packet_info *pinfo, proto_tree *tree, guint8 *drep)
223 offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep,
224 hf_mapi_hnd, NULL, NULL, FALSE, FALSE);
227 /* this is a unidimensional varying and conformant array of
229 offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
230 dissect_ndr_byte_array, NDR_POINTER_REF,
231 "Encrypted data", hf_mapi_encrypted_data);
233 offset = mapi_decrypt_pdu(tvb, offset, pinfo, tree, drep);
236 /* length of encrypted data. */
237 offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
238 hf_mapi_encap_datalen, NULL);
240 offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
241 hf_mapi_unknown_short, NULL);
246 mapi_ec_do_rpc_reply(tvbuff_t *tvb, int offset,
247 packet_info *pinfo, proto_tree *tree, guint8 *drep)
249 offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep,
250 hf_mapi_hnd, NULL, NULL, FALSE, FALSE);
253 /* this is a unidimensional varying and conformant array of
255 offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
256 dissect_ndr_byte_array, NDR_POINTER_REF,
257 "Encrypted data", hf_mapi_encrypted_data);
259 offset = mapi_decrypt_pdu(tvb, offset, pinfo, tree, drep);
262 /* length of encrypted data */
263 offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
264 hf_mapi_encap_datalen, NULL);
266 offset = dissect_ntstatus(tvb, offset, pinfo, tree, drep,
273 mapi_logoff_rqst(tvbuff_t *tvb, int offset,
274 packet_info *pinfo, proto_tree *tree, guint8 *drep)
276 offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep,
277 hf_mapi_hnd, NULL, NULL, FALSE, FALSE);
283 mapi_logoff_reply(tvbuff_t *tvb, int offset,
284 packet_info *pinfo, proto_tree *tree, guint8 *drep)
286 offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep,
287 hf_mapi_hnd, NULL, NULL, FALSE, FALSE);
289 offset = dissect_ntstatus(tvb, offset, pinfo, tree, drep,
296 mapi_reg_push_notification_rqst(tvbuff_t *tvb, int offset,
297 packet_info *pinfo _U_, proto_tree *tree, guint8 *drep _U_)
299 static dissector_handle_t newmail_handle;
301 proto_tree_add_item(tree, hf_mapi_notification_payload, tvb, 28, 8,
303 proto_tree_add_item(tree, hf_mapi_notification_port, tvb, 50, 2,
306 /* Register the notification port from this packet with the newmail
308 newmail_handle = find_dissector("newmail");
309 dissector_add("udp.port", tvb_get_ntohs(tvb, 50), newmail_handle);
315 static dcerpc_sub_dissector dcerpc_mapi_dissectors[] = {
316 { MAPI_EC_DO_CONNECT, "EcDoConnect",
319 { MAPI_EC_DO_DISCONNECT,"EcDoDisconnect",
322 { MAPI_EC_DO_RPC, "EcDoRpc",
323 mapi_ec_do_rpc_request,
324 mapi_ec_do_rpc_reply },
325 { MAPI_EC_GET_MORE_RPC, "EcGetMoreRpc", NULL, NULL },
326 { MAPI_EC_REGISTER_PUSH_NOTIFICATION, "EcRRegisterPushNotification",
327 mapi_reg_push_notification_rqst, NULL },
328 { MAPI_EC_UNREGISTER_PUSH_NOTIFICATION, "EcRUnregisterPushNotification",
329 NULL, NULL }, /* Not used by Microsoft Outlook */
330 { MAPI_EC_DUMMY_RPC, "EcDummyRpc", NULL, NULL },
331 { MAPI_EC_GET_DC_NAME, "EcRGetDCName", NULL, NULL },
332 { MAPI_EC_NET_GET_DC_NAME, "EcRNetGetDCName", NULL, NULL },
333 { MAPI_EC_DO_RPC_EXT, "EcDoRpcExt", NULL, NULL },
334 {0, NULL, NULL, NULL }
338 proto_register_dcerpc_mapi(void)
341 static hf_register_info hf[] = {
343 { "Operation", "mapi.opnum", FT_UINT16, BASE_DEC,
344 NULL, 0x0, "", HFILL }},
347 { "Context Handle", "mapi.hnd", FT_BYTES, BASE_NONE,
348 NULL, 0x0, "", HFILL }},
351 { "Return code", "mapi.rc", FT_UINT32, BASE_HEX,
352 VALS (NT_errors), 0x0, "", HFILL }},
354 { &hf_mapi_unknown_string,
355 { "Unknown string", "mapi.unknown_string", FT_STRING, BASE_NONE,
356 NULL, 0, "Unknown string. If you know what this is, contact wireshark developers.", HFILL }},
358 { &hf_mapi_unknown_short,
359 { "Unknown short", "mapi.unknown_short", FT_UINT16, BASE_HEX,
360 NULL, 0, "Unknown short. If you know what this is, contact wireshark developers.", HFILL }},
362 { &hf_mapi_unknown_long,
363 { "Unknown long", "mapi.unknown_long", FT_UINT32, BASE_HEX,
364 NULL, 0, "Unknown long. If you know what this is, contact wireshark developers.", HFILL }},
366 { &hf_mapi_encap_datalen,
367 { "Length", "mapi.encap_len", FT_UINT16, BASE_DEC,
368 NULL, 0x0, "Length of encapsulated/encrypted data", HFILL }},
370 { &hf_mapi_encrypted_data,
371 { "Encrypted data", "mapi.encrypted_data", FT_BYTES, BASE_HEX,
372 NULL, 0, "Encrypted data", HFILL }},
374 { &hf_mapi_decrypted_data_maxlen,
375 { "Max Length", "mapi.decrypted.data.maxlen", FT_UINT32, BASE_DEC,
376 NULL, 0x0, "Maximum size of buffer for decrypted data", HFILL }},
378 { &hf_mapi_decrypted_data_offset,
379 { "Offset", "mapi.decrypted.data.offset", FT_UINT32, BASE_DEC,
380 NULL, 0x0, "Offset into buffer for decrypted data", HFILL }},
382 { &hf_mapi_decrypted_data_len,
383 { "Length", "mapi.decrypted.data.len", FT_UINT32, BASE_DEC,
384 NULL, 0x0, "Used size of buffer for decrypted data", HFILL }},
386 { &hf_mapi_decrypted_data,
387 { "Decrypted data", "mapi.decrypted.data", FT_BYTES, BASE_HEX,
388 NULL, 0x0, "Decrypted data", HFILL }},
391 { "Length", "mapi.pdu.len", FT_UINT16, BASE_DEC,
392 NULL, 0x0, "Size of the command PDU", HFILL }},
394 { &hf_mapi_notification_port,
395 { "Notification port", "mapi.notification_port", FT_UINT16,
397 "UDP port which newmail protocol notifications are sent to on the client", HFILL }},
399 { &hf_mapi_notification_payload,
400 { "Notification payload", "mapi.notification_payload",
401 FT_BYTES, BASE_NONE, NULL, 0x0,
402 "Payload to be sent in newmail protocol notification packets", HFILL }},
407 static gint *ett[] = {
409 &ett_mapi_decrypted_pdu
411 module_t *mapi_module;
413 proto_dcerpc_mapi = proto_register_protocol(
414 "Microsoft Exchange MAPI", "MAPI", "mapi");
416 proto_register_field_array(proto_dcerpc_mapi, hf,
418 proto_register_subtree_array(ett, array_length(ett));
419 mapi_module = prefs_register_protocol(proto_dcerpc_mapi, NULL);
420 prefs_register_bool_preference(mapi_module, "decrypt",
422 "Whether the dissector should decrypt MAPI PDUs",
427 proto_reg_handoff_dcerpc_mapi(void)
429 /* Register protocol as dcerpc */
431 dcerpc_init_uuid(proto_dcerpc_mapi, ett_dcerpc_mapi,
432 &uuid_dcerpc_mapi, ver_dcerpc_mapi,
433 dcerpc_mapi_dissectors, hf_mapi_opnum);