Microsoft KB Archive/310866

From BetaArchive Wiki

Article ID: 310866

Article Last Modified on 2/8/2006



APPLIES TO

  • Microsoft Exchange Server 2003 Standard Edition
  • Microsoft Exchange Server 2000 Service Pack 1



This article was previously published under Q310866

SUMMARY

In Microsoft Exchange Server 2003 and in Microsoft Exchange 2000 Server, you can set mailbox rights by using the Active Directory Users and Computers (ADUnC) snap-in on a username that has been mailbox enabled. (Right-click the user object, click Properties, click the Exchange Advanced tab, and then click Mailbox Rights.)

Although you can modify these mailbox rights from the ADUnC snap-in, this article demonstrates how to perform this task programmatically after you create the mailbox in the information store.

MORE INFORMATION

Requirements

The following list outlines the recommended hardware, software, network infrastructure, and service packs that are required:

  • You must use an Exchange 2003 or Exchange 2000 server on which you have installed either Service Pack 2, or Service Pack 1 and the post-Service Pack 1 Exchange 2000 hotfix. For more information about Service Packs, see the "References" section.
  • You must use ADSI code to access the user object information from the Active Directory.
  • You must start the Exchange 2003 or Exchange 2000 information store where the user's mailbox exists (the store must be running and mounted).

In an Exchange 2003 or Exchange 2000 organization or Windows Server 2003 or Windows 2000 domain environment, a mailbox includes two parts:

  • The Active Directory Mailbox Enabled User. This is just a user object in the Active Directory that has several mail and mailbox-related properties set on it.
  • The Mailbox Folder in the Exchange information store. This is the location where the user's mail is stored and where several mailbox-specific properties are set.

The msExchMailboxSecurityDescriptor Attribute

The mailbox rights are stored on a security descriptor property on the mailbox in the information store. The attribute on the Active Directory user object that is named msExchMailboxSecurityDescriptor is designed to reflect the mailbox rights on the user's mailbox.

This attribute exists on the user object in the Active Directory and 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 msExchMailboxSecurityDescriptor is modified directly, the actual mailbox security descriptor on the user's mailbox in the information store is not updated. If the user's mailbox security descriptor is modified from ADUnC or as demonstrated in the code in this article, msExchMailboxSecurityDescriptor is automatically updated to reflect these changes.

Changes that you make on msExchMailboxSecurityDescriptor are reflected on the user's mailbox security descriptor only if you set this attribute before you create the mailbox in the web store.

For more information, click the following article number to view the article in the Microsoft Knowledge Base:

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


Note that the Exchange 2003 or Exchange 2000 mailbox for an Active Directory mailbox enabled user is created in an Exchange store when the user tries to access the mailbox for the first time or when any mail is sent to this mailbox.

Another limitation of msExchMailboxSecurityDescriptor is that it does not reflect any of the inherited access control entries (ACEs) on the security descriptor of the mailbox itself. Therefore, Microsoft does not recommend that you modify the mailbox rights on a mailbox by reading msExchMailboxSecurityDescriptor. Other ways of reading a user's mailbox rights are more accurate than using this directory attribute.

The IExchangeMailbox Interface

You can use the IExchangeMailbox interface to work with the mailbox rights on an Exchange 2003 or Exchange 2000 mailbox. The Exchange 2003 or Exchange 2000 server must be configured as listed in "Requirements" for the following to work:

  • To expose mailbox rights
  • For the IExchangeMailbox interface to be present
  • To run the sample code

This interface belongs to the CDOEXM library (Cdoexm.dll version 6.0.4720.13).

NOTE: Do not try to manually copy Cdoexm.dll and then use the regsvr32 command to register this .dll file, because this results in compatibility issues.

The IExchangeMailbox interface inherits all the properties and methods of the IMailboxStore interface and introduces one additional property that is named MailboxRights. You can query for the IExchangeMailbox interface only from ADSI interfaces and not from the CDO.Person object.

The MailboxRights property exposes the security descriptor on the Exchange 2000 Mailbox in the information store, which you can work with by using the IADsSecurityDescriptor interface in the ADSI library. You can handle this security descriptor like you handle the security descriptor on any other type of object (for example, users in the Active Directory or files in a folder). For more information about security descriptors and interfaces in the ADSI library that are exposed to programmatically manipulate a security descriptor, see the "References" section of this article.

If the mailbox for this mailbox enabled user object has not been created in the information store yet, IExchangeMailbox interface manipulates the msExchMailboxSecurityDescriptor attribute instead. This explains why you see a limited set of rights when you use this interface or ADUnC to view the mailbox rights for a mailbox enabled user before their mailbox has been created in the information store. After the mailbox has been created, you see a lot more mailbox rights. These additional rights are the inherited rights on the mailbox from the parent store object in the Exchange information store.

Set Up the Visual Basic Environment

  1. Start Microsoft Visual Basic 6.0 on your Exchange 2003 or Exchange 2000 server.
  2. Open a new Standard EXE project: on the File menu, click New, 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, paste the code that follows these steps in the place of (overwrite) the Form_Load() subroutine.
  5. Change the values that are set for the two variables, sUserADsPath and sTrustee:
    1. Set sUserADsPath to the LDAP path for the Active Directory User object whose mailbox rights you want to view or modify.
    2. Set sTrustee to the name of the account that you want to add an ACE onto the mailbox's security descriptor, and allow this account Full Mailbox Access. Set sTrustee in the form domainName\UserName.

IMPORTANT: Because this sample demonstrates how to read and modify the mailbox rights, and how to add an access control entry (ACE) for full mailbox access to the specified trustee, test this code on a test user first.

The Visual Basic Sample Code

   CONST ADS_ACEFLAG_INHERIT_ACE = 2
   CONST ADS_RIGHT_DS_CREATE_CHILD = 1
   CONST ADS_ACETYPE_ACCESS_ALLOWED = 0
   CONST ADS_ACETYPE_ACCESS_DENIED = 1 
   CONST ADS_ACETYPE_SYSTEM_AUDIT = 2 
   CONST ADS_ACETYPE_ACCESS_ALLOWED_OBJECT = 5 
   CONST ADS_ACETYPE_ACCESS_DENIED_OBJECT = 6 
   CONST ADS_ACETYPE_SYSTEM_AUDIT_OBJECT = 7 
   CONST ADS_ACETYPE_SYSTEM_ALARM_OBJECT = 8 


'********************************************************************
'*
'* 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("AccessControlEntry")
    Ace1.AccessMask = gAccessMask
    Ace1.AceType = gAceType
    Ace1.AceFlags = gAceFlags
    Ace1.Flags = gFlags
    Ace1.Trustee = TrusteeName
    'See whether ObjectType must be set.
    If CStr(gObjectType) <> "0" Then
       Ace1.ObjectType = gObjectType
    End If

    'See whether InheritedObjectType must be set.
    If CStr(gInheritedObjectType) <> "0" Then
        Ace1.InheritedObjectType = gInheritedObjectType
    End If
    dacl.AddAce Ace1

    ' Destroy objects.
    Set Ace1 = Nothing
End Function


Private Sub Form_Load()
Dim objUser As IADsUser
Dim oSecurityDescriptor As New SecurityDescriptor
Dim dacl As New AccessControlList
Dim ace As New AccessControlEntry

' ********************************************************************
' You will need to change this variable according to your environment.
'
sUserADsPath = "LDAP://ServerName/CN=User1,CN=Users,DC=DomainName,DC=com"
sTrustee = "DomainName\UserName"
' ********************************************************************

' Get directory user object.
Set objUser = GetObject(sUserADsPath)

' Get the Mailbox security descriptor (SD).
Set oSecurityDescriptor = objUser.MailboxRights

' Extract the discretionary access control list (ACL) by using the IADsSecurityDescriptor.
' Interface
Set dacl = oSecurityDescriptor.DiscretionaryAcl

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'  The following block of code demonstrates how to read all the ACEs on a
'  DACL for the Exchange 2000 mailbox.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Debug.Print "Here are the existing ACEs in the mailbox's DACL:"

' Enumerate all the access control entries (ACEs) in the ACL using the IADsAccessControlList.
' Interface, therefore, displaying the current mailbox rights.
Debug.Print "Trustee, AccessMask, ACEType, ACEFlags, Flags, ObjectType, InheritedObjectType"
Debug.Print "-------  ----------  -------  --------  -----  ----------  -------------------"
Debug.Print

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

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'  The following block of code demonstrates how to add a new ACE to the
'  DACL for the Exchange 2000 mailbox with the Trustee specified in 
'  sTrustee, which permits "Full Control" over this mailbox.
'  This is the same task that is performed by ADUnC when you follow these
'  steps to modify the properties of a user: on the Exchange Advanced tab,
'  under Mailbox Rights, click Add, select the Trustee, and then select the 
'  Full Mailbox Access Rights check box. 
'  Similarly, you can also remove ACEs from this ACL by using the IADsAccessControlEntry interfaces.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

' Template: AddAce(TrusteeName, gAccessMask, gAceType, gAceFlags, gFlags, gObjectType, gInheritedObjectType)
AddAce dacl, sTrustee, ADS_RIGHT_DS_CREATE_CHILD, _
       ADS_ACETYPE_ACCESS_ALLOWED, ADS_ACEFLAG_INHERIT_ACE, 0, 0, 0

' Add the modified DACL to the security descriptor.
oSecurityDescriptor.DiscretionaryAcl = dacl

' Save new SD onto the user.
objUser.MailboxRights = oSecurityDescriptor

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

MsgBox "Done viewing and modifying the Mailbox security descriptor"

End Sub
                

The Visual Basic Script Code

CONST ADS_ACETYPE_ACCESS_ALLOWED = 0
CONST ADS_ACETYPE_ACCESS_DENIED = 1
CONST ADS_ACETYPE_SYSTEM_AUDIT = 2
CONST ADS_ACETYPE_ACCESS_ALLOWED_OBJECT = 5
CONST ADS_ACETYPE_ACCESS_DENIED_OBJECT = 6
CONST ADS_ACETYPE_SYSTEM_AUDIT_OBJECT = 7
CONST ADS_ACETYPE_SYSTEM_ALARM_OBJECT = 8


Dim objUser
Dim oSecurityDescriptor 
Dim dacl 
Dim ace 

' ********************************************************************
' Change this variable according to your environment.
'
sUserADsPath = "LDAP://ServerName/CN=User1,CN=Users,DC=DomainName,DC=com"
sTrustee = "DomainName\UserName"
' ********************************************************************

'Get directory user object.
Set objUser = GetObject(sUserADsPath)

' Get the Mailbox security descriptor (SD).
Set oSecurityDescriptor = objUser.MailboxRights

' Extract the Discretionary Access Control List (DACL) using the IADsSecurityDescriptor.
' Interface.
Set dacl = oSecurityDescriptor.DiscretionaryAcl
Set ace = CreateObject("AccessControlEntry")

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'  The following block of code demonstrates how to read all the 
'  ACEs on a DACL for the Exchange 2000 mailbox.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
wscript.echo "Here are the existing ACEs in the mailbox's DACL:"

' Enumerate all the Access Control Entries (ACE) in the DACL using the IADsAccessControlList.
' Interface, therefore, displaying the current mailbox rights.
'wscript.echo "Trustee, AccessMask, ACEType, ACEFlags, Flags, ObjectType, InheritedObjectType"

For Each ace In dacl
' Display all the properties of the ACEs using the IADsAccessControlEntry interface.
    msgbox ace.Trustee & ", " & ace.AccessMask & ", " & ace.AceType & ", " & ace.AceFlags & ", " & ace.Flags & ", " & ace.ObjectType & ", " & ace.InheritedObjectType
Next

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'  The following block of code demonstrates adding a new ACE to the DACL
'  for the Exchange 2003/2000 mailbox with the Trustee specified in sTrustee,
'  which permits full control over this mailbox.
'  This is the same task that is performed by ADUnC when you follow these
'  steps to modify the properties of a user: on the Exchange Advanced tab,
'  under Mailbox Rights, click Add, select the Trustee, and then select the 
'  Full Mailbox Access Rights check box. 
'  Similarly, you can also remove ACEs from this ACL by using the IADsAccessControlEntry interfaces.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

' Template: AddAce(TrusteeName, gAccessMask, gAceType, gAceFlags, gFlags, gObjectType, gInheritedObjectType)
AddAce dacl, sTrustee, ADS_RIGHT_DS_CREATE_CHILD, _
       ADS_ACETYPE_ACCESS_ALLOWED, ADS_ACEFLAG_INHERIT_ACE, 0, 0, 0

' Add the modified DACL to the security descriptor.
oSecurityDescriptor.DiscretionaryAcl = dacl

' Save new SD onto the user.
objUser.MailboxRights = oSecurityDescriptor

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

MsgBox "Done viewing and modifying the mailboxsecurity descriptor"
'********************************************************************
'*
'* 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("AccessControlEntry")
    Ace1.AccessMask = gAccessMask
    Ace1.AceType = gAceType
    Ace1.AceFlags = gAceFlags
    Ace1.Flags = gFlags
    Ace1.Trustee = TrusteeName
    'See whether ObjectType must be set
    If CStr(gObjectType) <> "0" Then
       Ace1.ObjectType = gObjectType
    End If

    'See whether InheritedObjectType must be set.
    If CStr(gInheritedObjectType) <> "0" Then
        Ace1.InheritedObjectType = gInheritedObjectType
    End If
    dacl.AddAce Ace1

    ' Destroy objects.
    Set Ace1 = Nothing
End Function
                

REFERENCES

For more information about the latest service pack, click the following article number to view the article in the Microsoft Knowledge Base:

301378 How to obtain the latest Exchange 2000 Server service pack


For more information about other topics mentioned in this article, click the following article numbers to view the articles in the Microsoft Knowledge Base:

302926 XADM: You cannot programmatically change mailbox rights


252459 Retrieve properties of user objects with ADSI and ADO


For more information, visit the following Microsoft Developer Network Web site:

Keywords: kbhowto kbdswadsi2003swept KB310866