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 Registry object security using APIs

Other articles in this series are

Handling NTFS Permissions Part-1 (handling kernel object permissions)
Handling NTFS Permissions Part-2 (handling use object permissions)
Handling NTFS Permissions Part-3 (handling shared resource permissions)
Handling NTFS Permissions Part-5 (handling printer permissions)


The UpdatePermissionsOfRegistryKey function in the sample code uses the RegGetKeySecurity() and RegSetKeySecurity() functions to modify an existing DACL of a registry key. UpdatePermissionsOfHKey is used to call this helper function to modify permissions on a SOFTWARE\TEST registry key under HKEY_LOCAL_MACHINE.

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 textbox, 1 combobox and 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 = UpdatePermissionsOfHKey(Combo1.ItemData(Combo1.ListIndex), Text1)

  If success = False Then
    MsgBox "Error in UpdatePermissionsOfHKey", vbCritical
  Else
    MsgBox "Permissions Applied Successfully", vbInformation
  End If
End Sub

Private Sub Form_Load()
'//make sure that this path exist on your system
  Text1.Text = "SOFTWARE\TEST"
  Command1.Caption = "<< Apply Permissions"

  Combo1.AddItem "HKEY_LOCAL_MACHINE"
  Combo1.ItemData(0) = HKEY_LOCAL_MACHINE

  Combo1.AddItem "HKEY_CLASSES_ROOT"
  Combo1.ItemData(1) = HKEY_CLASSES_ROOT

  Combo1.AddItem "HKEY_CURRENT_USER"
  Combo1.ItemData(2) = HKEY_CURRENT_USER

  Combo1.AddItem "HKEY_USERS"
  Combo1.ItemData(3) = HKEY_USERS

  Combo1.ListIndex = 0
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

'
' 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


' Registry access masks
Public Const KEY_QUERY_VALUE = &H1
Public Const KEY_SET_VALUE = &H2
Public Const KEY_CREATE_SUB_KEY = &H4
Public Const KEY_ENUMERATE_SUB_KEYS = &H8
Public Const KEY_NOTIFY = &H10
Public Const KEY_CREATE_LINK = &H20
Public Const KEY_WOW64_32KEY = &H200
Public Const KEY_WOW64_64KEY = &H100

Public Const KEY_READ = ((STANDARD_RIGHTS_READ Or _
    KEY_QUERY_VALUE Or _
    KEY_ENUMERATE_SUB_KEYS Or _
    KEY_NOTIFY) _
    And (Not SYNCHRONIZE))
Public Const KEY_WRITE = ((STANDARD_RIGHTS_WRITE Or _
    KEY_SET_VALUE Or _
    KEY_CREATE_SUB_KEY) _
    And (Not SYNCHRONIZE))
Public Const KEY_EXECUTE = ((KEY_READ) And (Not SYNCHRONIZE))
Public Const KEY_ALL_ACCESS = ((STANDARD_RIGHTS_ALL Or _
    KEY_QUERY_VALUE Or _
    KEY_SET_VALUE Or _
    KEY_CREATE_SUB_KEY Or _
    KEY_ENUMERATE_SUB_KEYS Or _
    KEY_NOTIFY Or _
    KEY_CREATE_LINK) _
    And (Not SYNCHRONIZE))

' Registry constants
Public Const HKEY_CLASSES_ROOT = &H80000000
Public Const HKEY_CURRENT_USER = &H80000001
Public Const HKEY_LOCAL_MACHINE = &H80000002
Public Const HKEY_USERS = &H80000003


' 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



'Security APIs
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 registry key
Private Declare Function RegOpenKeyEx Lib "advapi32.dll" _
    Alias "RegOpenKeyExA" _
    (ByVal hKey As Long, _
    ByVal lpSubKey As String, _
    ByVal ulOptions As Long, _
    ByVal samDesired As Long, phkResult As Long) As Long

Private Declare Function RegCloseKey Lib "advapi32.dll" _
    (ByVal hKey As Long) As Long

Private Declare Function RegGetKeySecurity Lib "advapi32.dll" _
    (ByVal hKey As Long, _
    ByVal SecurityInformation As Long, _
    ByVal pSecurityDescriptor As Long, _
    lpcbSecurityDescriptor As Long) As Long

Private Declare Function RegSetKeySecurity Lib "advapi32.dll" _
    (ByVal hKey As Long, _
    ByVal SecurityInformation As Long, _
    ByVal pSecurityDescriptor As Long) 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 UpdatePermissionsOfRegistryKey( _
  ByVal hKey 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 = RegGetKeySecurity(hKey, _
      DACL_SECURITY_INFORMATION, 0, _
      nLengthNeeded)
  ' This call will fail. On Return nLengthNeeded will be updated.
  ' Check for that below
  If nLengthNeeded = 0 Then
    MsgBox "RegGetKeySecurity failed with error code : " _
        & fResult
    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 = RegGetKeySecurity(hKey, _
      DACL_SECURITY_INFORMATION, oldSD, _
      nLengthNeeded)
  If fResult <> ERROR_SUCCESS Then
    MsgBox "RegGetKeySecurity failed with error code : " _
        & fResult
    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 = RegSetKeySecurity(hKey, _
      DACL_SECURITY_INFORMATION, sdInfo.pSD)
  If fResult <> ERROR_SUCCESS Then
    MsgBox "RegSetKeySecurity failed with error code : " _
        & fResult
    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
  UpdatePermissionsOfRegistryKey = bStatus
End Function


Public Function UpdatePermissionsOfHKey(Optional RootKey = HKEY_LOCAL_MACHINE, Optional KeyName = "SOFTWARE\TEST") As Boolean
  Dim success As Boolean
  Dim hKey As Long
  Dim Accounts(0 To 2) As AccountPerm
  Dim fResult As Long, n As Long
  Dim dwNumOfAccounts As Long
  Dim siaNtAuthority As SID_IDENTIFIER_AUTHORITY

  'KeyName = "SOFTWARE\TEST"
  dwNumOfAccounts = UBound(Accounts)

  ' Set up the account permissions that need to be created as an array
  Accounts(0).AccountName = ""
  Accounts(0).AccessMask = GENERIC_READ
  Accounts(0).AceFlags = CONTAINER_INHERIT_ACE
  Accounts(0).AceType = ACCESS_ALLOWED_ACE_TYPE

  ' Construct SID for Everyone "Universal well-known SID"
  siaNtAuthority.Value(5) = SECURITY_WORLD_SID_AUTHORITY
  If AllocateAndInitializeSid(siaNtAuthority, 1, _
      SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, _
      Accounts(0).pSid) = 0 Then
    MsgBox "AllocateAndInitializeSid failed with error code : " _
        & Err.LastDllError
    Exit Function
  End If
  'If the caller initializes SID, set SidPassedByCaller member to True
  Accounts(0).SidPassedByCaller = True

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

  ' The following entry will deny all permissions on future subkeys
  Accounts(2).AccountName = "User2"
  Accounts(2).AccessMask = GENERIC_ALL
  Accounts(2).AceFlags = CONTAINER_INHERIT_ACE Or INHERIT_ONLY_ACE
  Accounts(2).AceType = ACCESS_DENIED_ACE_TYPE
  Accounts(2).pSid = 0
  Accounts(2).SidPassedByCaller = False

  fResult = RegOpenKeyEx(RootKey, _
      KeyName, 0, _
      READ_CONTROL Or WRITE_DAC, hKey)
  If fResult <> ERROR_SUCCESS Then
    MsgBox "RegOpenKeyEx failed with error code : " & fResult
  Else
    success = UpdatePermissionsOfRegistryKey(hKey, Accounts)
    RegCloseKey hKey
    UpdatePermissionsOfHKey = 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.
- If you receive success message then goto the registry key by running regedit command. Check the Permissions of the key (HKLM\Software\Test). To check permissions right click on the key, click on the Permissions and then click on the Advanced button on security tab and you should see the entries for User1 and User2 as shown below.




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.