Search code examples
delphipermissionswindows-7administrator

How to get permission level of a folder?


I want to detect a folder, if needs Administrator privilege level (using Delphi). Is it possible?

I wrote this Code. This is what exactly I want. But I want to do this using Windows standard functions.

// Check if You need Administrator-level access to create a folder
try
  mkdir(SDirectory + '\~TEST');
except
  on E: exception do
  begin
    if E.message = 'File access denied' then
    begin
      MessageBox(self.Handle,
        'You need Administrator-level access to create this folder', '', MB_ICONERROR);
      exit;
    end;
  end;
end;
RmDir(SDirectory + '\~TEST');

Solution

  • The following example is translated from this article. It can be used for determination if the file or directory has the access rights noticed in that article for every user, so if I ask for FILE_ALL_ACCESS then it means that everyone has the full access to the desired file or directory. Note that in the following code there's no exception handling and that I can't even remember when I've used VB last time so it might be wrong so take this as an inspiration and feel free to modify this post.

    const
      FILE_READ_DATA = $0001;
      FILE_WRITE_DATA = $0002;
      FILE_APPEND_DATA = $0004;
      FILE_READ_EA = $0008;
      FILE_WRITE_EA = $0010;
      FILE_EXECUTE = $0020;
      FILE_READ_ATTRIBUTES = $0080;
      FILE_WRITE_ATTRIBUTES = $0100;
      FILE_GENERIC_READ = (STANDARD_RIGHTS_READ or FILE_READ_DATA or
        FILE_READ_ATTRIBUTES or FILE_READ_EA or SYNCHRONIZE);
      FILE_GENERIC_WRITE = (STANDARD_RIGHTS_WRITE or FILE_WRITE_DATA or
        FILE_WRITE_ATTRIBUTES or FILE_WRITE_EA or FILE_APPEND_DATA or SYNCHRONIZE);
      FILE_GENERIC_EXECUTE = (STANDARD_RIGHTS_EXECUTE or FILE_READ_ATTRIBUTES or
        FILE_EXECUTE or SYNCHRONIZE);
      FILE_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED or SYNCHRONIZE or $1FF;
    
    function CheckFileAccess(const FileName: string; const CheckedAccess: Cardinal): Cardinal;
    var Token: Cardinal;
        Status: LongBool;
        Access: Cardinal;
        SecDescSize: Cardinal;
        PrivSetSize: Cardinal;
        PrivSet: PRIVILEGE_SET;
        Mapping: GENERIC_MAPPING;
        SecDesc: PSECURITY_DESCRIPTOR;
    begin
      Result := 0;
      GetFileSecurity(PChar(Filename), OWNER_SECURITY_INFORMATION or GROUP_SECURITY_INFORMATION or DACL_SECURITY_INFORMATION, nil, 0, SecDescSize);
      SecDesc := GetMemory(SecDescSize);
    
      if GetFileSecurity(PChar(Filename), OWNER_SECURITY_INFORMATION or GROUP_SECURITY_INFORMATION or DACL_SECURITY_INFORMATION, SecDesc, SecDescSize, SecDescSize) then
      begin
        ImpersonateSelf(SecurityImpersonation);
        OpenThreadToken(GetCurrentThread, TOKEN_QUERY, False, Token);
        if Token <> 0 then
        begin
          Mapping.GenericRead := FILE_GENERIC_READ;
          Mapping.GenericWrite := FILE_GENERIC_WRITE;
          Mapping.GenericExecute := FILE_GENERIC_EXECUTE;
          Mapping.GenericAll := FILE_ALL_ACCESS;
    
          MapGenericMask(Access, Mapping);
          PrivSetSize := SizeOf(PrivSet);
          AccessCheck(SecDesc, Token, CheckedAccess, Mapping, PrivSet, PrivSetSize, Access, Status);
          CloseHandle(Token);
          if Status then
            Result := Access;
        end;
      end;
    
      FreeMem(SecDesc, SecDescSize);
    end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      if CheckFileAccess('C:\Windows', FILE_ALL_ACCESS) = FILE_ALL_ACCESS then
        ShowMessage('C:\Windows has full access for everyone')
      else
        ShowMessage('Someone has no full access to C:\Windows');
    end;
    

    enter image description here
    with Delphi 2007 on 64-bit Windows 7 Enterprise SP 1


    Anyway much more easier would be to download JEDI Windows Security Code Library and follow the example like this one (I hope it works also for directories but I'm pretty sure it will).