Atlanta Custom Software Development 

 
   Search        Code/Page
 

User Login
Email

Password

 

Forgot the Password?
Services
» Web Development
» Maintenance
» Data Integration/BI
» Information Management
Programming
  Database
Automation
OS/Networking
Graphics
Links
Tools
» Regular Expr Tester
» Free Tools


The Win32 Application Programming Interface (API) provides two sets of APIs for working with security descriptors and access control lists (ACLs): low-level and high-level. This series of articles provide a complete set of Microsoft Visual Basic code samples that use low-level access control APIs to create, as well as modify, an existing discretionary ACL (DACL) on a kernel object, user object, shared resource (such as a shared folder or shared printer), registry key, or printer.

In this article we will learn how to use Visual Basic to handle user object (Desktop,Windows...) security using APIs

Other articles in this series are

Handling NTFS Permissions Part-1 (handling kernel object permissions)
Handling NTFS Permissions Part-3 (handling shared resource permissions)
Handling NTFS Permissions Part-4 (handling registry key permissions)
Handling NTFS Permissions Part-5 (handling printer permissions)


The UpdatePermissionsOfUserObject function in the sample code uses the GetUserObjectSecurity() and SetUserObjectSecurity() functions to modify an existing DACL of any user object. UpdatePermissionsOfDesktop is used to call this helper function to modify permissions of the "Default" desktop in the current window station.

This example uses the following generic structure to represent the permissions for a user or group account

Click here to copy the following block
Public Type AccountPerm
  AccountName As String
  AccessMask As Long
  AceFlags As Byte
  AceType As Byte
  pSid As Long
  SidPassedByCaller As Boolean
End Type


where AccountName is any user or group account name, and AccessMask is any of the generic or object-specific access masks. All the access mask constants for any securable object are defined in the sample code. AceFlags and AceType structure members have the same values as documented in the ACE_HEADER data structure in the Microsoft Platform SDK.

As demonstrated in some of the code samples available through the preceding link, the caller can specify an array of AccountPerm structures to either construct a new security descriptor or add to an existing security descriptor of any securable object. If the caller wants to pass a well known SID, the caller can allocate the SID by using the AllocateAndInitializeSid() function and then specify it in the pSid structure member, with SidPassedByCaller set to True.

Step-By-Step Example

- First step to test this example is create 3 User accounts (User1, User2 and User3) as shown below



- Create a standard exe project
- Add a module to the project
- Place one command button on the form1
- Place the following code in form1 code window

Form1.frm

Click here to copy the following block
Private Sub Command1_Click()
  Dim success As Boolean
  success = UpdatePermissionsOfDesktop
  If success = False Then
    MsgBox "Error in UpdatePermissionsOfDesktop", vbCritical
  Else
    MsgBox "Permissions Applied to desktop WinSta0\Default", vbInformation
  End If
End Sub

Private Sub Form_Load()
  Command1.Caption = "<< Apply Permissions"
End Sub

- Place the following code in Module1

Module1.bas

Click here to copy the following block
Option Explicit

' Constants used within our API calls. Refer to the MSDN for more
' information on how/what these constants are used for.

' Memory constants used by various memory API calls.
Private Const LMEM_FIXED = &H0
Private Const LMEM_ZEROINIT = &H40
Private Const LPTR = (LMEM_FIXED + LMEM_ZEROINIT)

'Generic Access Rights
Public Const GENERIC_ALL = &H10000000
Public Const GENERIC_READ = &H80000000
Public Const GENERIC_EXECUTE = &H20000000
Public Const GENERIC_WRITE = &H40000000

'Standard Access Rights
Public Const DELETE = &H10000
Public Const READ_CONTROL = &H20000
Public Const WRITE_DAC = &H40000
Public Const WRITE_OWNER = &H80000
Public Const SYNCHRONIZE = &H100000
Public Const STANDARD_RIGHTS_REQUIRED = &HF0000
Public Const STANDARD_RIGHTS_READ = READ_CONTROL
Public Const STANDARD_RIGHTS_WRITE = READ_CONTROL
Public Const STANDARD_RIGHTS_EXECUTE = READ_CONTROL
Public Const STANDARD_RIGHTS_ALL = &H1F0000
Public Const SPECIFIC_RIGHTS_ALL = &HFFFF&
Public Const ACCESS_SYSTEM_SECURITY = &H1000000
Public Const MAXIMUM_ALLOWED = &H2000000

' Constants to be used in API calls. Refer to the MSDN for more
' information on how/what these constants are used for.
Private Const DACL_SECURITY_INFORMATION = &H4
Private Const SECURITY_DESCRIPTOR_REVISION = 1
Private Const SECURITY_DESCRIPTOR_MIN_LENGTH = 20
Private Const SD_SIZE = (65536 + SECURITY_DESCRIPTOR_MIN_LENGTH)
Private Const ACL_REVISION2 = 2
Private Const ACL_REVISION = 2
Private Const MAXDWORD = &HFFFFFFFF
Private Const SidTypeUser = 1
Private Const AclSizeInformation = 2

' The following are the inherit flags that go into the AceFlags
' field of an Ace header.
Public Const OBJECT_INHERIT_ACE = &H1
Public Const CONTAINER_INHERIT_ACE = &H2
Public Const NO_PROPAGATE_INHERIT_ACE = &H4
Public Const INHERIT_ONLY_ACE = &H8
Public Const INHERITED_ACE = &H10
Public Const VALID_INHERIT_FLAGS = &H1F

' The following are the security descriptor flags.
Private Const SE_DACL_AUTO_INHERIT_REQ = &H100
Private Const SE_SACL_AUTO_INHERIT_REQ = &H200
Private Const SE_DACL_AUTO_INHERITED = &H400
Private Const SE_SACL_AUTO_INHERITED = &H800
Private Const SE_DACL_PROTECTED = &H1000
Private Const SE_SACL_PROTECTED = &H2000

' Type of ACE being added.
Public Const ACCESS_ALLOWED_ACE_TYPE = 0
Public Const ACCESS_DENIED_ACE_TYPE = 1

' WindowStation and Desktop access masks
Public Const WINSTA_ENUMDESKTOPS = &H1&
Public Const WINSTA_READATTRIBUTES = &H2&
Public Const WINSTA_ACCESSCLIPBOARD = &H4&
Public Const WINSTA_CREATEDESKTOP = &H8&
Public Const WINSTA_WRITEATTRIBUTES = &H10&
Public Const WINSTA_ACCESSGLOBALATOMS = &H20&
Public Const WINSTA_EXITWINDOWS = &H40&
Public Const WINSTA_ENUMERATE = &H100&
Public Const WINSTA_READSCREEN = &H200&

Public Const DESKTOP_READOBJECTS = &H1&
Public Const DESKTOP_CREATEWINDOW = &H2&
Public Const DESKTOP_CREATEMENU = &H4&
Public Const DESKTOP_HOOKCONTROL = &H8&
Public Const DESKTOP_JOURNALRECORD = &H10&
Public Const DESKTOP_JOURNALPLAYBACK = &H20&
Public Const DESKTOP_ENUMERATE = &H40&
Public Const DESKTOP_WRITEOBJECTS = &H80&
Public Const DESKTOP_SWITCHDESKTOP = &H100&

Public Const WINSTA_ALL_ACCESS = (WINSTA_ACCESSCLIPBOARD Or _
    WINSTA_ACCESSGLOBALATOMS Or _
    WINSTA_CREATEDESKTOP Or _
    WINSTA_ENUMDESKTOPS Or _
    WINSTA_ENUMERATE Or _
    WINSTA_EXITWINDOWS Or _
    WINSTA_READATTRIBUTES Or _
    WINSTA_READSCREEN Or _
    WINSTA_WRITEATTRIBUTES)

Public Const DESKTOP_ALL_ACCESS = (DESKTOP_CREATEMENU Or _
    DESKTOP_CREATEWINDOW Or _
    DESKTOP_ENUMERATE Or _
    DESKTOP_HOOKCONTROL Or _
    DESKTOP_JOURNALPLAYBACK Or _
    DESKTOP_JOURNALRECORD Or _
    DESKTOP_READOBJECTS Or _
    DESKTOP_SWITCHDESKTOP Or _
    DESKTOP_WRITEOBJECTS)


'
' Constants from WINNT.H for the various well-known SIDs, users and groups
'
Public Const SECURITY_WORLD_SID_AUTHORITY = &H1
Public Const SECURITY_NT_AUTHORITY = &H5

Public Const SECURITY_BUILTIN_DOMAIN_RID = &H20&
Public Const DOMAIN_ALIAS_RID_ADMINS = &H220&
Public Const DOMAIN_ALIAS_RID_USERS = &H221&
Public Const SECURITY_LOCAL_SYSTEM_RID = &H12
Public Const SECURITY_WORLD_RID = &H0

Public Const DOMAIN_USER_RID_ADMIN = &H1F4
Public Const DOMAIN_USER_RID_GUEST = &H1F5

Public Const DOMAIN_GROUP_RID_ADMINS = &H200

Public Const INVALID_HANDLE_VALUE = -1
Public Const OPEN_EXISTING = 3
Public Const FILE_FLAG_BACKUP_SEMANTICS = &H2000000

'Folder Specific Access Rights
Public Const FILE_LIST_DIRECTORY = &H1&  ' directory
Public Const FILE_ADD_FILE = &H2&  ' directory
Public Const FILE_ADD_SUBDIRECTORY = &H4&  ' directory
Public Const FILE_TRAVERSE = &H20&  ' directory
Public Const FILE_DELETE_CHILD = &H40&  ' directory

Public Const FILE_READ_DATA = &H1&  ' file
Public Const FILE_WRITE_DATA = &H2&  ' file
Public Const FILE_APPEND_DATA = &H4&  ' file
Public Const FILE_EXECUTE = &H20&  ' file

Public Const FILE_READ_EA = &H8&  ' file & directory
Public Const FILE_WRITE_EA = &H10&  ' file & directory

Public Const FILE_READ_ATTRIBUTES = &H80&  ' all
Public Const FILE_WRITE_ATTRIBUTES = &H100&  ' all

' Generic access masks for files
Public Const FILE_ALL_ACCESS As Long = _
    STANDARD_RIGHTS_REQUIRED Or _
    SYNCHRONIZE Or _
    511
Public Const FILE_GENERIC_READ As Long = _
    STANDARD_RIGHTS_READ Or _
    FILE_READ_DATA Or _
    FILE_READ_ATTRIBUTES Or _
    FILE_READ_EA Or _
    SYNCHRONIZE
Public Const FILE_GENERIC_WRITE As Long = _
    STANDARD_RIGHTS_WRITE Or _
    FILE_WRITE_DATA Or _
    FILE_WRITE_ATTRIBUTES Or _
    FILE_WRITE_EA Or _
    FILE_APPEND_DATA Or _
    SYNCHRONIZE
Public Const FILE_GENERIC_EXECUTE As Long = _
    STANDARD_RIGHTS_EXECUTE Or _
    FILE_READ_ATTRIBUTES Or _
    FILE_EXECUTE Or _
    SYNCHRONIZE


' Other constants
Public Const ERROR_SUCCESS = 0&
Public Const NERR_Success = 0&

' Version Information constant
Private Const VER_PLATFORM_WIN32_NT = &H2

' Types needed for ACL manipulation. Refer to MSDN for more info
Private Type ACL
  AclRevision As Byte
  Sbz1 As Byte
  AclSize As Integer
  AceCount As Integer
  Sbz2 As Integer
End Type

Private Type ACL_SIZE_INFORMATION
  AceCount As Long
  AclBytesInUse As Long
  AclBytesFree As Long
End Type

Private Type ACE_HEADER
  AceType As Byte
  AceFlags As Byte
  AceSize As Integer
End Type

Private Type ACE
  Header As ACE_HEADER
  Mask As Long
  SidStart As Long
End Type

Private Type SECURITY_ATTRIBUTES
  Length As Long
  SecurityDescriptor As Long
  InheritHandle As Long
End Type

Private Type SID_IDENTIFIER_AUTHORITY
  Value(6) As Byte
End Type

Private Type OSVERSIONINFO
  dwOSVersionInfoSize As Long
  dwMajorVersion As Long
  dwMinorVersion As Long
  dwBuildNumber As Long
  dwPlatformId As Long
  szCSDVersion As String * 128
End Type


' Application Types
Public Type AccountPerm
  AccountName As String
  AccessMask As Long
  AceFlags As Byte
  AceType As Byte
  pSid As Long
  SidPassedByCaller As Boolean
End Type

Private Type SDMemInfo
  pSD As Long
  pAcl As Long
End Type

Private Declare Function LocalAlloc Lib "kernel32.dll" _
    (ByVal wFlags As Long, ByVal wBytes As Long) As Long

Private Declare Function LocalFree Lib "kernel32.dll" _
    (ByVal hMem As Long) As Long

Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" _
    (hpvDest As Any, ByVal hpvSource As Long, _
    ByVal cbCopy As Long)

Private Declare Function InitializeSecurityDescriptor Lib "advapi32.dll" _
    (ByVal pSecurityDescriptor As Long, _
    ByVal dwRevision As Long) As Long

Private Declare Function LookupAccountName Lib "advapi32.dll" Alias _
    "LookupAccountNameA" (ByVal lpSystemName As Long, _
    ByVal lpAccountName As String, _
    ByVal Sid As Long, _
    cbSid As Long, _
    ByVal ReferencedDomainName As String, _
    cbReferencedDomainName As Long, _
    peUse As Long) As Long

Private Declare Function GetLengthSid Lib "advapi32.dll" _
    (ByVal pSid As Long) As Long

Private Declare Function InitializeAcl Lib "advapi32.dll" _
    (ByVal pAcl As Long, ByVal nAclLength As Long, _
    ByVal dwAclRevision As Long) As Long

Private Declare Function SetSecurityDescriptorDacl Lib "advapi32.dll" _
    (ByVal pSecurityDescriptor As Long, ByVal bDaclPresent As Long, _
    ByVal pDacl As Long, ByVal bDaclDefaulted As Long) As Long

Private Declare Function GetAce Lib "advapi32.dll" _
    (ByVal pAcl As Long, ByVal dwAceIndex As Long, pACE As Long) As Long

Private Declare Function GetSecurityDescriptorDacl Lib "advapi32.dll" _
    (ByVal pSecurityDescriptor As Long, lpbDaclPresent As Long, _
    pDacl As Long, lpbDaclDefaulted As Long) As Long

Private Declare Function GetAclInformation Lib "advapi32.dll" _
    (ByVal pAcl As Long, pAclInformation As Any, _
    ByVal nAclInformationLength As Long, _
    ByVal dwAclInformationClass As Long) As Long

Private Declare Function GetSecurityDescriptorControl Lib "advapi32.dll" _
    (ByVal pSecurityDescriptor As Long, _
    pControl As Long, lpdwRevision As Long) As Long

Private Declare Function SetSecurityDescriptorControl Lib "advapi32.dll" _
    (ByVal pSecurityDescriptor As Long, _
    ByVal controlBitsOfInterest As Long, _
    ByVal controlBitsToSet As Long) As Long

Private Declare Function EqualSid Lib "advapi32.dll" _
    (ByVal pSid1 As Long, ByVal pSid2 As Long) As Long

Private Declare Function AddAce Lib "advapi32.dll" (ByVal pAcl As Long, _
    ByVal dwAceRevision As Long, ByVal dwStartingAceIndex As Long, _
    ByVal pAceList As Long, ByVal nAceListLength As Long) As Long

Private Declare Function AllocateAndInitializeSid Lib "advapi32.dll" _
    (pIdentifierAuthority As SID_IDENTIFIER_AUTHORITY, _
    ByVal nSubAuthorityCount As Byte, ByVal nSubAuthority0 As Long, _
    ByVal nSubAuthority1 As Long, ByVal nSubAuthority2 As Long, _
    ByVal nSubAuthority3 As Long, ByVal nSubAuthority4 As Long, _
    ByVal nSubAuthority5 As Long, ByVal nSubAuthority6 As Long, _
    ByVal nSubAuthority7 As Long, lpPSid As Long) As Long

Private Declare Sub FreeSid Lib "advapi32.dll" (ByVal pSid As Long)

' APIs for modifying DACL of a user object like a windowstation or desktop
Private Declare Function GetUserObjectSecurity Lib "user32.dll" _
    (ByVal hObject As Long, _
    RequestedInformation As Long, _
    ByVal pSecurityDescriptor As Long, _
    ByVal nLength As Long, _
    lpnLengthNeeded As Long) As Long
    
Private Declare Function SetUserObjectSecurity Lib "user32.dll" _
    (ByVal hObject As Long, _
    SecurityInformation As Long, _
    ByVal pSecurityDescriptor As Long) As Long
    
Private Declare Function OpenDesktop Lib "user32.dll" Alias "OpenDesktopA" _
    (ByVal lpszDesktop As String, ByVal dwFlags As Long, _
    ByVal fInherit As Long, ByVal dwDesiredAccess As Long) As Long
    
Private Declare Function CloseDesktop Lib "user32.dll" _
    (ByVal hDesktop As Long) As Long
    
Private Declare Function OpenWindowStation Lib "user32.dll" Alias _
    "OpenWindowStationA" _
    (ByVal lpszWindowStation As String, ByVal fInherit As Long, _
    ByVal dwDesiredAccess As Long) As Long
    
Private Declare Function CloseWindowStation Lib "user32.dll" _
    (ByVal hWindowStation As Long) As Long
    
Private Declare Function GetProcessWindowStation Lib "user32.dll" () As Long

Private Declare Function GetThreadDesktop Lib "user32.dll" _
    (ByVal dwThreadId As Long) As Long
    
Private Declare Function GetCurrentThread Lib "kernel32.dll" () As Long

' Version Checking APIs
Private Declare Function GetVersionExA Lib "kernel32.dll" _
    (lpVersionInformation As OSVERSIONINFO) As Integer

Private Function IsEqual(Accounts() As AccountPerm, pSid As Long) As Boolean
  Dim nEntries As Long
  Dim nIndex As Long

  ' Check if the supplied SID pSid matches with one of the
  ' new SIDs specified in Accounts()
  nEntries = UBound(Accounts)
  For nIndex = 0 To nEntries
    If (EqualSid(Accounts(nIndex).pSid, pSid)) Then
      IsEqual = True
      Exit Function
    End If
  Next
  IsEqual = False
End Function

Private Function ConstructAndAddAce( _
    ByVal pNewACL As Long, _
    ByVal AceType As Byte, _
    ByVal AceFlags As Byte, _
    ByVal AccessMask As Long, _
    ByVal pSid As Long) As Long
  Dim fResult As Long

  Dim dwNewACESize As Long
  Dim dwSidLen As Long
  Dim tempAce As ACE
  Dim pACE As Long

  fResult = 0
  On Error GoTo Label1

  ' Find the length of SID and size of new ACE to be added
  dwSidLen = GetLengthSid(pSid)
  dwNewACESize = Len(tempAce) + dwSidLen - 4

  ' Allocate memory for the new ACE
  pACE = LocalAlloc(LPTR, dwNewACESize)
  If pACE = 0 Then Err.Raise 0

  ' Set up the ACE structure in VB variable
  tempAce.Header.AceType = AceType
  tempAce.Header.AceFlags = AceFlags
  tempAce.Header.AceSize = dwNewACESize
  tempAce.Mask = AccessMask

  ' Copy the VB variable contents and the SID to the
  ' the ACE allocated
  CopyMemory ByVal pACE, VarPtr(tempAce), LenB(tempAce)
  CopyMemory ByVal pACE + 8, pSid, dwSidLen

  ' Add the new ACE to the new ACL
  fResult = AddAce(pNewACL, ACL_REVISION, _
      MAXDWORD, _
      pACE, _
      dwNewACESize)
  LocalFree pACE
Label1:
  ConstructAndAddAce = fResult
End Function

Private Function AddSecurityDescriptor(ByVal pOldSD As Long, _
                    Accounts() As AccountPerm, _
                    sdInfo As SDMemInfo) As Long

  Dim pNewACL As Long
  Dim dwNewACLSize As Long
  Dim dwTotalDACLSize As Long
  Dim szDomainName As String
  Dim cbDomainName As Long
  Dim nSidSize As Long
  Dim I As Long, n As Long
  Dim eUse As Long
  Dim fReturn As Long
  Dim fResult As Long
  Dim tempACL As ACL
  Dim tempAce As ACE
  Dim Ptr As Long
  Dim dwNumOfAccounts As Long
  Dim pSD As Long
  Dim AceIndex As Long
  Dim lDaclPresent As Long
  Dim lDaclDefaulted As Long
  Dim sACLInfo As ACL_SIZE_INFORMATION
  Dim pAcl As Long
  Dim osinfo As OSVERSIONINFO
  Dim w2kOrAbove As Boolean

  On Error GoTo ExitLabel

  ' Determine if system is Windows 2000 or above
  osinfo.dwOSVersionInfoSize = Len(osinfo)
  osinfo.szCSDVersion = Space$(128)
  GetVersionExA osinfo
  w2kOrAbove = _
      (osinfo.dwPlatformId = VER_PLATFORM_WIN32_NT And _
      osinfo.dwMajorVersion >= 5)

  ' Intialize some of the variables
  fReturn = 0
  sdInfo.pAcl = 0
  sdInfo.pSD = 0

  dwNumOfAccounts = UBound(Accounts)

  ' Allocate memory for a new Security Descriptor
  pSD = LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH)
  If pSD = 0 Then Err.Raise 0
  sdInfo.pSD = pSD

  ' Initialize the new Security Descriptor
  fResult = InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)
  If fResult = 0 Then Err.Raise 0

  ' Get the existing ACL size
  lDaclPresent = 0
  pAcl = 0
  If (pOldSD) Then
    fResult = GetSecurityDescriptorDacl(pOldSD, lDaclPresent, _
        pAcl, lDaclDefaulted)
    If fResult = 0 Then Err.Raise 0

    If (lDaclPresent <> 0 And pAcl <> 0) Then
      fResult = GetAclInformation(pAcl, sACLInfo, Len(sACLInfo), 2&)
      If fResult = 0 Then Err.Raise 0
      dwTotalDACLSize = sACLInfo.AclBytesInUse
    Else
      dwTotalDACLSize = Len(tempACL)
    End If
  Else
    dwTotalDACLSize = Len(tempACL)
  End If

  ' Find the SIDs for each userName supplied in Accounts() array
  ' and compute the new ACL size needed.
  ' Call LookupAccountName only for the entries where the
  ' SID is not supplied by the caller.
  szDomainName = Space(256)
  For n = 0 To dwNumOfAccounts
    If (Accounts(n).pSid = 0) Then
      nSidSize = 0
      cbDomainName = 256

      ' Lookup the SID for this user
      ' First call is to find the buffer size required for SID
      fResult = LookupAccountName(0, Accounts(n).AccountName, 0, _
          nSidSize, szDomainName, _
          cbDomainName, eUse)
      Accounts(n).pSid = LocalAlloc(LPTR, nSidSize)
      If Accounts(n).pSid = 0 Then Err.Raise 0

      ' Get the Actual SID value in this second call
      fResult = LookupAccountName(0, Accounts(n).AccountName, _
          Accounts(n).pSid, _
          nSidSize, szDomainName, _
          cbDomainName, eUse)
      If fResult = 0 Then Err.Raise 0
    End If

    ' sizeof(DWORD) = 4
    dwNewACLSize = Len(tempAce) + GetLengthSid(Accounts(n).pSid) - 4
    dwTotalDACLSize = dwTotalDACLSize + dwNewACLSize
  Next

  ' Allocate memory for the new ACL
  pNewACL = LocalAlloc(LPTR, dwTotalDACLSize)
  If pNewACL = 0 Then Err.Raise 0

  sdInfo.pAcl = pNewACL

  ' Initialize the new ACL
  fResult = InitializeAcl(pNewACL, dwTotalDACLSize, ACL_REVISION)
  If fResult = 0 Then Err.Raise 0

  AceIndex = 0

  ' Add the new ACCESS DENIED ACEs first to the DACL
  For n = 0 To dwNumOfAccounts
    If (Accounts(n).AceType = ACCESS_DENIED_ACE_TYPE) Then
      fResult = ConstructAndAddAce(pNewACL, _
          Accounts(n).AceType, _
          Accounts(n).AceFlags, _
          Accounts(n).AccessMask, _
          Accounts(n).pSid)
      If fResult = 0 Then Err.Raise 0
      AceIndex = AceIndex + 1
    End If
  Next

  ' Copy all non-inherited ACEs from the existing DACL
  If (lDaclPresent <> 0 And pAcl <> 0 And sACLInfo.AceCount > 0) Then
    ' Get each ACE from the old DACL and add them into the new DACL.
    For I = 0 To (sACLInfo.AceCount - 1)
      ' Attempt to get the next ACE.
      fResult = GetAce(pAcl, I, Ptr)
      If (fResult = 0) Then Err.Raise 0

      CopyMemory tempAce, Ptr, LenB(tempAce)
      ' Exit this for loop, once the first INHERITED_ACE is found
      If ((tempAce.Header.AceFlags And INHERITED_ACE) = INHERITED_ACE) Then
        Exit For
      End If

      'Add the ACE to the new DACL if the SID is not in Accounts()
      If Not (IsEqual(Accounts(), Ptr + 8)) Then
        ' Now that you have the ACE, add it to the new ACL.
        fResult = AddAce(pNewACL, ACL_REVISION, _
            MAXDWORD, Ptr, _
            tempAce.Header.AceSize)
        If fResult = 0 Then Err.Raise 0
        AceIndex = AceIndex + 1
      End If
    Next I
  End If

  ' Add the new ACCESS ALLOWED ACEs next to the DACL
  For n = 0 To dwNumOfAccounts
    If (Accounts(n).AceType = ACCESS_ALLOWED_ACE_TYPE) Then
      fResult = ConstructAndAddAce(pNewACL, _
          Accounts(n).AceType, _
          Accounts(n).AceFlags, _
          Accounts(n).AccessMask, _
          Accounts(n).pSid)
      If fResult = 0 Then Err.Raise 0
      AceIndex = AceIndex + 1
    End If
  Next

  ' Copy now all inherited ACEs from the existing DACL, so that the
  ' new DACL will be in the Windows 2000 preferred order
  If (lDaclPresent <> 0 And pAcl <> 0 And sACLInfo.AceCount > 0) Then
    ' Get each INHERITED_ACE from the old ACL and
    ' add them into the new ACL.
    For I = I To (sACLInfo.AceCount - 1)
      ' Attempt to get the next ACE.
      fResult = GetAce(pAcl, I, Ptr)
      If (fResult = 0) Then Err.Raise 0

      CopyMemory tempAce, Ptr, LenB(tempAce)
      ' Add it to the new ACL.
      fResult = AddAce(pNewACL, ACL_REVISION, _
          MAXDWORD, Ptr, _
          tempAce.Header.AceSize)
      If fResult = 0 Then Err.Raise 0
      AceIndex = AceIndex + 1
    Next I
  End If

  If w2kOrAbove And pOldSD <> 0 Then
    Dim controlFlag As Long
    Dim dwRevision As Long
    Dim controlBitsOfInterest As Long
    Dim controlBitsToSet As Long

    fResult = GetSecurityDescriptorControl(pOldSD, _
        controlFlag, dwRevision)
    If (fResult <> 0) Then
      controlBitsOfInterest = 0
      controlBitsToSet = 0
      If ((controlFlag And SE_DACL_AUTO_INHERITED) = _
          SE_DACL_AUTO_INHERITED) Then
        controlBitsOfInterest = _
            SE_DACL_AUTO_INHERIT_REQ Or _
            SE_DACL_AUTO_INHERITED
        controlBitsToSet = controlBitsOfInterest
      ElseIf ((controlFlag And SE_DACL_PROTECTED) = _
          SE_DACL_PROTECTED) Then
        controlBitsOfInterest = _
            SE_DACL_PROTECTED
        controlBitsToSet = controlBitsOfInterest
      End If
      If controlBitsToSet <> 0 Then
        fResult = SetSecurityDescriptorControl(pSD, _
            controlBitsOfInterest, _
            controlBitsToSet)
        If fResult = 0 Then Err.Raise 0
      End If
    End If
  End If

  ' Add the new DACL to the new Security Descriptor
  fResult = SetSecurityDescriptorDacl(pSD, 1, pNewACL, 0)
  If fResult = 0 Then Err.Raise 0

  fReturn = 1

ExitLabel:
  ' Make sure we clean up
  For n = 0 To dwNumOfAccounts
    ' Free only the SIDs that has been allocated in this function
    If Accounts(n).pSid <> 0 And _
        Not (Accounts(n).SidPassedByCaller) Then
      LocalFree (Accounts(n).pSid)
      Accounts(n).pSid = 0
    End If
  Next
  ' If any of the functions failed, free new SD, and new ACL
  If fReturn = 0 Then
    If (sdInfo.pSD <> 0) Then LocalFree sdInfo.pSD
    sdInfo.pSD = 0
    If (sdInfo.pAcl <> 0) Then LocalFree sdInfo.pAcl
    sdInfo.pAcl = 0
  End If

  AddSecurityDescriptor = fReturn

End Function

Public Function UpdatePermissionsOfUserObject( _
  ByVal hObject As Long, Accounts() As AccountPerm) As Boolean

  Dim fResult As Long

  Dim sdInfo As SDMemInfo
  Dim oldSD As Long
  Dim nLengthNeeded As Long
  Dim bStatus As Boolean

  bStatus = False
  On Error GoTo Cleanup

  sdInfo.pAcl = 0
  sdInfo.pSD = 0

  nLengthNeeded = 0
  fResult = GetUserObjectSecurity(hObject, _
      DACL_SECURITY_INFORMATION, 0, _
      nLengthNeeded, nLengthNeeded)
  ' This call will fail. On Return nLengthNeeded will be updated.
  ' Check for that below
  If nLengthNeeded = 0 Then
    MsgBox "GetUserObjectSecurity failed with error code : " _
        & Err.LastDllError
    Err.Raise 0
  End If

  oldSD = LocalAlloc(LPTR, nLengthNeeded)
  If oldSD = 0 Then
    MsgBox "LocalAlloc failed with error code : " _
        & Err.LastDllError
    Err.Raise 0
  End If

  fResult = GetUserObjectSecurity(hObject, _
      DACL_SECURITY_INFORMATION, oldSD, _
      nLengthNeeded, nLengthNeeded)
  If fResult = 0 Then
    MsgBox "GetUserObjectSecurity failed with error code : " _
        & Err.LastDllError
    Err.Raise 0
  End If

  fResult = AddSecurityDescriptor(oldSD, Accounts(), sdInfo)
  If fResult = 0 Then
    MsgBox "Unable to create Security Descriptor"
    Err.Raise 0
  End If

  fResult = SetUserObjectSecurity(hObject, _
      DACL_SECURITY_INFORMATION, sdInfo.pSD)
  If fResult = 0 Then
    MsgBox "SetUserObjectSecurity failed with error code : " _
        & Err.LastDllError
    Err.Raise 0
  End If

  bStatus = True
Cleanup:
  'Free the memory allocated
  If (oldSD <> 0) Then LocalFree oldSD
  oldSD = 0
  If (sdInfo.pSD <> 0) Then LocalFree sdInfo.pSD
  sdInfo.pSD = 0
  If (sdInfo.pAcl <> 0) Then LocalFree sdInfo.pAcl
  sdInfo.pAcl = 0
  UpdatePermissionsOfUserObject = bStatus
End Function

Public Function UpdatePermissionsOfDesktop() As Boolean
  Dim success As Boolean
  Dim hWinsta As Long
  Dim hDesktop As Long
  Dim WinstaName As String
  Dim DesktopName As String
  Dim Accounts(0 To 0) As AccountPerm
  Dim n As Long
  Dim dwNumOfAccounts As Long

  'WinSta0 is the name of the window station object that represents the
  'physical screen, keyboard and mouse. Winlogon creates the following
  'desktops in the WinSta0 object

  '[1]Winlogon desktop
  '=======================
  'This is the desktop Winlogon and GINA use for interactive identification
  'and authentication, and other secure dialogs. Winlogon automatically
  'switches to this desktop when it receives SAS event notification.

  '[2]Application desktop
  '=======================
  'Each time a user successfully logs on, an application desktop is created
  'for that logon session. The application desktop is also called the default
  'or user desktop. This desktop is where all user activity takes place.
  'The application desktop is protected; only the system and the interactive
  'logon session have access to it. Note that only a particular instance of
  'the logged-on user has access to the desktop. If the interactive user
  'activates a process using the service controller, that service application
  'will not have access to the application desktop.

  '[3]Screen-saver desktop
  '=======================
  'This is the current desktop when a screen saver is running. If a user is
  'logged on, both the system and the interactive logon session have access
  'to the desktop. Otherwise, only the system has access to the desktop.

  WinstaName = "Winsta0"  '//window station
  DesktopName = "Default"  '//Application desktop of Winsta0
  dwNumOfAccounts = UBound(Accounts)

  ' Set up the account permissions that need to be created as an array

  ' The following entry will allow permissions for User1
  Accounts(0).AccountName = "User1"
  Accounts(0).AccessMask = GENERIC_READ Or _
      GENERIC_WRITE Or _
      GENERIC_EXECUTE
  Accounts(0).AceFlags = 0
  Accounts(0).AceType = ACCESS_ALLOWED_ACE_TYPE
  Accounts(0).pSid = 0
  Accounts(0).SidPassedByCaller = False

  hWinsta = OpenWindowStation(WinstaName, _
      0, READ_CONTROL Or WRITE_DAC)
  If (hWinsta = 0) Then
    MsgBox "OpenWindowStation failed with error code : " & Err.LastDllError
  Else
    UpdatePermissionsOfUserObject hWinsta, Accounts
    CloseWindowStation hWinsta
  End If

  hDesktop = OpenDesktop(DesktopName, _
      0, 0, READ_CONTROL Or WRITE_DAC)
  If (hDesktop = 0) Then
    MsgBox "OpenDesktop failed with error code : " & Err.LastDllError
  Else
    success = UpdatePermissionsOfUserObject(hDesktop, Accounts)
    CloseDesktop hDesktop
    UpdatePermissionsOfDesktop = success
  End If

  ' Make sure we clean up
  For n = 0 To dwNumOfAccounts
    If Accounts(n).pSid <> 0 And Accounts(n).SidPassedByCaller Then
      FreeSid (Accounts(n).pSid)
      Accounts(n).pSid = 0
    End If
  Next
End Function

- Now press F5 to run the demo
- Now click on Apply Permissions button.


Submitted By : Nayan Patel  (Member Since : 5/26/2004 12:23:06 PM)

Job Description : He is the moderator of this site and currently working as an independent consultant. He works with VB.net/ASP.net, SQL Server and other MS technologies. He is MCSD.net, MCDBA and MCSE. In his free time he likes to watch funny movies and doing oil painting.
View all (893) submissions by this author  (Birth Date : 7/14/1981 )


Home   |  Comment   |  Contact Us   |  Privacy Policy   |  Terms & Conditions   |  BlogsZappySys

© 2008 BinaryWorld LLC. All rights reserved.