Advertisement
Java_Volume1 Windows API Call/ Explanation #90477

Set ACL using low-level access control functions

This module provides a function that uses the Windows NT low-level access control functions to set the access rights on a folder (directory). The High-level access control functions (GetNamedSecurityInfo etc) do not function properly. They merge all ACEs for each SID. MS only acknowledges one of the four functions as malfunctioning, in fact they all are not suited for folders (directories).

AI

AI Summary: This codebase represents a historical implementation of the logic described in the metadata. Our preservation engine analyzes the structure to provide context for modern developers.

Source Code
original-source
Attribute VB_Name = "ModACL"
Option Explicit
'for public function SetAccessRights
Enum fNSR
  f_NEW_FULL   'Will remove the existing ACL and assign Full rights
  f_REVOKE    'Will revoke the specified trustee
  f_SET_CHANGE  'Will just set new Change rights
  f_SET_FULL   'Will just set new Full rights
End Enum
  Const SECURITY_DESCRIPTOR_REVISION = (1)
  Const ACL_REVISION = (2)
  Const DACL_SECURITY_INFORMATION = 4&
  Const ERROR_SUCCESS = 0&
  Const SE_FILE_OBJECT = 1&
  
  Const SET_ACCESS = 2& 'NOT_USED_ACCESS = 0, GRANT_ACCESS, SET_ACCESS, DENY_ACCESS,
  Const REVOKE_ACCESS = 4& 'REVOKE_ACCESS, SET_AUDIT_SUCCESS, SET_AUDIT_FAILURE
  Private Type AclType
   AclRevision As Byte
   Sbz1 As Byte
   aclSize As Integer
   AceCount As Integer
   Sbz2 As Integer
  End Type
  Private Type AceType
   AceType As Byte
   AceFlags As Byte
   AceSize As Integer
   AceMask As Long
   Sid(99) As Byte
  End Type
'The predefined ace types that go into the AceType field of an Ace header.
  Const ACCESS_ALLOWED_ACE_TYPE = &H0
  Const ACCESS_DENIED_ACE_TYPE = &H1
  Const SYSTEM_AUDIT_ACE_TYPE = &H2
  Const SYSTEM_ALARM_ACE_TYPE = &H3
'The inherit flags that go into the AceFlags field of an Ace header.
  Const OBJECT_INHERIT_ACE = &H1
  Const CONTAINER_INHERIT_ACE = &H2
  Const NO_PROPAGATE_INHERIT_ACE = &H4
  Const INHERIT_ONLY_ACE = &H8
  Const VALID_INHERIT_FLAGS = &HF
  
Private Declare Function FormatMessage Lib "kernel32" Alias "FormatMessageA" _
  (ByVal dwFlags As Long, ByVal lpSource As Long, ByVal dwMessageId As Long, _
  ByVal dwLanguageId As Long, ByVal lpBuffer As String, ByVal nSize As Long, _
  Arguments As Any) As Long
Declare Function LocalFree Lib "kernel32" (ByVal hMem As Long) As Long
'Private Declare Function LookupAccountSid Lib "advapi32.dll" Alias _
'  "LookupAccountSidA" (ByVal system As String, pSid As Any, _
'  ByVal Account As String, ByRef AccSize As Long, ByVal Domain As String, _
'  ByRef domSize As Long, ByRef peUse As Long) As Boolean
Private Declare Function LookupAccountName Lib "advapi32.dll" Alias _
  "LookupAccountNameA" (ByVal system As String, ByVal Account As String, _
  pSid As Any, ByRef sidSize As Long, ByVal Domain As String, _
  ByRef domSize As Long, ByRef peUse As Long) As Boolean
Private Declare Function IsValidSid Lib "advapi32.dll" (pSid As Any) As Long
Private Declare Function GetLengthSid Lib "advapi32.dll" (pSid As Any) As Long
Private Declare Function GetLastError Lib "kernel32.dll" () As Long
'       pSD and pDACL always ByRef
Private Declare Function GetFileSecurity Lib "advapi32.dll" Alias "GetFileSecurityA" (ByVal szFileName As String, ByVal reqtype As Long, pSD As Any, ByVal bufsiz As Long, bufneed As Long) As Long
Private Declare Function SetFileSecurity Lib "advapi32.dll" Alias "SetFileSecurityA" (ByVal szFileName As String, ByVal reqtype As Long, pSD As Any) As Long
Private Declare Function GetSecurityDescriptorDacl Lib "advapi32.dll" (pSD As Any, ByRef pDaclPres As Long, pDacl As Any, ByRef bDaclDefaulted As Long) As Long
Private Declare Function SetSecurityDescriptorDacl Lib "advapi32.dll" (pSD As Any, ByVal pDaclPres As Long, pDacl As Any, ByVal bDaclDefaulted As Long) As Long
'    Declare Function GetAclInformation Lib "advapi32.dll" (pAcl As ACL, pAclInformation As Any, ByVal nAclInformationLength As Long, ByVal dwAclInformationClass As Integer) As Long
Private Declare Function InitializeSecurityDescriptor Lib "advapi32.dll" (pSD As Any, ByVal dwRevision As Long) As Long
Private Declare Function InitializeAcl Lib "advapi32.dll" (pAcl As Any, ByVal nAclLength As Long, ByVal dwAclRevision As Long) As Long
'rivate Declare Function AddAccessAllowedAce Lib "advapi32.dll" (pAcl As Any, ByVal AceRev As Long, ByVal mask As Long, pSid As Any) As Long
'rivate Declare Function AddAccessDeniedAce Lib "advapi32.dll" (pAcl As Any, ByVal AceRev As Long, ByVal mask As Long, pSid As Any) As Long
Private Declare Function GetAce Lib "advapi32.dll" (pAcl As Any, ByVal dwAceIndex As Long, ppAce As Long) As Long
Private Declare Function AddAce Lib "advapi32.dll" (pAcl As Any, ByVal dwAceRevision As Long, ByVal dwStartingAceIndex As Long, pAceList As Any, ByVal nAceListLength As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As Any, pSource As Any, ByVal ByteLen As Long)
' *********************************************************************************************
' *********************************************************************************************
' *********************************************************************************************
Public Function SetAccessRights(sSrv As String, sFilename As String, _
                szAccount As String, fNewSetRev As fNSR) As Boolean
 Dim x as Long, i as Long, lRet As Long, long1 As Long
 Dim Sid(100) As Byte, SIS(100) As Byte
 Dim sisSize As Long, sidSize As Long, peUse As Long
 Dim sDom As String, domSize As Long
 Dim SecDsc() As Byte
 Dim pSD As Long, DACLparm1 As Long, DACLparm2 As Long
 Dim pDacl As Long
 Dim ACL As AclType
 Dim NewACL() As Byte
 Dim aclSize As Long, aclRev As Long
 Dim pAce As Long, numAce As Long
 Dim ACE As AceType
 Dim AceSize As Long, AccType As Long, AccMask As Long
 
  SetAccessRights = False
  On Error GoTo 0
   
  domSize = 25
  sDom = String(domSize, " ") ' make vb alloc memory
  
  sisSize = 100 ' get sid of "system"
  If LookupAccountName(sSrv + vbNullChar, "System" + vbNullChar, SIS(0), sisSize, _
              sDom, domSize, peUse) = 0 Then DisplayError "LookupAccountName - 1", GetLastError(): Exit Function
  If IsValidSid(SIS(0)) = 0 Then DisplayError "LookupAccountName - SIS", GetLastError(): Exit Function
  
  sidSize = 100 ' get sid of szAccount
  If LookupAccountName(sSrv + vbNullChar, szAccount + vbNullChar, Sid(0), sidSize, _
              sDom, domSize, peUse) = 0 Then DisplayError "LookupAccountName - 2", GetLastError(): Exit Function
  If IsValidSid(Sid(0)) = 0 Then DisplayError "LookupAccountName - SID", GetLastError(): Exit Function
  sidSize = GetLengthSid(Sid(0))
'1: ------------- get the D-ACL --------------------------
  SecDsc = String(2000, " ")
  If GetFileSecurity(sFilename & vbNullChar, DACL_SECURITY_INFORMATION, _
            SecDsc(0), 4000, long1) = 0 Then DisplayError "GetFileSecurity", GetLastError(): Exit Function
  DACLparm1 = 0
  If GetSecurityDescriptorDacl(SecDsc(0), DACLparm1, pDacl, DACLparm2) = 0 Then DisplayError "GetSecurityDescriptorDacl", GetLastError(): Exit Function
	' pDacl is now a pointer to the DACL in SecDsc()  
  If DACLparm1 > 0 Then
    CopyMemory ACL, ByVal pDacl, 8  'Now copy to read the contents of the acl
    aclRev = ACL.AclRevision
    aclSize = ACL.aclSize
  Else
    ACL.AceCount = 0
    aclRev = ACL_REVISION
    aclSize = 0
  End If
'2: ------------- Create a new ACL --------------------------
  aclSize = aclSize + 200
  NewACL = String(aclSize/2, " ")  ' make vb alloc memory
  If InitializeAcl(NewACL(0), aclSize, aclRev) = 0 Then DisplayError "InitializeAcl", GetLastError(): Exit Function
  aclSize = 8
'3: ------------- Copy the ACEs except our ones -------------
  For i = 0 To 99
    ACE.Sid(i) = 0
  Next i
  aclRev = ACL.AclRevision
  For x = 0 To ACL.AceCount - 1
   If GetAce(ByVal pDacl, x, pAce) = 0 Then Exit Function
   CopyMemory ACE, ByVal pAce, 8
   AceSize = ACE.AceSize
   CopyMemory ACE, ByVal pAce, AceSize
   long1 = 0
   If fNewSetRev = f_NEW_FULL Then      'when new, still copy 'system'
     If CompareSid(ACE.Sid, SIS) Then long1 = 1
   Else                    'otherwise, copy all except szAccount
     If Not CompareSid(ACE.Sid, Sid) Then long1 = 1
   End If
   If long1 = 1 Then
     If AddAce(NewACL(0), aclRev, -1, ByVal pAce, AceSize) = 0 Then DisplayError "AddAce - copy", GetLastError(): Exit Function
     aclSize = aclSize + AceSize
   End If
  Next x
'4: ------------- Put in our ACEs --------------------------
  If fNewSetRev <> f_REVOKE Then
   AceSize = 8 + sidSize
   ACE.AceType = ACCESS_ALLOWED_ACE_TYPE  ' byte 0
   ACE.AceSize = AceSize          ' byte 2+3, mask = 4-7
   ACE.AceMask = IIf(fNewSetRev = f_SET_CHANGE, &H1301BF, &H1F01FF) 'Change, Full
   CopyMemory ACE.Sid(0), Sid(0), sidSize
   
   ACE.AceFlags = INHERIT_ONLY_ACE Or OBJECT_INHERIT_ACE
   If AddAce(NewACL(0), aclRev, 0, ACE, AceSize) = 0 Then DisplayError "AddAce - new1", GetLastError(): Exit Function
   aclSize = aclSize + AceSize
   
   ACE.AceFlags = CONTAINER_INHERIT_ACE  ' byte 1 - objectitself
   If AddAce(NewACL(0), aclRev, 0, ACE, AceSize) = 0 Then DisplayError "AddAce - new2", GetLastError(): Exit Function
   aclSize = aclSize + AceSize
  End If
'5: ------------- Write back the D-ACL----------------------
  CopyMemory NewACL(2), aclSize, 2
  If InitializeSecurityDescriptor(SecDsc(0), SECURITY_DESCRIPTOR_REVISION) = 0 Then _
			DisplayError "InitializeSecurityDescriptor", GetLastError(): Exit Function
  If SetSecurityDescriptorDacl(SecDsc(0), DACLparm1, NewACL(0), DACLparm2) = 0 Then _
			DisplayError "SetSecurityDescriptorDacl", GetLastError(): Exit Function
  If SetFileSecurity(sFilename & vbNullChar, DACL_SECURITY_INFORMATION, SecDsc(0)) = 0 Then _
			DisplayError "SetFileSecurity", GetLastError(): Exit Function
  SetAccessRights = True
End Function
Private Sub DisplayError(sApi As String, lCode As Long)
 Dim sMsg As String
 Dim sRtrnCode As String
 Dim lFlags As Long
 Dim lRet As Long
 Const FORMAT_MESSAGE_FROM_SYSTEM = &H1000
   sRtrnCode = Space$(256)
   lFlags = FORMAT_MESSAGE_FROM_SYSTEM
   lRet = FormatMessage(lFlags, 0&, lCode, 0&, sRtrnCode, 256&, 0&)
   If lRet = 0 Then MsgBox Err.LastDllError
   sMsg = "Error: " & sApi & vbCrLf
   sMsg = sMsg & "Code: " & lCode & vbCrLf
   sMsg = sMsg & "Desc: " & sRtrnCode
   MsgBox sMsg
End Sub
Private Function CompareSid(arr1() As Byte, Arr2() As Byte) As Boolean
Dim i As Long, len1 As Long, len2 As Long
  On Error GoTo 0
  CompareSid = False
  
  If IsValidSid(arr1(0)) = 0 Then Exit Function
  len1 = GetLengthSid(arr1(0))
  If IsValidSid(Arr2(0)) = 0 Then Exit Function
  len2 = GetLengthSid(Arr2(0))
  If len1 <> len2 Then Exit Function
  For i = 0 To len1 - 1
    If arr1(i) <> Arr2(i) Then Exit For
  Next i
  If i = len1 Then CompareSid = True
End Function

Upload
Original Comments (3)
Recovered from Wayback Machine