Check Access Rights to File/Directory on NTFS Volume

More information: Windows NT/2000/XP has API function AccessCheck, which in fact checks access rights to every operating system object, which supports access rights. This function is called implicitly by system every time user accesses such object. To call AccessCheck function explicitly it is necessary to carry out a whole series of operations with data structures responsible for OS security and call some other functions.

To simplify working with access rights to objects of NTFS file system (files, directories) I have written CheckFileAccess function which assumes all this hard work.

Here is description of this function:

CheckFileAccess(Filename As String, _
ByVal DesiredAccess As Long) As Long,

where:

Filename - file or directory full path.
Directory path must not end on "/" character.

DesiredAccess - desired access rights bit mask.

The function returns a bit mask which consists of those bits of desired bit mask, which correspond with allowed access rights. In case of access rights to given file or directory not supported, the function returns -1 value.

As desired access mask you may use any combination with OR operator of constants from the beginning of CheckFileAccess function listing. The most popular of them are:

FILE_GENERIC_READ - read access,

FILE_GENERIC_WRITE - write access,

FILE_GENERIC_EXECUTE - execute access,

DELETE - delete access,

WRITE_DAC - change access rights access,

WRITE_OWNER - change owner access,

FILE_ALL_ACCESS - full access,

MAXIMUM_ALLOWED - maximal allowed access.

It is also possible to use constants, applicable to any secure OS objects:

GENERIC_READ - read access,

GENERIC_WRITE - write access,

GENERIC_EXECUTE - execute access,

GENERIC_ALL - full access,

but in this case the function returns correspondingly values FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_GENERIC_EXECUTE, FILE_ALL_ACCESS (of course, if correspondent rights exist).

For example, to find out whether exists read and write access to the file "d:/Test.tmp", it is possible to use two ways:

Way 1:

Dim AccessRead As Boolean, AccessWrite As Boolean
    AccessRead = CheckFileAccess("d:/Test.tmp", _
                 FILE_GENERIC_READ) = FILE_GENERIC_READ
    AccessWrite = CheckFileAccess("d:/Test.tmp", _
                 FILE_GENERIC_WRITE) = FILE_GENERIC_WRITE
Way 2:
Dim AccessRead As Boolean, AccessWrite As Boolean
Dim AccessMask As Long
    AccessMask = CheckFileAccess("d:/Test.tmp", MAXIMUM_ALLOWED)
    AccessRead = (AccessMask _
                 And FILE_GENERIC_READ) = FILE_GENERIC_READ
    AccessWrite = (AccessMask _
                 And FILE_GENERIC_WRITE) = FILE_GENERIC_WRITE
In the first case call of CheckFileAccess function performs twice, in second case intermediate variable used.

This code has been viewed 78147 times.

Instructions: Copy the declarations and code below and paste directly into your VB project.


 

  1. 'PUT IN MODULE
  2. Option Explicit
  3. '   ********************************************
  4. '   *         ?2000 Sergey Merzlikin          *
  5. '   ********************************************
  6. ' Desired access rights constants
  7. Public Const MAXIMUM_ALLOWED           As Long = 
  8. Public Const DELETE                    As Long = 
  9. Public Const READ_CONTROL              As Long = 
  10. Public Const WRITE_DAC                 As Long = 
  11. Public Const WRITE_OWNER               As Long = 
  12. Public Const SYNCHRONIZE               As Long = 
  13. Public Const STANDARD_RIGHTS_READ      As Long = READ_CONTROL
  14. Public Const STANDARD_RIGHTS_WRITE     As Long = READ_CONTROL
  15. Public Const STANDARD_RIGHTS_EXECUTE   As Long = READ_CONTROL
  16. Public Const STANDARD_RIGHTS_REQUIRED  As Long = 
  17. Public Const FILE_READ_DATA            As Long = &H1   '  file & pipe
  18. Public Const FILE_LIST_DIRECTORY       As Long = &H1   '  directory
  19. Public Const FILE_ADD_FILE             As Long = &H2   '  directory
  20. Public Const FILE_WRITE_DATA           As Long = &H2   '  file & pipe
  21. Public Const FILE_CREATE_PIPE_INSTANCE As Long = &H4   '  named pipe
  22. Public Const FILE_ADD_SUBDIRECTORY     As Long = &H4   '  directory
  23. Public Const FILE_APPEND_DATA          As Long = &H4   '  file
  24. Public Const FILE_READ_EA              As Long = &H8   '  file & directory
  25. Public Const FILE_READ_PROPERTIES      As Long = FILE_READ_EA
  26. Public Const FILE_WRITE_EA             As Long = &H10  '  file & directory
  27. Public Const FILE_WRITE_PROPERTIES     As Long = FILE_WRITE_EA
  28. Public Const FILE_EXECUTE              As Long = &H20  '  file
  29. Public Const FILE_TRAVERSE             As Long = &H20  '  directory
  30. Public Const FILE_DELETE_CHILD         As Long = &H40  '  directory
  31. Public Const FILE_READ_ATTRIBUTES      As Long = &H80  '  all
  32. Public Const FILE_WRITE_ATTRIBUTES     As Long = &H100 '  all
  33. Public Const FILE_GENERIC_READ         As Long = (STANDARD_RIGHTS_READ _
  34.       Or FILE_READ_DATA Or FILE_READ_ATTRIBUTES _
  35.       Or FILE_READ_EA Or SYNCHRONIZE)
  36. Public Const FILE_GENERIC_WRITE        As Long = (STANDARD_RIGHTS_WRITE _
  37.       Or FILE_WRITE_DATA Or FILE_WRITE_ATTRIBUTES _
  38.       Or FILE_WRITE_EA Or FILE_APPEND_DATA Or SYNCHRONIZE)
  39. Public Const FILE_GENERIC_EXECUTE      As Long = (STANDARD_RIGHTS_EXECUTE _
  40.       Or FILE_READ_ATTRIBUTES Or FILE_EXECUTE Or SYNCHRONIZE)
  41. Public Const FILE_ALL_ACCESS           As Long = (STANDARD_RIGHTS_REQUIRED _
  42.       Or SYNCHRONIZE Or &H1FF&)
  43. Public Const GENERIC_READ              As Long = 
  44. Public Const GENERIC_WRITE             As Long = 
  45. Public Const GENERIC_EXECUTE           As Long = 
  46. Public Const GENERIC_ALL               As Long = 
  47. ' Types, constants and functions
  48. ' to work with access rights
  49. Public Const OWNER_SECURITY_INFORMATION As Long = 
  50. Public Const GROUP_SECURITY_INFORMATION As Long = 
  51. Public Const DACL_SECURITY_INFORMATION  As Long = 
  52. Public Const TOKEN_QUERY                As Long = 8
  53. Public Const SecurityImpersonation As Integer = 3
  54. Public Const ANYSIZE_ARRAY = 1
  55. Public Type GENERIC_MAPPING
  56.     GenericRead As Long
  57.     GenericWrite As Long
  58.     GenericExecute As Long
  59.     GenericAll As Long
  60. End Type
  61. Public Type LUID
  62.     LowPart As Long
  63.     HighPart As Long
  64. End Type
  65. Public Type LUID_AND_ATTRIBUTES
  66.     pLuid As LUID
  67.     Attributes As Long
  68. End Type
  69. Public Type PRIVILEGE_SET
  70.     PrivilegeCount As Long
  71.     Control As Long
  72.     Privilege(ANYSIZE_ARRAY) As LUID_AND_ATTRIBUTES
  73. End Type
  74. Public Declare Function GetFileSecurity Lib "advapi32.dll" _
  75.     Alias "GetFileSecurityA" (ByVal lpFileName As String, _
  76.     ByVal RequestedInformation As Long, pSecurityDescriptor As Byte, _
  77.     ByVal nLength As Long, lpnLengthNeeded As LongAs Long
  78. Public Declare Function AccessCheck Lib "advapi32.dll" _
  79.     (pSecurityDescriptor As ByteByVal ClientToken As Long, _
  80.     ByVal DesiredAccess As Long, GenericMapping As GENERIC_MAPPING, _
  81.     PrivilegeSet As PRIVILEGE_SET, PrivilegeSetLength As Long, _
  82.     GrantedAccess As Long, Status As LongAs Long
  83. Public Declare Function ImpersonateSelf Lib "advapi32.dll" _
  84.     (ByVal ImpersonationLevel As IntegerAs Long
  85. Public Declare Function RevertToSelf Lib "advapi32.dll" () As Long
  86. Public Declare Sub MapGenericMask Lib "advapi32.dll" (AccessMask As Long, _
  87.     GenericMapping As GENERIC_MAPPING)
  88. Public Declare Function OpenThreadToken Lib "advapi32.dll" _
  89.     (ByVal ThreadHandle As LongByVal DesiredAccess As Long, _
  90.     ByVal OpenAsSelf As Long, TokenHandle As LongAs Long
  91. Public Declare Function GetCurrentThread Lib "kernel32" () As Long
  92. Public Declare Function CloseHandle Lib "kernel32" _
  93.     (ByVal hObject As LongAs Long
  94. ' Types, constants and functions for OS version detection
  95. Public Type OSVERSIONINFO
  96.     dwOSVersionInfoSize As Long
  97.     dwMajorVersion As Long
  98.     dwMinorVersion As Long
  99.     dwBuildNumber As Long
  100.     dwPlatformId As Long
  101.     szCSDVersion As String * 128
  102. End Type
  103. Public Const VER_PLATFORM_WIN32_NT As Long = 2
  104. Public Declare Function GetVersionEx Lib "kernel32" Alias "GetVersionExA" _
  105.     (lpVersionInformation As OSVERSIONINFO) As Long
  106. ' Constant and function for detection of support
  107. ' of access rights by file system
  108. Public Const FS_PERSISTENT_ACLS As Long = 
  109. Public Declare Function GetVolumeInformation Lib "kernel32" _
  110.     Alias "GetVolumeInformationA" (ByVal lpRootPathName As String, _
  111.     ByVal lpVolumeNameBuffer As StringByVal nVolumeNameSize As Long, _
  112.     lpVolumeSerialNumber As Long, lpMaximumComponentLength As Long, _
  113.     lpFileSystemFlags As LongByVal lpFileSystemNameBuffer As String, _
  114.     ByVal nFileSystemNameSize As LongAs Long
  115. ' *-----------------------------------------------------------------------*
  116. ' CheckFileAccess function checks access rights to given file.
  117. ' DesiredAccess - bitmask of desired access rights.
  118. ' The function returns bitmask, which contains those bits of desired bitmask,
  119. ' which correspond with existing access rights.
  120. Private Function CheckFileAccess(Filename As String, _
  121.                 ByVal DesiredAccess As LongAs Long
  122. Dim r As Long, SecDesc() As Byte, SDSize As Long, hToken As Long
  123. Dim PrivSet As PRIVILEGE_SET, GenMap As GENERIC_MAPPING
  124. Dim Volume As String, FSFlags As Long
  125. ' Checking OS type
  126. If Not IsNT() Then
  127. ' Rights not supported. Returning -1.
  128.     CheckFileAccess = -1
  129.     Exit Function
  130. End If
  131. ' Checking access rights support by file system
  132. If Left$(Filename, 2) = "//" Then
  133. ' Path in UNC format. Extracting share name from it
  134.     r = InStr(3, Filename, "/")
  135.     If r = 0 Then
  136.         Volume = Filename & "/"
  137.     Else
  138.         Volume = Left$(Filename, r)
  139.     End If
  140. ElseIf Mid$(Filename, 2, 2) = ":/" Then
  141. ' Path begins with drive letter
  142.     Volume = Left$(Filename, 3)
  143. 'Else
  144. ' If path not set, we are leaving Volume blank.
  145. ' It retutns information about current drive.
  146. End If
  147. ' Getting information about drive
  148. GetVolumeInformation Volume, vbNullString, 0, ByVal 0&, _
  149.                     ByVal 0&, FSFlags, vbNullString, 0
  150. If (FSFlags And FS_PERSISTENT_ACLS) = 0 Then
  151. ' Rights not supported. Returning -1.
  152.     CheckFileAccess = -1
  153.     Exit Function
  154. End If
  155. ' Determination of buffer size
  156. GetFileSecurity Filename, OWNER_SECURITY_INFORMATION _
  157.         Or GROUP_SECURITY_INFORMATION _
  158.         Or DACL_SECURITY_INFORMATION, 0, 0, SDSize
  159. If Err.LastDllError <> 122 Then
  160. ' Rights not supported. Returning -1.
  161.     CheckFileAccess = -1
  162.     Exit Function
  163. End If
  164. If SDSize = 0 Then Exit Function
  165. ' Buffer allocation
  166. ReDim SecDesc(1 To SDSize)
  167. ' Once more call of function
  168. ' to obtain Security Descriptor
  169. If GetFileSecurity(Filename, OWNER_SECURITY_INFORMATION _
  170.         Or GROUP_SECURITY_INFORMATION _
  171.         Or DACL_SECURITY_INFORMATION, _
  172.         SecDesc(1), SDSize, SDSize) = 0 Then
  173. ' Error. We must return no access rights.
  174.     Exit Function
  175. End If
  176. ' Adding Impersonation Token for thread
  177. ImpersonateSelf SecurityImpersonation
  178. ' Opening of Token of current thread
  179. OpenThreadToken GetCurrentThread(), TOKEN_QUERY, 0, hToken
  180. If hToken <> 0 Then
  181. ' Filling GenericMask type
  182.     GenMap.GenericRead = FILE_GENERIC_READ
  183.     GenMap.GenericWrite = FILE_GENERIC_WRITE
  184.     GenMap.GenericExecute = FILE_GENERIC_EXECUTE
  185.     GenMap.GenericAll = FILE_ALL_ACCESS
  186. ' Conversion of generic rights
  187. ' to specific file access rights
  188.     MapGenericMask DesiredAccess, GenMap
  189. ' Checking access
  190.     AccessCheck SecDesc(1), hToken, DesiredAccess, GenMap, _
  191.             PrivSet, Len(PrivSet), CheckFileAccess, r
  192.     CloseHandle hToken
  193. End If
  194. ' Deleting Impersonation Token
  195. RevertToSelf
  196. End Function
  197. ' *-----------------------------------------------------------------------*
  198. ' IsNT() function returns True, if the program works
  199. ' in Windows NT or Windows 2000 operating system, and False
  200. ' otherwise.
  201. Private Function IsNT() As Boolean
  202. Dim OSVer As OSVERSIONINFO
  203. OSVer.dwOSVersionInfoSize = Len(OSVer)
  204. GetVersionEx OSVer
  205. IsNT = (OSVer.dwPlatformId = VER_PLATFORM_WIN32_NT)
  206. End Function
  207. ' *-----------------------------------------------------------------------*

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章