Microsoft KB Archive/304935

= How to set Exchange Server 2000 and 2003 mailbox rights at the time of mailbox creation =

Article ID: 304935

Article Last Modified on 2/23/2007

-

APPLIES TO


 * Microsoft Exchange Server 2003 Standard Edition
 * Microsoft Exchange 2000 Server Standard Edition
 * Microsoft Windows Server 2003, Standard Edition (32-bit x86)
 * Microsoft Windows 2000 Server
 * Microsoft Active Directory Service Interfaces 2.5
 * Microsoft Collaboration Data Objects for Exchange Management 1.1

-



This article was previously published under Q304935



SUMMARY
This article shows you how to programmatically modify mailbox rights on a Microsoft Exchange Server 2000 or 2003 mailbox at the same time that you mailbox-enable the user object in the Microsoft Active Directory directory service.

This article includes sample code that shows you how to set the mailbox rights for an Exchange 2000 or 2003 mailbox before the actual mailbox has been created for the user in the Exchange 2000 or 2003 information store but after the user object has been mailbox-enabled in Active Directory.

Note This code has no effect if the mailbox already exists in the Exchange 2000 or 2003 information store. In other words, it does not affect the actual mailbox rights on the user's mailbox if the user's mailbox has already been accessed. For more information about how to mailbox rights on an Exchange 2000 mailbox both before and after it has been created in the information store, click the following article number to view the article in the Microsoft Knowledge Base:

310866 How to set Exchange 2000 mailbox rights on a mailbox that exists in the information store



MORE INFORMATION
A mailbox has two parts in an Exchange 2000 or 2003 organization in a Microsoft Windows 2000 or Microsoft Windows Server 2003 domain environment.
 * The Active Directory mailbox-enabled user: This is just a user object in Active Directory. Several mail-related properties and mailbox-related properties are set on this user object.
 * The Mailbox Folder in the Exchange information store: This is the location where the user's actual mail is stored and where several properties that are specific to the mailbox are set.

The mailbox rights are stored on a security descriptor property that is located on the mailbox in the information store. There is also an attribute on the Active Directory user object, called the msExchMailboxSecurityDescriptor. This attribute is designed only to reflect the mailbox rights on the user's mailbox.

A quick overview of the mailbox-enabling process in Exchange 2000 or 2003
Here are the steps that are typically taken to create Exchange 2000 or 2003 mailbox-enabled users in Active Directory:
 * 1) A domain administrator creates the Active Directory user object and enables the user account, either from the &quot;Active Directory Users and Computers&quot; (ADUnC) snap-in or from code that uses Active Directory Services Interfaces (ADSI).
 * 2) The domain administrator then mailbox-enables this user, either from ADUnC or programmatically through the IMailboxStore interface in Collaboration Data Objects for Exchange Management (CDOEXM). A link to the documentation for the IMailboxStore interface is included in the &quot;References&quot; section of this article. Any approach other than CDOEXM that is used to programmatically mailbox-enable the user object is not supported.

These two approaches make sure that the msExchMailboxSecurityDescriptor attribute and several other attributes are set correctly on the user object when they mailbox-enable it. This step, basically, sets a small subset of mail attributes and mailbox attributes on the user object in Active Directory. At this point, the user's mailbox is not yet ready for access.
 * 1) The Recipient Update Service (RUS) that runs on the Exchange 2000 or 2003 server, depending on when it is scheduled to run, stamps all the remaining mail-related and mailbox-related attributes on this user object. At this point, the user's mailbox has not yet been created in the Exchange 2000 or 2003 information store. However, the user is completely mailbox-enabled. Now, the mailbox is ready to be accessed.
 * 2) When the user first accesses the mailbox or when the first message is routed to the mailbox, the actual mailbox is created in the Exchange 2000 or 2003 information store. At this point, when Exchange creates the mailbox for the user, the mailbox rights are set on the mailbox's security descriptor in the store. This is based on the access control entries (ACEs) that are set on the msExchMailboxSecurityDescriptor attribute.

The msExchMailboxSecurityDesciptor attribute
This attribute exists on the user object in Active Directory. It stores a partial copy of the user's mailbox security descriptor. This attribute is not back-linked to the user's mailbox security descriptor.

In other words, if you modify this attribute directly, you do not update the actual mailbox security descriptor on the user's mailbox in the Exchange information store, unless you set this attribute before the actual mailbox has been created in the information store.

In fact, if there is a conflict between the security descriptor that is reflected by the msExchMailboxSecurityDescriptor attribute on the user object in Active Directory and the security descriptor that is stored on the user's mailbox in the information store, Exchange fixes the msExchMailboxSecurityDescriptor attribute to reflect the security descriptor on the user's mailbox. If you modify the security descriptor of the user's mailbox from ADUnC or through the CDOEXM IExchangeMailbox interface, the msExchMailboxSecurityDescriptor attribute is updated automatically to reflect these changes.

Limitations of using the msExchMailboxSecurityDescriptor attribute

 * The changes that you make on this attribute are reflected on the security descriptor of the user's mailbox only when you set this attribute before the mailbox is created in the information store. Note that the Exchange 2000 and 2003 mailbox for a mailbox-enabled user in Active Directory is created in an Exchange store when the user first accesses the mailbox or when any mail is sent to this user.
 * Another limitation of this attribute is that the attribute does not reflect any of the inherited ACEs on the actual mailbox's security descriptor. Hence, reading this directory attribute is not the most accurate approach to read a user's mailbox rights.

Advantages of using the msExchMailboxSecurityDescriptor attribute

 * This attribute is defined on a user object in Active Directory. Therefore, it can be accessed using any API that is compliant with Lightweight Directory Access Protocol (LDAP), such as the ADSI APIs or the LDAP APIs.
 * Because this code does not require CDOEXM, you can run it from a server that does not have the Microsoft Exchange 2000 and 2003 System Management Tools installed. But, again, you must set the mailbox rights before the user's mailbox is created in the information store. Also, you can read the mailbox rights at any time on this user's mailbox. But keep in mind the limitations that are mentioned in this article. (See the &quot;Limitations of Using the msExchMailboxSecurityDescriptor Attribute&quot; section.)

If you do not set the msExchMailboxSecurityDescriptor attribute on the mailbox-enabled user before the actual mailbox is created in the information store, the actual security descriptor property on the mailbox in the information store does not include an ACE with the following:
 * The Trustee property set to Self
 * The Access Mask property set to Full Mailbox Access
 * The Read permission set to Allow
 * The ACE Type set to Allow

If this is the case, the user may experience problems when the user tries to access public folders or any resources that are outside the local Exchange server. This is one of the reasons why the IMailboxStore interface in the CDOEXM library is the only supported mechanism to programmatically mailbox-enable an Active Directory user against an Exchange 2000 or 2003 store. Here is a sample that shows you how to use ADSI and CDOEXM to make a mailbox-enabled user object in Active Directory. Then you manually set the msExchMailboxSecurityDescriptor interface to include an ACE with the trustee specified in the code. The sole purpose of this sample is to show you how to set this attribute before the user's mailbox has been accessed and created in the information store if the attribute was not set correctly in the past.

Setting up the Visual Basic environment to run the Visual Basic sample

 * 1) Start Microsoft Visual Basic 6.0 on the Exchange 2000 or 2003 server.
 * 2) Create a New Standard EXE Project. To do so, click New on the File menu, and then double-click Standard EXE.
 * 3) On the Project menu, click References, and then select Active DS Type Library and Microsoft CDO for Exchange Management.
 * 4) In the source view of the form, type or paste the following code so that it replaces the Form_Load subroutine.
 * 5) Change the value that is set on the variable sUserADsPath to the LDAP path for the Active Directory user object whose mailbox rights you want to view or modify.

NOTE: This sample shows you how to read the copy of the mailbox rights that is stored on the msExchMailboxSecurityDescriptor attribute. It also shows you how to modify the mailbox rights and to add an ACE for full mailbox access to the Self ACE as the trustee.

The Visual Basic code
'******************************************************************** '* '* Function AddAce(dacl, TrusteeName, gAccessMask, gAceType, '*           gAceFlags, gFlags, gObjectType, gInheritedObjectType) '* '* Purpose: Adds an ACE to a DACL '* Input:      dacl            Object's Discretionary Access Control List '*             TrusteeName     SID or Name of the trustee user account '*             gAccessMask     Access Permissions '*             gAceType        ACE Types '*             gAceFlags       Inherit ACEs from the owner of the ACL '*             gFlags          ACE has an object type or inherited object type '*             gObjectType     Used for Extended Rights '*             gInheritedObjectType '* '* Output: Object - New DACL with the ACE added '* '********************************************************************

Function AddAce(dacl, TrusteeName, gAccessMask, gAceType, gAceFlags, gFlags, gObjectType, gInheritedObjectType) Dim Ace1 ' Create a new ACE object Set Ace1 = CreateObject(&quot;AccessControlEntry&quot;) Ace1.AccessMask = gAccessMask Ace1.AceType = gAceType Ace1.AceFlags = gAceFlags Ace1.Flags = gFlags Ace1.Trustee = TrusteeName 'Check to see if ObjectType needs to be set If CStr(gObjectType) <> &quot;0&quot; Then Ace1.ObjectType = gObjectType End If

'Check to see if InheritedObjectType needs to be set If CStr(gInheritedObjectType) <> &quot;0&quot; Then Ace1.InheritedObjectType = gInheritedObjectType End If   dacl.AddAce Ace1

' Destroy objects Set Ace1 = Nothing End Function

Private Sub Form_Load Dim objContainer As IADsContainer Dim objUser As IADsUser Dim objMailbox As CDOEXM.IMailboxStore Dim oSecurityDescriptor As SecurityDescriptor Dim dacl As AccessControlList Dim ace As AccessControlEntry

' ******************************************************************** ' You must change this variable according to your environment '

sContainerADsPath = &quot;LDAP://domain.com/cn=Users,DC=domain,DC=com&quot; sUserLoginName = &quot;testUser&quot; sUserFirstName = &quot;Test&quot; sUserLastName = &quot;User&quot; sMBXStoreDN = &quot;CN=Mailbox Store (ExServer),CN=First Storage Group,&quot; & _ &quot;CN=InformationStore,CN=ExServer,CN=Servers,CN=AdminGP,&quot; & _ &quot;CN=Administrative Groups,CN=Microsoft,CN=Microsoft Exchange,&quot; & _ &quot;CN=Services,CN=Configuration,DC=domain,DC=com&quot; sTrustee = &quot;domainName\userName&quot; ' ********************************************************************

' Get directory container object object Set objContainer = GetObject(sContainerADsPath)

' Create the user object in the target container in Active Directory Set objUser = objContainer.Create(&quot;User&quot;, &quot;CN=&quot; & sUserFirstName & &quot; &quot; & _             sUserLastName) objUser.Put &quot;samAccountName&quot;, sUserLoginName objUser.Put &quot;givenName&quot;, sUserFirstName objUser.Put &quot;sn&quot;, sUserLastName objUser.SetInfo objUser.SetPassword &quot;password&quot; objUser.SetInfo

' Mailbox-enable the user object by using the CDOEXM::IMailboxStore ' interface ' This also sets the msExchMailboxSecurityDescriptor appropriately Set objMailbox = objUser objMailbox.CreateMailbox sMBXStoreDN objUser.SetInfo

'************************************************************************** ' The msExchMailboxSecurityDescriptor attribute is a backlink attribute '  from the Exchange Mailbox in the Web store to the directory. What this '  implies is that the mailbox rights are stored on the actual mailbox in '   the Web store and this directory attribute reflects these mailbox '  rights. ' By default, changing this attribute does not affect the mailbox rights '  in the store. This attribute can only be modified before the actual '  mailbox in the store is created. If it is set before the mailbox in '  the Web store is created, Exchange will use the DACL set on this '  attribute as the DACL for mailbox rights on the mailbox in the store. '  Therefore, it can only be set before the mailbox-creation time. ' On installing Exchange 2000 SP2 on the Exchange Server where this code '  is being run, that would enable modifying the actual mailbox rights '  even after mailbox creation. '**************************************************************************

' Get the copy Mailbox Security Descriptor (SD) stored on the ' msExchMailboxSecurityDescriptor attribute objUser.GetInfoEx Array(&quot;msExchMailboxSecurityDescriptor&quot;), 0 Set oSecurityDescriptor = objUser.Get(&quot;msExchMailboxSecurityDescriptor&quot;)

' Extract the Discretionary Access Control List (ACL) using the ' IADsSecurityDescriptor interface Set dacl = oSecurityDescriptor.DiscretionaryAcl

' ' The following block of code demonstrates reading all the ACEs on a '  DACL for the Exchange 2000 mailbox. 'Debug.Print &quot;Here are the existing ACEs the mailbox's DACL - &quot;

' Enumerate all the access control entries (ACEs) in the ACL using ' the IADsAccessControlList interface, thus displaying the current ' mailbox rights Debug.Print &quot;Trustee, AccessMask, ACEType, ACEFlags, Flags, ObjectType, InheritedObjectType&quot; Debug.Print &quot;--- --  ---    -  --&quot; & _ &quot; ---&quot; Debug.Print

For Each ace In dacl ' Display all the ACEs' properties by using the IADsAccessControlEntry ' interface Debug.Print ace.Trustee & &quot;, &quot; & ace.AccessMask & &quot;, &quot; & _ ace.AceType & &quot;, &quot; & ace.AceFlags & &quot;, &quot; & ace.Flags & &quot;, &quot; & _ ace.ObjectType & &quot;, &quot; & ace.InheritedObjectType Next

' ' The following block of code demonstrates adding a new ACE to the DACL ' for the Exchange 2000 mailbox with the Trustee specified in sTrustee, ' giving allow &quot;Full Control&quot; over this mailbox. ' This is the same task that is performed by ADUnC when selecting Add, ' specifying the Trustee, and checking the &quot;Full Mailbox Access&quot; Rights ' checkbox under the Mailbox Rights in the Exchange Advanced tab on the ' properties of a user. ' Similarly, you could remove ACEs from this ACL as well using the ' IADsAccessControlEntry interfaces. '

' Template: AddAce(TrusteeName, gAccessMask, gAceType, gAceFlags, gFlags, gObjectType, gInheritedObjectType) ' Setting the Access Mask to 131075 enables &quot;full mailbox access&quot; and ' &quot;read&quot; privileges AddAce dacl, sTrustee, 131075, _ ADS_ACETYPE_ACCESS_ALLOWED, ADS_ACEFLAG_INHERIT_ACE, 0, 0, 0

' Add the modified DACL back onto the Security Descriptor oSecurityDescriptor.DiscretionaryAcl = dacl

' Save New SD onto the user objUser.Put &quot;msExchMailboxSecurityDescriptor&quot;, oSecurityDescriptor

' Commit changes from the property cache to the Information Store objUser.SetInfo

MsgBox &quot;Done viewing and modifying the copy of the Mailbox Security Descriptor&quot;

End Sub

The Visual Basic Script code
Dim objContainer Dim objUser Dim objMailbox Dim oSecurityDescriptor Dim dacl Dim ace

' ******************************************************************** ' You must change this variable according to your environment '

sContainerADsPath = &quot;LDAP://domain.com/cn=Users,DC=domain,DC=com&quot; sUserLoginName = &quot;testUser&quot; sUserFirstName = &quot;Test&quot; sUserLastName = &quot;User&quot; sMBXStoreDN = &quot;CN=Mailbox Store (ExServer),CN=First Storage Group,&quot; & _ &quot;CN=InformationStore,CN=ExServer,CN=Servers,CN=AdminGP,&quot; & _ &quot;CN=Administrative Groups,CN=Microsoft,CN=Microsoft Exchange,&quot; & _ &quot;CN=Services,CN=Configuration,DC=domain,DC=com&quot; sTrustee = &quot;domainName\userName&quot; ' ********************************************************************

' Get directory container object object Set objContainer = GetObject(sContainerADsPath)

' Create the user object in the target container in Active Directory Set objUser = objContainer.Create(&quot;User&quot;, &quot;CN=&quot; & sUserFirstName & &quot; &quot; & _             sUserLastName) objUser.Put &quot;samAccountName&quot;, sUserLoginName objUser.Put &quot;givenName&quot;, sUserFirstName objUser.Put &quot;sn&quot;, sUserLastName objUser.SetInfo objUser.SetPassword &quot;password&quot; objUser.SetInfo

' Mailbox enable the user object by using the CDOEXM::IMailboxStore ' interface ' This also sets the msExchMailboxSecurityDescriptor appropriately Set objMailbox = objUser objMailbox.CreateMailbox sMBXStoreDN objUser.SetInfo

'************************************************************************** ' The msExchMailboxSecurityDescriptor attribute is a backlink attribute '  from the Exchange Mailbox in the Web Store to the directory. What this '  implies is that the mailbox rights are stored on the actual mailbox in '   the Web store and this directory attribute reflects these mailbox '  rights. ' By default, changing this attribute does not affect the mailbox rights '  in the store. This attribute can only be modified before the actual '  mailbox in the store is created. If it is set before the mailbox in '  the Web store is created, Exchange will use the DACL set on this '  attribute as the DACL for mailbox rights on the mailbox in the store. '  Therefore, it can only be set before the mailbox creation time. ' On installing Exchange 2000 SP2 on the Exchange Server where this code '  is being run, that would enable modifying the actual mailbox rights '  even after mailbox creation. '**************************************************************************

' Get the copy Mailbox Security Descriptor (SD) stored on the ' msExchMailboxSecurityDescriptor attribute objUser.GetInfoEx Array(&quot;msExchMailboxSecurityDescriptor&quot;), 0 Set oSecurityDescriptor = objUser.Get(&quot;msExchMailboxSecurityDescriptor&quot;)

' Extract the Discretionary Access Control List (ACL) using the ' IADsSecurityDescriptor interface Set dacl = oSecurityDescriptor.DiscretionaryAcl

' ' The following block of code demonstrates reading all the ACEs on a '  DACL for the Exchange 2000 mailbox. 'Wscript.echo &quot;Here are the existing ACEs the mailbox's DACL - &quot;

' Enumerate all the access control entries (ACEs) in the ACL using ' the IADsAccessControlList interface, thus displaying the current ' mailbox rights Wscript.echo &quot;Trustee, AccessMask, ACEType, ACEFlags, Flags, ObjectType, InheritedObjectType&quot; Wscript.echo &quot;--- --  ---    -  --&quot; & _ &quot; ---&quot; Wscript.echo

For Each ace In dacl ' Display all the ACEs' properties using the IADsAccessControlEntry ' interface Wscript.echo ace.Trustee & &quot;, &quot; & ace.AccessMask & &quot;, &quot; & _ ace.AceType & &quot;, &quot; & ace.AceFlags & &quot;, &quot; & ace.Flags & &quot;, &quot; & _ ace.ObjectType & &quot;, &quot; & ace.InheritedObjectType Next

' ' The following block of code demonstrates adding a new ACE to the DACL ' for the Exchange 2000 mailbox with the Trustee specified in sTrustee, ' giving allow &quot;Full Control&quot; over this mailbox. ' This is the same task that is performed by ADUnC when selecting Add, ' specifying the Trustee, and checking the &quot;Full Mailbox Access&quot; Rights ' checkbox under the Mailbox Rights in the Exchange Advanced tab on the ' properties of a user. ' Similarly, you could remove ACEs from this ACL as well using the ' IADsAccessControlEntry interfaces. '

' Template: AddAce(TrusteeName, gAccessMask, gAceType, gAceFlags, gFlags, gObjectType, gInheritedObjectType) ' Setting the Access Mask to 131075 enables &quot;full mailbox access&quot; and ' &quot;read&quot; priviledges AddAce dacl, sTrustee, 131075, _ ADS_ACETYPE_ACCESS_ALLOWED, ADS_ACEFLAG_INHERIT_ACE, 0, 0, 0

' Add the modified DACL back onto the Security Descriptor oSecurityDescriptor.DiscretionaryAcl = dacl

' Save New SD onto the user objUser.Put &quot;msExchMailboxSecurityDescriptor&quot;, oSecurityDescriptor

' Commit changes from the property cache to the information store objUser.SetInfo

MsgBox &quot;Done viewing and modifying the copy of the Mailbox Security Descriptor&quot;

'******************************************************************** '* '* Function AddAce(dacl, TrusteeName, gAccessMask, gAceType, '*           gAceFlags, gFlags, gObjectType, gInheritedObjectType) '* '* Purpose: Adds an ACE to a DACL '* Input:      dacl            Object's Discretionary Access Control List '*             TrusteeName     SID or Name of the trustee user account '*             gAccessMask     Access Permissions '*             gAceType        ACE Types '*             gAceFlags       Inherit ACEs from the owner of the ACL '*             gFlags          ACE has an object type or inherited object type '*             gObjectType     Used for Extended Rights '*             gInheritedObjectType '* '* Output: Object - New DACL with the ACE added '* '********************************************************************

Function AddAce(dacl, TrusteeName, gAccessMask, gAceType, gAceFlags, gFlags, gObjectType, gInheritedObjectType) Dim Ace1 ' Create a new ACE object Set Ace1 = CreateObject(&quot;AccessControlEntry&quot;) Ace1.AccessMask = gAccessMask Ace1.AceType = gAceType Ace1.AceFlags = gAceFlags Ace1.Flags = gFlags Ace1.Trustee = TrusteeName 'Check to see if ObjectType needs to be set If CStr(gObjectType) <> &quot;0&quot; Then Ace1.ObjectType = gObjectType End If

'Check to see if InheritedObjectType needs to be set If CStr(gInheritedObjectType) <> &quot;0&quot; Then Ace1.InheritedObjectType = gInheritedObjectType End If   dacl.AddAce Ace1

' Destroy objects Set Ace1 = Nothing End Function

