Check File, Folder Permissions [Win_Func]

Share your advanced PureBasic knowledge/code with the community.
User avatar
Thunder93
Addict
Addict
Posts: 1788
Joined: Tue Mar 21, 2006 12:31 am
Location: Canada

Check File, Folder Permissions [Win_Func]

Post by Thunder93 »

Code: Select all

; Desired access rights constants
#MAXIMUM_ALLOWED = $2000000
#DELETE = $10000
#READ_CONTROL = $20000
#WRITE_DAC = $40000
#WRITE_OWNER = $80000
#SYNCHRONIZE = $100000

#STANDARD_RIGHTS_READ     = #READ_CONTROL
#STANDARD_RIGHTS_WRITE    = #READ_CONTROL
#STANDARD_RIGHTS_EXECUTE  = #READ_CONTROL
#STANDARD_RIGHTS_REQUIRED = $F0000

#FILE_READ_DATA            = $1             ; file & pipe
#FILE_LIST_DIRECTORY       = $1             ; directory
#FILE_ADD_FILE             = $2             ; directory
#FILE_WRITE_DATA           = $2             ; file & pipe
#FILE_CREATE_PIPE_INSTANCE = $4             ; named pipe
#FILE_ADD_SUBDIRECTORY     = $4             ; directory
#FILE_APPEND_DATA          = $4             ; file
#FILE_READ_EA              = $8             ; file & directory
#FILE_READ_PROPERTIES      = #FILE_READ_EA
#FILE_WRITE_EA             = $10            ; file & directory
#FILE_WRITE_PROPERTIES     = #FILE_WRITE_EA
#FILE_EXECUTE              = $20            ; file
#FILE_TRAVERSE             = $20            ; directory
#FILE_DELETE_CHILD         = $40            ; directory
#FILE_READ_ATTRIBUTES      = $80            ; all
#FILE_WRITE_ATTRIBUTES     = $100           ; all

#FILE_GENERIC_READ = #STANDARD_RIGHTS_READ | #FILE_READ_DATA | #FILE_READ_ATTRIBUTES | #FILE_READ_EA | #SYNCHRONIZE
#FILE_GENERIC_WRITE = #STANDARD_RIGHTS_WRITE | #FILE_WRITE_DATA | #FILE_WRITE_ATTRIBUTES | #FILE_WRITE_EA | #FILE_APPEND_DATA | #SYNCHRONIZE
#FILE_GENERIC_EXECUTE = #STANDARD_RIGHTS_EXECUTE | #FILE_READ_ATTRIBUTES | #FILE_EXECUTE | #SYNCHRONIZE
#FILE_ALL_ACCESS = #STANDARD_RIGHTS_REQUIRED | #SYNCHRONIZE | $1FF


#GENERIC_READ = $80000000
#GENERIC_WRITE = $40000000
#GENERIC_EXECUTE = $20000000
#GENERIC_ALL = $10000000

; Types, constants And functions
; To work With access rights
#OWNER_SECURITY_INFORMATION = $1
#GROUP_SECURITY_INFORMATION = $2
#DACL_SECURITY_INFORMATION  = $4
#TOKEN_QUERY                = 8
#SecurityImpersonation      = 3
#ANYSIZE_ARRAY              = 1

; Constant And function For detection of support
; of access rights by file system
#FS_PERSISTENT_ACLS = $8


; CheckFileAccess function checks access rights To given file.
; DesiredAccess - bitmask of desired access rights.
; The function returns bitmask, which contains those bits of desired bitmask,
; which correspond With existing access rights.
Procedure.l CheckFileAccess(Filename.s, DesiredAccess.l)
  Protected.l r, SDSize, FSFlags, Volume.s, hToken.i

  ; Checking access rights support by file system
  If Left(Filename, 2) = "\\"
    ; Path in UNC format. Extracting share name from it
    r = FindString(Filename, "\", 3)
    If r = 0
      Volume = Filename + "\"
    Else
      Volume = Left(Filename, r)
    EndIf

  ElseIf Mid(Filename, 2, 2) = ":\"
    ; Path begins With drive letter
    Volume = Left(Filename, 3)
    ;Else
    ; If path Not set, we are leaving Volume blank.
    ; It returns information about current drive.
  EndIf

  ; Getting information about drive
  GetVolumeInformation_(Volume, #Null, 0, 0, 0, @FSFlags, #Null, 0)

  If FSFlags And #FS_PERSISTENT_ACLS = 0
    ; Rights Not supported.
    ProcedureReturn -1
  EndIf

  RequestedInformation = #OWNER_SECURITY_INFORMATION | #GROUP_SECURITY_INFORMATION | #DACL_SECURITY_INFORMATION

  ; Determination of buffer size
  Retr = GetFileSecurity_(@Filename, RequestedInformation, 0, 0, @SDSize)

  If Not Retr
    If GetLastError_() <> 122
      ; Rights Not supported.
      ProcedureReturn -1
    EndIf
  EndIf

  If SDSize = 0 : ProcedureReturn -1 : EndIf

  ; Buffer allocation
  *SecDesc = AllocateMemory(SDSize)
  If Not *SecDesc
    ProcedureReturn -1
  EndIf


  ; Once more call of function
  ; To obtain Security Descriptor
  If GetFileSecurity_(@Filename, RequestedInformation, *SecDesc, SDSize, @SDSize) = 0
    ; Error. We must Return no access rights.
    ProcedureReturn 0
  EndIf

  ; Adding Impersonation Token For thread
  ImpersonateSelf_(#SecurityImpersonation)

  ; Opening of Token of current thread
  OpenThreadToken_(GetCurrentThread_(), #TOKEN_QUERY, 0, @hToken)


  If hToken <> 0
    ; Filling GenericMask type
    GenMap.GENERIC_MAPPING
    GenMap\GenericRead    = #FILE_GENERIC_READ
    GenMap\GenericWrite   = #FILE_GENERIC_WRITE
    GenMap\GenericExecute = #FILE_GENERIC_EXECUTE
    GenMap\GenericAll     = #FILE_ALL_ACCESS

    ; Conversion of generic rights to specific file access rights
    ;... MapGenericMask DesiredAccess, GenMap
    MapGenericMask_(@DesiredAccess, GenMap)
    PrivSet.PRIVILEGE_SET

    ; Checking access
    Size = SizeOf(PrivSet)

    AccessCheck_(*SecDesc, hToken, DesiredAccess, GenMap, PrivSet.PRIVILEGE_SET, @Size, @CheckFileAccess, @r)

    CloseHandle_(hToken)
  EndIf

  ; Deleting Impersonation Token
  RevertToSelf_()

  ;Free memory allocation
  FreeMemory(*SecDesc)

  ProcedureReturn CheckFileAccess
EndProcedure


CompilerIf #PB_Compiler_IsMainFile
  FileOrFolderName$ = GetEnvironmentVariable("SystemRoot")+"\notepad.exe"

  If CheckFileAccess(FileOrFolderName$, #FILE_GENERIC_READ) = #FILE_GENERIC_READ
    AccessRead2$ = "#FILE_GENERIC_READ"
  Else
    AccessRead2$ = "NO"
  EndIf  
    
  If CheckFileAccess(FileOrFolderName$, #FILE_GENERIC_WRITE) = #FILE_GENERIC_WRITE
    AccessWrite2$ = "#FILE_GENERIC_WRITE"
  Else
    AccessWrite2$ = "NO"
  EndIf

  MessageRequester("File Or Folder: Permissions", FileOrFolderName$+#LF$+#LF$+"Write permission is " + AccessWrite2$ + #CRLF$+#CRLF$+
                                                  "Read permission is " + AccessRead2$, #PB_MessageRequester_Ok)


  FileOrFolderName$ = GetEnvironmentVariable("LocalAppData")
  
  If CheckFileAccess(FileOrFolderName$, #FILE_GENERIC_READ) = #FILE_GENERIC_READ
    AccessRead2$ = "#FILE_GENERIC_READ"
  Else
    AccessRead2$ = "NO"
  EndIf  
    
  If CheckFileAccess(FileOrFolderName$, #FILE_GENERIC_WRITE) = #FILE_GENERIC_WRITE
    AccessWrite2$ = "#FILE_GENERIC_WRITE"
  Else
    AccessWrite2$ = "NO"
  EndIf

  MessageRequester("File Or Folder: Permissions", FileOrFolderName$+#LF$+#LF$+"Write permission is " + AccessWrite2$ + #CRLF$+#CRLF$+
                                                  "Read permission is " + AccessRead2$, #PB_MessageRequester_Ok)
CompilerEndIf
ʽʽSuccess is almost totally dependent upon drive and persistence. The extra energy required to make another effort or try another approach is the secret of winning.ʾʾ --Dennis Waitley