Error The security ID structure is invalid using VBScript to alter ACE on an address list

Hi I have written a script to alter the ACE list in an ACL for Exchange2003 I am programmaticaly trying to set Adrees Book and GAL access.
The problem is I keep getting the error
 The security ID Structure is invalid.
I am not sure how to fix this as far as I was aware Exchange2003 should reorder this for you.
this is the code I am using.


' Define Constants NB we dont want child objects to inherit
Const ADS_ACEFLAG_INHERIT_ACE = &H2
Const ADS_ACEFLAG_NO_PROPAGATE_INHERIT_ACE = &H4 'clears the inherit flag for inherited aces
Const ADS_ACETYPE_ACCESS_ALLOWED_OBJECT = &H5
Const ADS_RIGHT_GENERIC_ALL = &H10000000
Const ADS_ACETYPE_ACCESS_ALLOWED = &H5
Const ADS_ACEFLAG_ACCESS_DENIED = &H1
Const OPEN_ADDRESS_LIST = "{a1990816-4298-11d1-ade2-00c04fd8d5cd}"


' Get the object, security descriptor, and DACL
Set objAD = GetObject("LDAP://cn=Banana AB,cn=All Address Lists,cn=Address List Container,cn=SoHosted001,cn=Microsoft Exchange,cn=Services,cn=Configuration,dc=SOHOSTED001,dc=lan")
Set objSD = objAD.Get("ntSecurityDescriptor")
Set objDACL = objSD.DiscretionaryAcl

' Create the ACE and set its properties first remove authenticated users
Set objACE = CreateObject("AccessControlEntry")
objACE.Trustee = "SOHOSTED001\Authenticated Users"
objACE.AceFlags = ADS_ACEFLAG_NO_PROPAGATE_INHERIT_ACE
objACE.AceType = ADS_ACEFLAG_ACCESS_DENIED
objACE.AceType = ADS_ACETYPE_ACCESS_DENIED_OBJECT
'objACE.AccessMask = ADS_RIGHT_GENERIC_ALL

Set objACE1 = CreateObject("AccessControlEntry")
objACE1.Trustee = "SOHOSTED001\Banana GRP"
objACE1.AceFlags = ADS_ACEFLAG_INHERIT_ACE
objACE1.AceType = ADS_ACETYPE_ACCESS_ALLOWED
objACE1.AccessMask = ADS_RIGHT_READ_CONTROL
objACE1.AccessMask = ADS_RIGHT_DS_LIST_OBJECT
objACE1.AccessMask = ADS_RIGHT_DS_READ_PROP
objACE1.AccessMask = ADS_RIGHT_ACTRL_DS_LIST

Set objACE2 = CreateObject("AccessControlEntry")
objACE2.Trustee = "SOHOSTED001\Banana GRP"
objACE2.AceType = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT
objACE2.AccessMask = ADS_RIGHT_DS_CONTROL_ACCESS
objACE2.AccessMask = ADS_FLAG_OBJECT_TYPE_PRESENT
objACE2.ObjectType = OPEN_ADDRESS_LIST




' Add the ACE to the DACL object
objDACL.AddAce objACE
objDACL.AddAce objACE1
objDACL.AddAce objACE2
' Write the DACL object back to the security descriptor
objSD.DiscretionaryAcl = objDACL

' Write the security descriptor back to the AD object
objAD.Put "ntSecurityDescriptor", Array(objSD)
objAD.SetInfo

what I want to do is remove Authorised Users and add permissions for a group, in this case Banana GRP
Any advice most welcome
Thanks
LVL 1
tim_storeyAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Chris DentPowerShell DeveloperCommented:

I haven't tested any of this. But I suspect your problem is caused by this:

' Create the ACE and set its properties first remove authenticated users
Set objACE = CreateObject("AccessControlEntry")
objACE.Trustee = "SOHOSTED001\Authenticated Users"
objACE.AceFlags = ADS_ACEFLAG_NO_PROPAGATE_INHERIT_ACE
objACE.AceType = ADS_ACEFLAG_ACCESS_DENIED
objACE.AceType = ADS_ACETYPE_ACCESS_DENIED_OBJECT
'objACE.AccessMask = ADS_RIGHT_GENERIC_ALL

You care creating a new ACE with an explicit Deny rather than removing the entry from the DACL entirely. Is that really what you wanted to do? This entry has the potential (at least) to conflict with the existing ACE for that Trustee.

If you want to remove the ACE you can do so by looping through the DACL:

For Each objACE in objDACL
    If LCase(objACE.Trustee.Name) = LCase("SOHOSTED001\Authenticated Users") Then
        objDACL.RemoveACE objACE
    End If
Next

I might be wrong with objACE.Trustee.Name, it would be worth echoing that out to test it's really the value we're chasing.

You will still have to commit the DACL back to the object after this, or continue to modify the DACL for the other users.

If that fails, try adding your ACE entries one at a time to see if any one of them produces an error.

Chris
0
tim_storeyAuthor Commented:
Thanks Chris,

well I have tried this and found that for one thing I should be using NT Authority as the trustee well if I loop through the ACE's and echo them that's how its listed

So I ran a loop to remove the trustee as you suggested

and I am now getting a type mismatch at the objDACL.AddAce objACE line

I am wondering if this is because I am trying to remove a NT Authority account ?

and I am still getting the security ID structure is invalid if I try adding the other ACE's

any clues?

Tim
0
Chris DentPowerShell DeveloperCommented:

I'd make it one step at a time then. We also need to alter your AccessMasks, I should have noticed that earlier. Access Masks are computed by adding the constant values you're using together. See the modification below.


' Get the object, security descriptor, and DACL
Set objAD = GetObject("LDAP://cn=Banana AB,cn=All Address Lists,cn=Address List Container,cn=SoHosted001,cn=Microsoft Exchange,cn=Services,cn=Configuration,dc=SOHOSTED001,dc=lan")
Set objSD = objAD.Get("ntSecurityDescriptor")
Set objDACL = objSD.DiscretionaryAcl

For Each objACE in objDACL
    If LCase(objACE.Trustee.Name) = LCase("SOHOSTED001\NT Authority") Then
        objDACL.RemoveACE objACE
    End If
Next

' Put it back in to test the changes we're making:

' Write the DACL object back to the security descriptor
objSD.DiscretionaryAcl = objDACL

' Write the security descriptor back to the AD object
objAD.Put "ntSecurityDescriptor", Array(objSD)
objAD.SetInfo

' Request a new copy of the DACL

Set objSD = objAD.Get("ntSecurityDescriptor")
Set objDACL = objSD.DiscretionaryAcl

Set objACE1 = CreateObject("AccessControlEntry")
objACE1.Trustee = "SOHOSTED001\Banana GRP"
objACE1.AceFlags = ADS_ACEFLAG_INHERIT_ACE
objACE1.AceType = ADS_ACETYPE_ACCESS_ALLOWED
objACE1.AccessMask = ADS_RIGHT_READ_CONTROL + ADS_RIGHT_DS_LIST_OBJECT +_
                                     ADS_RIGHT_DS_READ_PROP + ADS_RIGHT_ACTRL_DS_LIST

Set objACE2 = CreateObject("AccessControlEntry")
objACE2.Trustee = "SOHOSTED001\Banana GRP"
objACE2.AceType = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT
objACE2.AccessMask = ADS_RIGHT_DS_CONTROL_ACCESS + ADS_FLAG_OBJECT_TYPE_PRESENT
objACE2.ObjectType = OPEN_ADDRESS_LIST

objDACL.AddAce objACE1
objDACL.AddAce objACE2
' Write the DACL object back to the security descriptor
objSD.DiscretionaryAcl = objDACL

' Write the security descriptor back to the AD object
objAD.Put "ntSecurityDescriptor", Array(objSD)
objAD.SetInfo



Remember that when we did this, we also needed to remove "objDACL.AddAce objACE" because we didn't create that one when we used the looping method to remove the unwanted ACE.

Chris
0
Making Bulk Changes to Active Directory

Watch this video to see how easy it is to make mass changes to Active Directory from an external text file without using complicated scripts.

tim_storeyAuthor Commented:
Thanks Chris,

well I am still getting security ID structure is invalid with ACE1 and ACE2 but not with ACE
I am pretty sure that the remove loop is working however this permission is an inherited one.

If I were to remove it manually I would have to disable Inherit in the Advanced permissions.... so this Ace_Flag needs to be set correctly, I think.....

Tim
0
Chris DentPowerShell DeveloperCommented:

Okay, I'll have another look in the morning. I have some sample code for disabling Inheritance I wrote quite a while ago. Although it's File System inheritance, I'll check that as well.

Chris
0
Chris DentPowerShell DeveloperCommented:

Okie dokie, lets try and get to the bottom of this one.

Windows permission structures are complex beasts, there never seems enough documentation to do what you want (or the MSDN links come back with "Content not found").

If this doesn't play you'll have to give me another day to get a test environment setup at home. I haven't got around to installing Exchange there and I'm unwilling to test permission setting on the lists here.

First of all, we need to deal with that Inheritance Flag:


Const SE_DACL_PROTECTED = &H1000

' Get the Object and Security Descriptor

Set objAD = GetObject("LDAP://cn=Banana AB,cn=All Address Lists,cn=Address List Container,cn=SoHosted001,cn=Microsoft Exchange,cn=Services,cn=Configuration,dc=SOHOSTED001,dc=lan")
Set objSD = objAD.Get("ntSecurityDescriptor")

' Disable Inheritance on the Security Descriptor

intControl = objSD.Control
objSD.Control = intControl Or SE_DACL_PROTECTED


That done we must create an entirey new DACL, the parent Address List won't have anything remotely useful now. In order to do that we must copy the DACL from the Parent:


' Get the SD from the Parent

Set objParent = GetObject("LDAP://CN=All Address Lists,CN=Address List Container," &_
      "cn=SoHosted001,cn=Microsoft Exchange,cn=Services,cn=Configuration,dc=SOHOSTED001,dc=lan")
Set objParentSD = objParent.Get("ntSecurityDescriptor")
Set objPatentDACL = objParentSD.DiscretionaryAcl

' Hold a Copy of the Parents DACL in Memory

Set objCopiedDACL = objParentDACL.CopyAccessList()


Okay, now we've got our copy we can modify the ACL so it does what we want:


' Loop through the Copied ACL to remove the unwanted ACE

For Each objACE in objCopiedDACL
      If objACE.Trustee = "NT Authority\Authenticated Users" Then
            objCopiedDACL.RemoveACE objACE
      End If
Next


Now we can add in our new Entries. I think we're going to have to extend the ones used above. I'll continue with that bit in the next post.

Chris
0
Chris DentPowerShell DeveloperCommented:

No we're not, I'm just being blind. Must get more coffee.

MS actually can help us out here though, they have pre-built functions for adding an ACE to a DACL, and another to reorder the DACL (if required). Conveniently all displayed in this article which incorporates what you're doing here:

http://msdn2.microsoft.com/en-us/library/aa123957.aspx

Unfortunately the example of this on MSDN lacks the values for the Masks they're using, without being able to apply them I can't reverse to see what it's built out of. So we have that obscure 256


AddAce objCopiedDACL, "SOHOSTED001\Banana GRP", 131220, 0, 2, 0, 0, 0
AddAce objCopiedDACL, "SOHOSTED001\Banana GRP", 256, 5, 2, 1, OPEN_ADDRESS_LIST, 0


MS also add in a ACE for an Administrator, you may consider doing that as well:


AddAce objCopiedDACL, "SOHOSTED001\<Admin>", 131220, 0, 2, 0, 0, 0
AddAce objCopiedDACL, "SOHOSTED001\<Admin>", 256, 5, 2, 1, OPEN_ADDRESS_LIST, 0


We should also Re-Order the ACE. I don't think we're going to able to avoid it, although you're welcome to try applying the existing DACL back to the SD.


Set objDACL = ReorderACL(objCopiedDACL)

' Write the DACL object back to the security descriptor
objSD.DiscretionaryAcl = objDACL

' Write the security descriptor back to the AD object
objAD.Put "ntSecurityDescriptor", Array(objSD)
objAD.SetInfo


And these are VbScript versions of the two functions called above (AddAce and ReorderACL):


Function AddAce(objDACL, strTrustee, intAccessMask, intAceType,_
            intAceFlags, intFlags, strObjectType, strInheritedObjectType)

      Dim objACE

      Set objACE = CreateObject("AccessControlEntry")
      objACE.AccessMask = intAccessMask
      objACE.AceType = intAccessType
      objACE.AceFlags = intAceFlags
      objACE.Flags = intFlags
      objACE.Trustee = strTrustee

      If CStr(strObjectType) <> "0" Then
           objACE.ObjectType = strObjectType
      End If

      If CStr(strInheritedObjectType) <> "0" Then
          objACE.InheritedObjectType = strInheritedObjectType
      End If

      objDACL.AddAce objACE
      Set objACE = Nothing
End Function

Function ReorderACL(objDacl)
      Dim objNewSD, objNewDACL, objImpDenyDACL, objImpDenyObjectDACL
      Dim objImpAllowDACL, objImpAllowObjectDACL, objACE

      Const ADS_ACETYPE_ACCESS_DENIED = &H1
      Const ADS_ACETYPE_ACCESS_DENIED_OBJECT = &H6
      Const ADS_ACETYPE_ACCESS_ALLOWED = &H0
      Const ADS_ACETYPE_ACCESS_ALLOWED_OBJECT = &H5
      Const ADS_ACEFLAG_INHERITED_ACE = &H10

      Set objNewSD = CreateObject("SecurityDescriptor")
      Set objNewDACL = CreateObject("AccessControlList")

      Set objImpDenyDACL = CreateObject("AccessControlList")
      Set objImpDenyObjectDACL = CreateObject("AccessControlList")
      Set objImpAllowDACL = CreateObject("AccessControlList")
      Set objImpAllowObjectDACL = CreateObject("AccessControlList")

      For Each objACE In objDACL
            Select Case objACE.AceType
                  Case ADS_ACETYPE_ACCESS_DENIED
                        objImpDenyDACL.AddAce objACE
                  Case ADS_ACETYPE_ACCESS_DENIED_OBJECT
                        objImpDenyObjectDACL.AddAce objACE
                  Case ADS_ACETYPE_ACCESS_ALLOWED
                        objImpAllowDACL.AddAce objACE
                  Case ADS_ACETYPE_ACCESS_ALLOWED_OBJECT
                        objImpAllowObjectDacl.AddAce objACE
                  Case Else
                        WScript.Echo "Bad ACE"
            End Select
      Next

      ' Combine the ACEs in the Proper Order
      ' Implicit Deny.
      For Each objACE In objImpDenyDACL
            objNewDACL.AddAce objACE
      Next

      ' Implicit Deny Object.
      For Each objACE In objImpDenyObjectDACL
            objNewDACL.AddAce objACE
      Next

      ' Implicit Allow.
      For Each objACEace In objImpAllowDACL
            objNewDACL.AddAce objACE
      Next

      ' Implicit Allow Object.
      For Each objACE In objImpAllowObjectDACL
            objNewDACL.AddAce objACE
      Next

      objNewDACL.AclRevision = objDACL.AclRevision

      Set ReorderACL = objNewDACL

      Set objNewDACL = Nothing
      Set objImpAllowObjectDACL = Nothing
      Set objImpAllowDACL = Nothing
      Set objImpDenyObjectDACL = Nothing
      Set objImpDenyDACL = Nothing
      Set objNewSD = Nothing
End Function
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
tim_storeyAuthor Commented:
Whew Chris,
I am not worthy....
thanks for the effort, will give it all a whirl, been bashing my head on this for about 2 weeks now....

Tim
0
Chris DentPowerShell DeveloperCommented:

It's a pretty solid thing to bash your head against as well :)

Chris
0
tim_storeyAuthor Commented:
It works,
the functions add and reorder perfectly, good stuff.

you get the points, deservedly, but I need to go a little further.....  ;)

I  need to try and figure out the intAccess mask's meaning, it would be good to know those values as I need to adapt this to use on other objects.  I am guessing this value is created form Or'ing the bitflags of the AccesMasks together?

So how did you get to intAccessMask = 131220 ? and as you say the mysterious 256

Would I be on the right track to Or together the AccessMasks and then see how it all comes out then?

Tim
0
Chris DentPowerShell DeveloperCommented:

You would, yes.

MS used to have a reference to all of them in MSDN but in a really helpful way it comes back with the "Content Not Found" mentioned above.

That leaves us with reverse engineering. Make the change and see what's changed.

I'll see if I can find another reference, and if I have time I'll install a virtual server and Exchange tonight so we can take it apart in a little more detail.

Chris
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
VB Script

From novice to tech pro — start learning today.