Introduction
This article is addresses a specific problem related to security of Microsoft Exchange Server: the ability to programmatically set permissions on folders in the Exchange information store.
To perform such an operation manually, Exchange Server administrator may use Exchange System Management (ESM) utility, which is a part of Exchange Server installation:
- Create public folders aaa and bbb with ESM, and create users with mailbox userAAA and userBBB in the Active Directory.
- Then in ESM, open aaa Properties dialog by selecting Folder Properties item in the right-click menu on public folder aaa.
- Activate Client Permissions dialog (depicted in figure below) by pressing the appropriate button.
- Using Add..., Remove... and Properties... buttons, modify roles and permissions given to users userAAA and userBBB on folder aaa (see figure below).
Background
I faced this problem (among many others) while developing a component for managing Active Directory and Exchange Server. Starting to deal with the problem, I thought that all I needed was to take a huge and generally well written book [1] by Thomas Rizzo and just find some ready-made solution there. Unfortunately, it was not the case. First, I found in the book the following information:
How you created the format for your security descriptor will depend on whether you are working in a MAPI public folder top-level hierarchy (TLH) or a non-MAPI TLH. A MAPI TLH requires that you create your security descriptor using the MAPI canonical format. This is what clients, such as Outlook, expect to see: the importance of this requirement cannot be overemphasized. If you create your security descriptor using the Windows canonical format, you will break Outlook! It is also possible to lock yourself out from being able to modify existing items or folders. Therefore, you must be very careful when you work with security descriptors. I highly recommend that you just take advantage of the Security Module that ships with the Exchange SDK. It understands how to correctly create both MAPI and Windows canonical formats and includes code to make sure you don't do any harm when working with security descriptors. (Page 890).
Naturally, after such a strong warning and recommendation, I found information about the Exchange SDK Security Module. In the same chapter, I read the following.
The Exchange SDK Application Security Module
Many developers requested the ability to set and get permissions on items and folders in the Exchange information store. Security can be complex and hard to understand, so the Application Security Module included with the SDK is especially valuable. The module is installed when you install the Exchange SDK. You can find it in the SDK directory under the Samples/Security folder. The module includes a set of JavaScript and ASP pages allowing you to access and modify the XML security descriptor in both Exchange and SPS 2001.
followed by:
You need to know some caveats about the security module, however. First, it cannot change permissions on inherited ACEs. This means that if a user's permissions are inherited from the parent folder, you cannot modify these permissions. Second, the module is written in JavaScript …
And then, of course:
If these shortcomings don't affect you, the security module makes the task of working with security easy.
(Pages 901-903).
Generally, it was recommended to run JavaScript on the Exchange machine using ASP for remote control. The problem was that “these shortcomings” did affect me. It apparently was not acceptable for the UI-less component I developed. Besides that, I might be needed to change permissions inherited from the parent folder. In short, I started to look for a more appropriate solution.
Brief Solution Description
Pretty soon, I found a Microsoft sample [2] that seemed to answer my problem. It actually did the job. The only thing left was to operate it remotely on behalf of an account with MAPI profile [3, 4] for Exchange. I chose .NET Remoting technique (unlike IIS WebService, Remoting allows us to run software on behalf of a particular account easily). I wrapped up the sample code in COM in-proc server and put it to my .NET object exported with Remoting. First, I tried to use Multi-Threaded Apartment (MTA) COM wrapper changing MAPI initialization according to [5, 6] recommendation. But apparently, Exchange SDK does not support MTA access: HrOpenExchangePublicStore()
method failed with “Unknown Exception” return code. So, the COM STA containing Microsoft sample [2] code exported with Remoting technique seemed the only choice.
Using the Code
The sample solution consists of the following projects:
ClientPermissionHelper. COM STA component wrapped up in Exchange SDK sample [2]; implements IPermission
interface containing Add()
, Modify()
and Remove()
methods to deal with permissions. For the sake of simplicity (and because performance is not the main concern for this sample), the component is designed stateless. It implies that each of the interface methods initializes MAPI, creates a MAPI session, does the job, and then releases session and un-initializes the MAPI connection. For the real world applications, a more sophisticated design may be adopted. ClientPermissionHelper
uses MAPI profile for Exchange, named "MS Exchange Settings" (name is hardcoded in the sample). The component uses Exchange SDK header files and static libraries that make it difficult to build it in VS .NET. To cope with this, the relevant header files are placed in the Include folder under the project main folder, and static libraries are paced in Lib folder, with appropriate changes in the project settings (thanks to Yuval Nahon who patiently solved the problem).
ClientPermission. .NET wrapper for ClientPermissionHelper
using COM Interop; exported with Remoting technique and, as such derived from MarshalByRefObject
class. The component implements IClientPermission
interface which is defined in SvrInterface
and consumed by Remoting client. Only one instance of COM object may be used since COM Interop automatically marshals calls from different threads of Remoting built-in thread pool to STA COM thread (of course, at the expense of some performance penalty).
SrvInterface. Defines IClientPermission
interface and Permissions
enumerator used by both Remoting server and client.
SrvHost. Hosts ClientPermission
component and provides its export. It may run on Exchange machine either as a normal application (with /console parameter in command line) or as a Windows service. In both cases, SrvHost should run under the account which has a valid MAPI profile for Exchange (named "MS Exchange Settings"). The component registers an HTTP channel with port number hard-coded for simplicity. In case of Windows service, SrvHost is registered under the name ESClientPermissionServer
as shown in the figure below:
Client. Manages Exchange permissions by calling methods of IClientPermission
interface implemented in ClientPermission
component.
InstExchProfile. Utility for creation of MAPI Exchange profile (as shown e.g., in [4]) named "MS Exchange Settings".
ClientPermissionHelper
, ClientPermission
, SrvHost
and InstExchProfile
have to be placed on the Exchange machine, Client
has to be placed on the client machine, and SrvInterface
on both.
In order to prepare a sample to run, the following steps should be performed:
- Build solution (make sure that ClientPermission project contains reference on ClientPermissionHelper COM Interop).
- Place ClientPermissionHelper.dll, ClientPermission.dll, SrvInterface.dll, SrvHost.exe and InstExchProfile.exe on Exchange machine, and Client.exe and SrvInterface.dll on client machine.
- Register COM ClientPermissionHelper.dll on server machine if it was not done during build. It may be done with either RegSvr32 utility or using ClientPermissionHelper.bat file from SrvHost\bin\Release or SrvHost\bin\Debug.
- Set up "MS Exchange Settings" Exchange profile on Exchange machine with InstExchProfile utility.
- If you are planning to run SrvHost.exe as Windows service, then it has to be installed as a service either with InstallUtil utility or using the file InstallService.bat under account with "MS Exchange Settings" Exchange profile on Exchange machine.
- Create manually public folder aaa and bbb on Exchange, and users userAAA and userBBB with mail boxes in Active Directory. In order to check that this is done correctly, try to add/modify/remove some permission on aaa and bbb for userAAA and userBBB manually.
To run the sample:
- Start SrvHost.exe either as a service or as an EXE application (with key /console or using file SrvHost.bat). If server is running as normal application, then it outputs log information to debug view. Thus DbgView utility may be useful.
- Run Client.exe on client machine.
As a result, permission on aaa and bbb for userAAA and userBBB should be changed appropriately.
Discussion
The above described approach actually solves the problem. But it would be also interesting to try to use ACE
[7] and ACLObject
[8] COM co-classes implemented in ACE.dll first shipped with Microsoft Exchange 5.5. Several publications (e.g., [9, 10 and 11] to mention just a few) describe various operations with Exchange folder permissions locally on Exchange machine. It might be probably possible to use these components from ClientPermission
with COM Interop instead of ClientPermissionHelper
.
Conclusion
This article describes a way to remotely modify permissions on folders in the Exchange Server information store. To attain this, a special Exchange SDK-based COM in-proc server that actually does the job is designed. It is wrapped into a .NET class exposed to a client with Remoting technique.
References
- [1] Programming Microsoft Outlook and Microsoft Exchange 2003, Third Edition / Thomas Rizzo. (1074 pages).
- [2] How To Modify Exchange Folder Permissions Using
IExchangeModifyTable
(297493).
- [3] Demystifying Exchange 2003 Custom Recipients, DLs, and Profiles.
- [4] Configure MAPI profile parameter.
- [5] FIX:
MAPIInitialize()
Fails with MAPI_E_INVALID_FLAGS
(179116).
- [6]
MAPI_NO_COINIT
Flag To Make MAPIInitialize
Not Call CoInit
(239853).
- [7]
ACE
CoClass.
- [8]
ACLObject
CoClass.
- [9] Minding the E-Mail by Bill Boswell, December 2003.
- [10] How To Add A Delegate To An Exchange Folder with the ACL Component and CDO (1.21) (295558).
- [11] PRB: ACL: Outlook 2000 Doesn't Properly Read ACL Settings (237924)