Note: This article refers to the policy mechanism of Exchange 2003 SP2, it does not apply to Exchange 2007. For information on how to manipulate Exchange 2007 policies, look for PowerShell tasks named ActiveSyncMailboxPolicy.

People in charge of IT departments want the ability to force users to have certain settings on their mobile devices. This usually includes things like requiring that the user enters a PIN (Personal Identification Number) before being able to use the phone. If the user forgets his phone in the Starbuck's restrooms, the person finding it won't be able to do much without knowing the PIN.

The upcoming Exchange 2003 Service Pack 2 (SP2) includes some enhancements in this area.

Where does the admin go to set those policies? It's in Exchange System Manager, under Global Settings / Mobile Services / Properties / General tab / Device Security button.

ESM will store this data in the Active Directory on the following object:

         CN=Outlook Mobile Access,CN=Global Settings,CN=First Organization,CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=...
Most of the settings are in the msExchOmaExtendedProperties attribute, it is a multi-valued string which could, in the future, contain more than just policy stuff, so we gave the policy information prefixes to recognize them. Here's an example of what it would look like.
         PolicyData:<wap-provisioningdoc>Settings are here</wap-provisioningdoc>
         PolicyDataSalt:M9RNvCWoW0WISbLT90QNbg==
         PolicyKey:4321
         PolicyDataRefreshInterval:1440c

Most of the settings are stored in the string prefixed "PolicyData:". The values from the ESM dialog are encoded between the <wap-provisioningdoc> tags. That XML blob is in a format that is understood by the CSP modules of Windows Mobile devices, and it looks like:

<wap-provisioningdoc>
    <characteristic type="SecurityPolicy">
        <parm name="4131" value="0"/>
    </characteristic>
    <characteristic type="Registry">
        <characteristic type="HKLM\Comm\Security\Policy\LASSD\AE\{50C13377-C66D-400C-889E-C316FC4AB374}">
            <parm name="AEFrequencyType" value="1"/>
            <parm name="AEFrequencyValue" value="5"/>
        </characteristic>
        <characteristic type="HKLM\Comm\Security\Policy\LASSD">
            <parm name="DeviceWipeThreshold" value="20"/>
        </characteristic>
        <characteristic type="HKLM\Comm\Security\Policy\LASSD">
            <parm name="CodewordFrequency" value="5"/>
        </characteristic>
        <characteristic type="HKLM\Comm\Security\Policy\LASSD\LAP\lap_pw">
            <parm name="MinimumPasswordLength" value="8"/>
        </characteristic>
        <characteristic type="HKLM\Comm\Security\Policy\LASSD\LAP\lap_pw">
            <parm name="PasswordComplexity" value="0"/>
        </characteristic>
    </characteristic>
</wap-provisioningdoc>

We're looking at providing a simpler alternative in a future version of the server. For now, if you want to generate your own policies, you'll have to generate this XML. Everything in the XML is hard-coded, except for the content of the "value" attributes. The meaning of which depends on the "name" attribute of the "parm" object (I love how they save 1 byte by removing an 'a' from 'param', but then use things like "HKLM\Comm\Security\Policy\LASSD\AE\{50C13377-C66D-400C-889E-C316FC4AB374}").

Here's how the XML elements map to the UI:

• The "Enforce password on device" checkbox maps to the name="4131" (don't ask me where 4131 comes from, I don't know). And it uses the value of "0" for enabled and the value of "1" for disabled (intuitive, isn't it?). If the checkbox is disabled, the rest of the settings are meaningless, so they are not included.
• The "Minimum password length" maps to name="MinimumPasswordLength" and is simply the minimum number of characters in the PIN. If the checkbox is unchecked, the value becomes 1. Remember that this setting is present only if a PIN is required, so a minimum length of 1 is implied anyway.
• The "Require both numbers and letters" checkbox maps to name="PasswordComplexity", the possible values are: 0 = Require alphanumeric, 1 = Require only numeric, 2 = Anything goes. ESM will only set values 0 (when checked) or 2 (when unchecked).
• The "Inactivity time" maps to name="AEFrequencyType" and name=" AEFrequencyValue". AEFrequencyType of 0 means there is no inactivity time (checkbox unchecked) while 1 means there is (checkbox checked) and the number of minutes is in AEFrequencyValue.
• The "Wipe device after failed (attempts)" maps to name="DeviceWipeThreshold". A value of -1 means the checkbox is unchecked, otherwise it's the number of failed attempts at entering a PIN before the device wipes all memory.

You then might be wondering what name="CodewordFrequency" means. First, "DeviceWipeThreshold" protects you from a hacker who "borrowed" your phone and is trying to guess your password. The memory will be wiped after a few attempts. On the other hand, "CodewordFrequency" protects you from your 3-year-old offspring. If little Timmy grabs your phone while you're reading the newspaper, and starts entering PINs at random, he could wipe your phone's memory! To prevent that, the phone will prompt Timmy to enter a certain "codeword" (it even tells you what the codeword is). Since most 3-year-olds can't read, he won't get to try more PINs. There is no UI in ESM for this setting, we set it to half of DeviceWipeThreshold, but no higher than 8.

Before I explain the other "PolicyXXX" strings, I need to explain how/when that policy data is sent to the device.

When the device tries to execute an Exchange Active Sync (EAS) command (synchronizing a folder, fetching an attachment, etc...) it will also send an X-MS-PolicyKey string in the HTTP headers of the request. The server looks at this policy key and compares it with the string that follows "PolicyKey:" in the multi-valued attribute above. If they don't match, the server will tell the device that it must issue a PROVISION command before it is allowed to execute any other command (the server does that by returning an HTTP status code of 449).

Every time ESM modifies the policy settings, it also modifies the "PolicyKey:" string. Once the device issues that PROVISION command, it will be given the policy data. The device must then send a second PROVISION command to confirm that it has successfully applied this policy. The server then answers the new policy key string that the device can use in X-MS-PolicyKey to execute other commands.

If the admin wants to, she can force devices to re-issue a PROVISION command every X hours (see "Refresh settings" in the UI). That refresh interval value is stored in the "PolicyDataRefreshInterval:" string (in number of minutes). To enforce this interval, the server needs to answer a 449 whenever it's been too long since the device last applied the policy settings. The server stores the timestamp of the last successful provision command in the user's mailbox, in the non-IPM subtree (so Outlook doesn't show it) along with a bunch of other information the server needs to maintain for each device.

There's still one more string I haven't explained: "PolicyDataSalt:". Since users have full unrestricted access to their own mailboxes, somebody could write a simple application that would continuously update the timestamp in the user's mailbox (using MAPI or DAV) so that the server always thinks the device has recently refreshed its policy. We must prevent users from tampering with that timestamp. To that end, we sign the timestamp by also storing its hash, but to make that hash non-guessable, we need to add random data to it. That's what the "salt" is; it's simply random bytes (base64 encoded). Users won't have access to it, so they can't generate a valid hash to sign the timestamp. The salt should only be created when the first policy is set, no need to change it when the policy changes (it would invalidate all the hashes).

If you look at the UI again, there are still two things I haven't covered: "Allow access to devices that do not support password settings" and the "Exceptions" button.

The first one is what we refer to as "loose" enforcement, meaning that if a device doesn't know anything about policies and the provision command (we know that by the absence of any X-MS-PolicyKey header), we would normally answer a 403 (Forbidden) HTTP response to any command. But if you have this checkbox checked, we will allow such devices to execute commands. Only devices that do send X-MS-PolicyKey will be required to apply policies. This is to provide a transition period for companies that have both old and new devices and don't want to lock out all their old devices. That option is not stored in the same multi-valued attribute like the other policy settings, it is stored as bit 0x00000010 in the msExchOmaAdminWirelessEnable attribute. The bit is set to 1, if the policy is to be enforced "loosely".

The last option is the Exceptions. This allows the admin to choose a list of users who are not required to apply the policy settings. Maybe only a handful of users have old devices, maybe the CEO doesn't like having to enter a PIN every time he uses his phone, etc... The server knows a user is exempt from policy settings, if bit 0x00000020 of msExchOmaAdminWirelessEnable is set to 1. But when ESM wants to display the list of exempted users, it needs an attribute it can query on (LDAP doesn't support searching for individual bits), so exempted users also have "PolicyDataExemption:true" added to the msExchOmaAdminExtendedSettings attribute (another multi-valued string) of the user object in the Active Directory.

I'll let you in on a little secret... even though ESM only let's you set policy settings on the global "Outlook Mobile Access" object; you can actually store them on this msExchOmaAdminExtendedSettings attribute of the user objects in the same way. The server will look for those "PolicyData:", "PolicyDataSalt:", etc... strings on the user object first, if it doesn't find it there, it then looks at the global object. This way you can override policy settings for individual users. But note that if one of those strings appears on the user object, they all need to be there. The server won't take some of the strings from the user object and others from the global object.

- Patrick Tousignant