Strange behavior when setting ACL on NTFS Folder

From: Yuri Niyazov (yuricakespam-google_at_yahoo.com)
Date: 03/25/04

  • Next message: [MS] Scott McNairy: "Re: 16-bit process"
    Date: 25 Mar 2004 13:28:11 -0800
    
    

    I am experiencing the following strange behavior on NTFS, Windows 2000
    Server SP3.

    First, I, logged in as Administrator, manually create a folder called
    C:\acltest, on it I remove all inherited ACE entries and create a
    "Everyone" "Full Control" "This Folder Only"
    ACE entry on it, using the right-click properties Explorer UI.

    Then, I create a "patient" folder under acltest using the first pasted
    below vbs script (acltest-createfolder.vbs)

    Then, I have another VBS WMI script set up certain read/write
    permissions for on the patient folder for users. That script is
    acl-script.vbs, pasted below.

    I execute both of these scripts at the console. I then right click on
    C:\acltest\patient and check the list of permissions in Properties
    dialog box. Everything comes out as I want it, including the "modify"
    entry for the user.

    Now, without doing anything else, I, as the user added (in this case
    "yuri"), use terminal services and connect to this machine from
    another workstation. I try to open "C:\acltest\patient" and I receive
    an "Access Denied" entry - something totally unexpected, since the
    permissions tell me that yuri is allowed to look at the contents of
    the folder. Now, I go back to the console, and using the Properties
    dialog box add some completely different ACE entry to
    C:\acltest\patient - something that should have no effect on the
    current situation, for example, a "Guest" "Deny Delete" "Subfolders
    only" entry. Click OK, and now, go back to the terminal services as
    "yuri" and try to open C:\acltest\patient folder - and all of a
    sudden, it's opened.

    The behavior seems to suggest that I am doing something that, even
    though it adds ACE entries into the Properties dialog box, it doesn't
    actually write (flush?) them out into whatever Security mechanism NTFS
    uses. After I click "OK" in properties dialog box, everything is
    probably re-written out properly.

    Further information about my setup: the machine is a Active Directory
    Domain Controller, yuri is a member of Domain Users, and is not a
    member of Power Users or Administrators. I did modify "Domain
    Controller Security Policy" to allow common users to use terminal
    services to login to the Domain Controller.

    Files (I am posting from google, I apologize about the wrapping. if it
    is a problem, email me and I will send them as files):

    acltest-createfolder.vbs:

    'START
    MsgBox "Requirements: create a C:\acltest folder." & vbCrLF & "Make
    sure that it is not inheriting any parent ACEs." _
      & vbCrLf & "Add on it the following entry: 'Everyone' 'Full Control'
    'This Folder Only'"

    set fso = CreateObject("Scripting.FileSystemObject")
    fso.CreateFolder "C:\acltest\patient"
    'END

    acl-script.vbs:

    'START
    Msgbox "start"
    r = SetPermissions("C:\acltest\patient", "Everyone", "DELETE", 1, 0)
    a = SetPermissions("C:\acltest\patient", "yuri", "ACCESS", 0, 3)
    if r = 1 or a = 1 then
        msgbox "error"
    end if
    Msgbox "stop"

    '#############################

    'Function SetPermissions

    'Variables
      'ExplicitPath (i.e. e:\data\folder - use GetExplicitPathFromUNC
    function if necessary)
      'UserOrGroupName
      'Permission (Read,Modify,Full)
      
    'Returns
      '0 if successful
      '1 if failed

      Function SetPermissions(ExplicitPath,UserOrGroupName,Permission,AceType,AceFlags)
      
        Found = 0

    'Create the security object. You have to invoke the Security and
    Restore Priviledges in the
    'script to make changes to ACEs
        Set objSecurity =
    GetObject("winmgmts:\\.\root\cimv2:Win32_LogicalFileSecuritySetting='"
    & ExplicitPath & "'")

        If objSecurity.GetSecurityDescriptor(objSD) = 0 Then
        Else
            MsgBox "Problem"
            SetPermissions = 1
            Exit Function
        End If

    'Determine which Permission to be applied
    ' If ucase(Permission) = "READ" Then PermissionBitMask = 1179817
    ' If ucase(Permission) = "MODIFY" Then PermissionBitMask = 1245631
    ' If ucase(Permission) = "FULL" Then PermissionBitMask = 2032127
        If ucase(Permission) = "ACCESS" Then PermissionBitMask = 197055
        If ucase(Permission) = "DELETE" Then PermissionBitMask = 65536
      
    'Create the Security Descriptor object (objSD) and then add, modify,
    or delete ACEs inside
    'the DACL.

    'If Found = 1, then the specified User or Group was modified. Use
    SetSecurityDescriptor
    'to save the changes.
        If Found = 1 Then
          If objSecurity.SetSecurityDescriptor(objSD) = 0 Then
            SetPermissions = 0
          Else
            SetPermissions = 1
            Err.Clear
          End If
        Else
        
    'Specified User or Group was NOT found in the existing DACL. Add a new
    ACE to the
    'DACL

    '(1) Get the SID of the user or group account.

    'Create a WMI object on the local computer (Assuming the local
    computer is in the
    'same domain (or in a trusted domain) as the one specified
          Set objWMI = GetObject("winmgmts:\\.\root\cimv2")

    'Get a collection of Users objects, using ExecQuery
          Set colUsers = objWMI.ExecQuery("SELECT * FROM WIN32_ACCOUNT
    WHERE Name = '" & UserOrGroupName & "'")
      
    'The collection should only have one user in it. Loop through the one
    user collection
    'and create a user object
          For Each UserName in colUsers
            Set objUserName = UserName
          Next
      
    'Next, we need both the binary and string representation of the user's
    SID to create a new
    'Win32_Trustee. objUser.SID only returns the string version. Create a
    Win32_SID object by
    'referencing the objUser's SID
          Set objSID = objWMI.Get("Win32_SID.SID='" & objUserName.SID &
    "'")

    '(2) Create a new blank Win32_Trustee object, and set it's properties
    to the appropriate
    ' values

    'Create a new blank Win32_Trustee object
          Set objTrusteeClass = objWMI.Get("Win32_Trustee")
          Set objTrustee = objTrusteeClass.SpawnInstance_()
      
    'Set the properties
          objTrustee.Domain = objSID.ReferencedDomainName
          objTrustee.Name = objSID.AccountName
          objTrustee.SID = objSID.BinaryRepresentation
          objTrustee.SidLength = objSID.SidLength
          objTrustee.SIDString = objSID.SID
      
      
    '(3) Create a new blank Win32_ACE object, and set it's properties to
    the appropriate
    ' values. The Trustee property should point to the newly created
    Win32_Trustee

    'Create a new blank Win32_ACE object
          Set objACEClass = objWMI.Get("Win32_ACE")
          Set objACE = objACEClass.SpawnInstance_()
      
    'Set the properties
          objACE.AccessMask = PermissionBitMask
          objACE.Trustee = objTrustee
          objACE.AceType = AceType
          objACE.AceFlags = AceFlags
      

    '(4) Add the ACE to the DACL. This is the hard part, because to keep
    the existing
    ' ACEs means we have to resize the array. The DACL array is not a
    dynamic array, so
    ' the solution is to create a new array of the right size, copy the
    explicit contents
    ' of the existing DACL (and the new ACE) into it, and then replace
    the existing
    ' DACL with the new one.

    'Create a Dictionary object (a hash). We're using a dictionary object,
    because it
    'can be dynamically resized
          Set objDictionary = CreateObject("Scripting.Dictionary")

    'Loop through the DACL array and populate the Dictionary object only
    with ACE objects
    'that have EXPLICIT PERMISSIONS. This can be tested by checking the
    AceFlags property.
    'If the 5th bit (16) is set to 1 then, the permission is inherited
    (See AceFlags
    'description above.
    'Doesn't matter what the Dictionary key is, The corresponding item is
    all that matters,
    'being the ACE of the existing DACL. We just use i as the key here
          For i = LBound(objSD.DACL) to UBound(objSD.DACL)
            If NOT objSD.DACL(i).AceFlags AND 16 Then
              objDictionary.Add i, objSD.DACL(i)
            End If
          Next
      
    'Add the new ACE.
          objDictionary.Add "Empty Key", objACE
      
    'Use the items method to return a list of just the items, and
    overwrite the existing
    'DACL with the new list of ACEs
          objSD.DACL = objDictionary.Items
      

    '(5) Finally, write back the Security Descriptor
            objSD.ControlFlags = 4
          If objSecurity.SetSecurityDescriptor(objSD) = 0 Then
            SetPermissions = 0
          Else
            SetPermissions = 1
            Err.Clear
          End If
        
        End If

      End Function
      
    '#############################
    'END


  • Next message: [MS] Scott McNairy: "Re: 16-bit process"

    Relevant Pages

    • Strange behavior when setting ACL on NTFS Folder
      ... ACE entry on it, using the right-click properties Explorer UI. ... I create a "patient" folder under acltest using the first pasted ... actually write them out into whatever Security mechanism NTFS ... 'Specified User or Group was NOT found in the existing DACL. ...
      (microsoft.public.scripting.vbscript)
    • Re: Customizable security in NTFS? Needs to be extensible & dynamic
      ... making a user a member of a group and adding ACEs for that group to the DACL of a folder does not result in immediate access to the folder for the user. ... Making a user a member of a group results in the user becoming "security equivalent" to the group. ... When effective access rights are calculated, full traversal from the root of the volume, as well as summation of all security equivalences, are both performed. ...
      (microsoft.public.development.device.drivers)
    • Re: Customizable security in NTFS? Needs to be extensible & dynamic
      ... immediate access to the folder for the user. ... implementation is used when computing effective access rights. ... user a member of a group results in the user becoming "security ... ACEs to a DACL on NTFS] can be assigned dynamically in the file system on ...
      (microsoft.public.development.device.drivers)
    • Re: ACLs Security
      ... SDDL (security descriptor definition language). ... There is also IO for inherit only (that is, the ACE ... >> the folder or file to get the 'under the hood' ACE identifyer. ...
      (microsoft.public.win2000.security)
    • SetSecurityDescriptor erases entire DACL
      ... I am trying to figure out how to add an ACE to the DACL for a particular folder during our install process. ... '* Pull the object's security descriptor, replace it's DACL, and send it back ...
      (microsoft.public.win32.programmer.wmi)