EKON 11 - Promised Entry #3#

One of the things promised, which are on the Internet somewhere, but sometimes hard to find, was a code snippet which reliably returns, whether the program is started in administrative mode or not. This piece of code is similar to old known solutions, however under Vista the old version returned the user level, rather than the token under which the program was started. The following code works well under Windows Vista and older systems.

const
  SECURITY_NT_AUTHORITY: TSIDIdentifierAuthority = (Value: (0, 0, 0, 0, 0, 5));
  SECURITY_BUILTIN_DOMAIN_RID = $00000020;
  DOMAIN_ALIAS_RID_ADMINS = $00000220;
  SE_GROUP_ENABLED = $00000004;

function IsAdmin: Boolean;
var
  hAccessToken: THandle;
  ptgGroups: PTokenGroups;
  dwInfoBufferSize: DWORD;
  psidAdministrators: PSID;
  x: Integer;
  bSuccess: BOOL;
begin
  Result   := False;
  bSuccess := OpenThreadToken(GetCurrentThread, TOKEN_QUERY, True, hAccessToken);
  if not bSuccess then
    if GetLastError = ERROR_NO_TOKEN then
      bSuccess := OpenProcessToken(GetCurrentProcess, TOKEN_QUERY, hAccessToken);
  if bSuccess then
  begin
    GetTokenInformation(hAccessToken, TokenGroups, nil, 0, dwInfoBufferSize);
    ptgGroups := GetMemory(dwInfoBufferSize); 
    bSuccess := GetTokenInformation(hAccessToken, TokenGroups, ptgGroups, dwInfoBufferSize, dwInfoBufferSize);
    CloseHandle(hAccessToken);
    if bSuccess then
    begin
      AllocateAndInitializeSid(SECURITY_NT_AUTHORITY, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, psidAdministrators);
      {$R-}
      for x := 0 to ptgGroups.GroupCount - 1 do
      begin
        if (SE_GROUP_ENABLED = (ptgGroups.Groups[x].Attributes and SE_GROUP_ENABLED)) and EqualSid(psidAdministrators, ptgGroups.Groups[x].Sid) then
        begin
          Result := True;
          Break;
        end;
      end;
      {$R+}
      FreeSid(psidAdministrators);
    end;
    FreeMem(ptgGroups);
  end;
end;

Thanks to Olaf for pointing out the insufficient memory problem. Fixed in this sample.

Tuesday, October 02, 2007 10:35:01 AM (W. Europe Standard Time, UTC+01:00) #    Comments [2]  | 

 

Google AdSense


Thursday, October 04, 2007 10:47:30 AM (W. Europe Standard Time, UTC+01:00)
Hello Daniel,

Unfortunately, in the code given the buffer size when calling "GetTokenInformation" is too small in a lot of cases and leads to wrong results. To fix this first call "GetTokenInformation" with a "TokenInformationLength = 0". This returns the required buffer size in "ReturnLength".

GetTokenInformation(TokenHandle, TokenGroups, nil, 0, dwInfoBufferSize);
ptgGroups := GetMemory(dwInfoBufferSize);
bSuccess := GetTokenInformation(TokenHandle, TokenGroups, ptgGroups, dwInfoBufferSize, dwInfoBufferSize);

Furthermore, on Windows NT4 and better one could use the "IsUserAnAdmin" function exposed by "Shell32.dll":

function IsUserAnAdmin : bool; stdcall; external 'shell32.dll' index 680;

Note that this requires IE5 or higher to be installed.

Regards, Olaf
Olaf H.
Thursday, October 04, 2007 4:06:50 PM (W. Europe Standard Time, UTC+01:00)
Thanks Olaf,

I have fixed the sample above according to your comments. Makes sense too ;-) As for the IsUserAnAdmin function, which probably works in Vista to, it'll return the user type, however not the situation in which context the application runs on Windows Vista or Windows OS coming next.
Comments are closed.
All content © 2008, Daniel Wischnewski
On this page
Archives
Promoted Links
Blogroll OPML
My current Flickr Images
www.flickr.com
Dies ist ein Flickr Modul mit �ffentlichen Fotos und Videos von dwischnewski. Ihr eigenes Modul k�nnen Sie hier erstellen.
Recommendations
Sitemap
Special Pages
Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

Theme design by Jelle Druyts