How to use high-level access control APIs from Visual Basic (295004)



The information in this article applies to:

  • Microsoft Win32 Application Programming Interface (API), when used with:
    • the operating system: Microsoft Windows 2000
    • the operating system: Microsoft Windows XP

This article was previously published under Q295004

SUMMARY

The Win32 API provides two sets of APIs for working with security descriptors (SDs) and access control lists (ACLs). Low-level as well as high-level access control API sets provide an interface for working with SDs and ACLs. For Microsoft Windows 2000 and MIcrosoft Windows XP, the high-level access control APIs have been enhanced to support object-specific access control entries (ACEs), directory service (DS) objects, and automatic inheritance. This article provides sample code that uses high-level access control APIs to modify an existing discretionary access control list (DACL) on a folder securable object.

MORE INFORMATION

The following Visual Basic sample code uses the GetNamedSecurityInfo() API to retrieve the existing DACL of the C:\Test1 folder. Then, it builds the EXPLICIT_ACCESS structure for everyone trustee with GENERIC_READ access by using the BuildExplicitAccessWithName() API. In this example, the ACE is constructed with inheritance CONTAINER_INHERIT_ACE or OBJECT_INHERIT_ACE, which applies as an effective ACE for the C:\Test1 folder and an inheritable ACE for subfolders as well as files.

The SetEntriesInAcl() API creates a new access-control list (ACL) by merging new access-control information specified in EXPLICIT_ACCESS structures into an existing ACL and returns a newly updated DACL in memory. This updated DACL is then used to set security on the C:\Test1 folder by using the SetNamedSecurityInfo() API.
Option Explicit

' Success status of high level access control APIs
Private Const ERROR_SUCCESS = 0&

' Type of Securable Object we are operating in this sample code
Private Const SE_FILE_OBJECT = 1&

' The Security Information constants required
Private Const DACL_SECURITY_INFORMATION = 4&
Private Const SET_ACCESS = 2&

' Standard access rights extracted from WinNT.h
Private Const SYNCHRONIZE = &H100000
Private Const READ_CONTROL = &H20000
Private Const WRITE_DAC = &H40000
Private Const WRITE_OWNER = &H80000
Private Const STANDARD_RIGHTS_READ = (READ_CONTROL)
Private Const STANDARD_RIGHTS_WRITE = (READ_CONTROL)
Private Const DELETE = &H10000

' Generic access rights extracted from WinNT.h
Private Const GENERIC_ALL = &H10000000
Private Const GENERIC_EXECUTE = &H20000000
Private Const GENERIC_READ = &H80000000
Private Const GENERIC_WRITE = &H40000000

' Inheritance Flags
Private Const CONTAINER_INHERIT_ACE = &H2
Private Const OBJECT_INHERIT_ACE = &H1

' The TRUSTEE structure identifies the user account, group account, or logon session
' to which an ACE applies. The structure can use a name or a security identifier (SID)
' to identify the trustee.

' Access control APIs, such as SetEntriesInAcl and GetExplicitEntriesFromAcl, use this
' structure to identify the account associated with the access-control or audit-control
' information in an EXPLICIT_ACCESS structure.
Private Type TRUSTEE
    pMultipleTrustee As Long
    MultipleTrusteeOperation As Long
    TrusteeForm As Long
    TrusteeType As Long
    ptstrName As String
End Type

' EXPLICIT_ACCESS structure that specifies access-control information for a specified
' trustee such as access mask as well as inheritance flags
Private Type EXPLICIT_ACCESS
    grfAccessPermissions As Long
    grfAccessMode As Long
    grfInheritance As Long
    pTRUSTEE As TRUSTEE
End Type

' High Level access control API declarations
Private Declare Sub BuildExplicitAccessWithName Lib "Advapi32.dll" Alias _
    "BuildExplicitAccessWithNameA" _
    (ea As Any, _
    ByVal TrusteeName As String, _
    ByVal AccessPermissions As Long, _
    ByVal AccessMode As Integer, _
    ByVal Inheritance As Long)
    
Private Declare Function SetEntriesInAcl Lib "Advapi32.dll" Alias _
    "SetEntriesInAclA" _
    (ByVal CountofExplicitEntries As Long, _
    ea As Any, _
    ByVal OldAcl As Long, _
    NewAcl As Long) As Long

Private Declare Function GetNamedSecurityInfo Lib "Advapi32.dll" Alias _
    "GetNamedSecurityInfoA" _
    (ByVal ObjName As String, _
    ByVal SE_OBJECT_TYPE As Long, _
    ByVal SecInfo As Long, _
    ByVal pSid As Long, _
    ByVal pSidGroup As Long, _
    pDacl As Long, _
    ByVal pSacl As Long, _
    pSecurityDescriptor As Long) As Long
    
Private Declare Function SetNamedSecurityInfo Lib "Advapi32.dll" Alias _
    "SetNamedSecurityInfoA" _
    (ByVal ObjName As String, _
    ByVal SE_OBJECT As Long, _
    ByVal SecInfo As Long, _
    ByVal pSid As Long, _
    ByVal pSidGroup As Long, _
    ByVal pDacl As Long, _
    ByVal pSacl As Long) As Long

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

Private Sub Command1_Click()

Dim result As Long
Dim pSecDesc As Long
Dim ea As EXPLICIT_ACCESS
Dim pNewDACL As Long
Dim pOldDACL As Long
 
' Get the DACL information of c:\test1 folder using GetNamedSecurityInfo() API.
' SE_FILE_OBJECT constant says that the named securable object is a file or folder
result = GetNamedSecurityInfo("c:\test1", SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, 0&, 0&, pOldDACL, 0&, pSecDesc)
If result = ERROR_SUCCESS Then
    
    ' Construct an EXPLICIT_ACCESS structure for Everyone with GENERIC_READ access that will apply for c:\test1
    ' as well as subfolder and files using BuildExplicitAccessWithName() API
    BuildExplicitAccessWithName ea, "Users", GENERIC_READ, SET_ACCESS, CONTAINER_INHERIT_ACE Or OBJECT_INHERIT_ACE
    
    ' Merge constructed EXPLICIT_ACCESS structure to the existing DACL and get an updated DACL in memory from
    ' SetEntriesInAcl() API
    result = SetEntriesInAcl(1, ea, pOldDACL, pNewDACL)
    If result = ERROR_SUCCESS Then
        MsgBox "SetEntriesInAcl succeeded"
        
        ' Call SetNamedSecurityInfo() API with the updated DACL in memory to change the DACL of c:\test1 folder
        result = SetNamedSecurityInfo("c:\test1", SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, 0&, 0&, pNewDACL, 0&)
        If result = ERROR_SUCCESS Then
            MsgBox "SetNamedSecurityInfo succeeded"
        Else
            MsgBox "SetNamedSecurityInfo failed with error code : " & result
        End If
        
        ' Free the memory allocated for the new DACL by the SetEntriesInAcl() API, using LocalFree() API
        LocalFree pNewDACL
    Else
        MsgBox "SetEntriesInAcl failed with error code : " & result
    End If
    
    ' Free the memory allocated for the security descriptor by the GetNamedSecurityInfo() API, using LocalFree() API
    LocalFree pSecDesc
Else
    MsgBox "GetNamedSecurityInfo failed with error code : " & result
End If
End Sub
				

REFERENCES

For more information, click the following article numbers to view the articles in the Microsoft Knowledge Base:

102102 How to add an access-allowed ACE to a file

316440 How to use low-level access control APIs from Visual Basic


Modification Type:MajorLast Reviewed:7/19/2005
Keywords:kbACL kbAPI kbhowto kbKernBase kbSecurity KB295004