Microsoft KB Archive/322890

From BetaArchive Wiki

Article ID: 322890

Article Last Modified on 10/16/2007



APPLIES TO

  • Microsoft Active Directory Service Interfaces 2.5
  • Microsoft Exchange 2000 Server Service Pack 2



This article was previously published under Q322890


SUMMARY

This article demonstrates how to associate an external account with an Exchange 2000 mailbox.

The following conditions must exist:

  • The external account must be a Windows NT user or a user in an Active Directory that is in a different forest from where the Exchange 2000 server resides.
  • There must be a trust between the domain where the NT or Active Directory user object resides and the domain where the Exchange user object resides.

To do this, you must modify attributes on a mailbox-enabled user object in the Active Directory by specifying the external account as its Master Account.

To associate an external account with a mailbox

To programmatically associate an external account with an Exchange 2000 mailbox, follow these steps:

  1. Create a mailbox-enabled user account in the Windows 2000/Exchange 2000 domain (if the account is not already created).


Note After you create this user account, you must disable this user account.

  1. Create a user account in either a trusted Windows NT 4 domain or in a trusted Active Directory forest (if an account is not already created).
  2. On the mailbox-enabled user account that you created in step 1, set the msExchMasterAccountSID attribute to the security identifier (in its raw mode) of the NT 4 or Active Directory user.
  3. On the mailbox-enabled user account that you created in step 1, modify the security descriptor to add an access control entry (ACE) with the trustee set to the external NT or Active Directory account, and with rights to Read, Associated External Account, and Full Mailbox Access.

Code sample requirements

  • You must run the code on an Exchange 2000 SP2 server or on an Exchange 2000 SP1 server with hotfix

    302926 You cannot programmatically change mailbox rights

  • You must register the ADsSecurity.dll file on the system that is executing the script.

    To obtain the most current version of ADsSecurity.dll, install the most current version of the Microsoft Platform Software Development Kit (SDK) and use RegSvr32 (command: regsvr32 adssecurity.dll) to register the .dll file.

Code sample

The following code sample demonstrates this process:

'********************************************************************
'*
'* 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)
' Bubble Error to Calling Function
'On Error Resume Next
    Dim Ace1
    ' Add new ACE.
    Set Ace1 = CreateObject("AccessControlEntry")
    Ace1.AccessMask = gAccessMask
    Ace1.AceType = gAceType
    Ace1.AceFlags = gAceFlags
    Ace1.Flags = gFlags
    Ace1.Trustee = TrusteeName
    'Determine whether ObjectType has to be set
    If CStr(gObjectType) <> "0" Then
       Ace1.ObjectType = gObjectType
    End If

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

    ' Kill objects.
    Set Ace1 = Nothing
End Function

'********************************************************************
'*
'* Function ReorderACL(objDACL)
'*
'* Purpose: Reorders a DACL properly
'* Input:       objDACL                     Access Control List (Object)
'*
'* Output:  Object - Reordered DACL
'*
'********************************************************************

Function ReorderACL(objDACL, bMakeExplicit)
    ' Dim objects.
    Dim ImpDenyDacl, ImpDenyObjectDacl, InheritedDacl, ImpAllowDacl, ImpAllowObjectDacl
    Dim objSD, newDACL
    ' Dim other variables.
    Dim ace
    
    ' Set constants.
    Const ADS_ACEFLAG_INHERITED_ACE = &H10
    Const ADS_ACETYPE_ACCESS_ALLOWED = &H0
    Const ADS_ACETYPE_ACCESS_DENIED = &H1
    Const ADS_ACETYPE_ACCESS_ALLOWED_OBJECT = &H5
    Const ADS_ACETYPE_ACCESS_DENIED_OBJECT = &H6
    
    ' Create the new DACL.
    Set objSD = CreateObject("SecurityDescriptor")
    
    ' Create the ACL objects.
    Set newDACL = CreateObject("AccessControlList")
    Set ImpDenyDacl = CreateObject("AccessControlList")
    Set ImpDenyObjectDacl = CreateObject("AccessControlList")
    Set InheritedDacl = CreateObject("AccessControlList")
    Set ImpAllowDacl = CreateObject("AccessControlList")
    Set ImpAllowObjectDacl = CreateObject("AccessControlList")

    ' Loop through the original DACL.
    For Each ace In objDACL
    If bMakeExplicit Then
         If ((ace.AceFlags And ADS_ACEFLAG_INHERITED_ACE) = ADS_ACEFLAG_INHERITED_ACE) Then
            ace.AceFlags = ace.AceFlags Xor ADS_ACEFLAG_INHERITED_ACE
        End If
   Else
     ' The order of inherited ACEs does not matter.  Because you are
     ' adding them to the top of a new list, when they are added back
     ' to the DACL for the object, they will be in the same order as 
     ' originally.  This is a positive side affect of addin items or a LIFO
     ' (Last In First Out) type list'
     InheritedDacl.AddAce ace
   End If
     ' You have an implicit ACE; it belongs in the correct pool.
     Select Case ace.AceType
         Case ADS_ACETYPE_ACCESS_ALLOWED
             ImpAllowDacl.AddAce ace
         Case ADS_ACETYPE_ACCESS_DENIED
             ImpDenyDacl.AddAce ace
         Case ADS_ACETYPE_ACCESS_ALLOWED_OBJECT
             ImpAllowObjectDacl.AddAce ace
         Case ADS_ACETYPE_ACCESS_DENIED_OBJECT
             ImpDenyObjectDacl.AddAce ace
         Case Else
            'Bad Ace, but let's just leave it out for now.
      End Select
   Next
    '
    ' Combine the ACEs in the proper order.
    '   Implicit Deny
    '   Implicit Deny Object
    '   Implicit Allow
    '   Implicit Allow Object
    '   Inherited ACEs
    '
    ' Implicit Deny
    For Each ace In ImpDenyDacl
       newDACL.AddAce ace
    Next
    
    ' Implicit deny object.
    For Each ace In ImpDenyObjectDacl
       newDACL.AddAce ace
    Next
    
    ' Implicit allow.
    For Each ace In ImpAllowDacl
       newDACL.AddAce ace
    Next
    
    ' Implicit allow object.
    For Each ace In ImpAllowObjectDacl
       newDACL.AddAce ace
    Next

    ' Inherited ACEs.
    For Each ace In InheritedDacl
       newDACL.AddAce ace
    Next
    
    'Set the Appropriate revision level for the DACL.
    newDACL.AclRevision = objDACL.AclRevision

    ' Return properly ordered DACL.
    Set ReorderACL = newDACL
    
    ' Kill objects.
    Set newDACL = Nothing
    Set InheritedDacl = Nothing
    Set ImpAllowObjectDacl = Nothing
    Set ImpAllowDacl = Nothing
    Set ImpDenyObjectDacl = Nothing
    Set ImpDenyDacl = Nothing
    Set objSD = Nothing
End Function
Private Sub Command1_Click()
Dim objUser As IADsUser
Dim oSID As New ADsSID
Dim RawSID
Dim oSecurityDescriptor As New SecurityDescriptor
Dim dacl As New AccessControlList
Dim ace As New AccessControlEntry
' You have to change these variables according to your environment.
' This is the external account.
sWinNTPath_Ext_Account = "WinNT://NTDomainName/NTDomainUser"<BR/>
' This is the external account.
sAssocNTAccount = "NTDomainName\NTDomainUser"
' This is the Windows 2000 mailbox-enabled object (Exchange mailbox).
sEx2kMbxPath = "LDAP://Win2KDC/CN=testarticle,cn=users,DC=MyWin2KDomain,DC=com"
' Get directory user object.
Set objUser = GetObject(sEx2kMbxPath)
' User ADsSecurity.dll to determine the user's SID from the NT domain.
oSID.SetAs ADS_SID_WINNT_PATH, sWinNTPath_Ext_Account
RawSID = oSID.GetAs(ADS_SID_RAWSTRING)
' Set msExchMasterAccountSID.
' This is the same task that is performed by ADUnC when checking the "Associated External Account" check box.
' Under the Mailbox Rights in the Exchange Advanced tab on the properties of a user.
objUser.Put "msExchMasterAccountSID", RawSID
objUser.SetInfo

Set oSecurityDescriptor = objUser.MailboxRights
On Error Resume Next
Set oSecurityDescriptor = objUser.Get("msExchMailboxSecurityDescriptor")
If (Err) Then
Debug.Print "The msExchMailboxSecurityDescriptor attribute is empty."
Debug.Print "Hence this user's mailbox does not have any mailbox rights set on it."
Debug.Print "Error (" & Err.Number & "): " & Err.Description
Exit Sub
End If
' Extract the discretionary access control list (ACL) using the IADsSecurityDescriptor interface.
Set dacl = oSecurityDescriptor.DiscretionaryAcl
Debug.Print "Here are the existing ACEs the mailbox's DACL - "
' Enumerate all the access control entries (ACEs) in the ACL using the IADsAccessControlList interface.
' Hence displaying the current mailbox rights.
For Each ace In dacl
' Display all the ACEs' properties using the IADsAccessControlEntry interface.
Debug.Print ace.Trustee & ", " & ace.AccessMask & ", " & ace.AceType & ", " & ace.AceFlags & ", " & ace.Flags & ", " & ace.ObjectType & ", " & ace.InheritedObjectType
Next
' Adding a new ACE for Full Control to allow "Full Control" for the external account over this mailbox.
' This is the same task that is performed by ADUnC when checking the "Full Control" Rights check box.
' Under the Mailbox Rights in the Exchange Advanced tab on the properties of a user.
AddAce dacl, sAssocNTAccount, (ADS_RIGHT_DELETE + ADS_RIGHT_ACTRL_DS_LIST + ADS_RIGHT_DS_CREATE_CHILD + ADS_RIGHT_READ), _
ADS_ACETYPE_ACCESS_ALLOWED, ADS_ACEFLAG_INHERITED_ACE, 0, 0, 0
' Reorder ACEs in the DACL.
Set dacl = ReorderACL(dacl, True)
' Add new DACL to the Security Descriptor.
oSecurityDescriptor.DiscretionaryAcl = dacl
' Save new SD onto the user.
objUser.MailboxRights = Array(oSecurityDescriptor)
objUser.SetInfo
MsgBox "Done"
End Sub

                

REFERENCES

For more information about how to do this by using the Exchange System Manager, click the following article number to view the article in the Microsoft Knowledge Base:

278888 How to associate an Exchange 2000 mailbox or an Exchange 2003 mailbox with a Windows NT 4.0 account


Keywords: kbdswadsi2003swept kbhowtomaster KB322890