View Issue Details

IDProjectCategoryView StatusLast Update
0005040JEDI Code LibraryJclSysInfopublic2009-12-17 10:18
ReporterHeikoAdamsAssigned Tooutchy 
PrioritynormalSeverityfeatureReproducibilityalways
Status resolvedResolutionfixed 
PlatformDesktop WorkstationOSWindows 7OS Version6.1 Build 7600
Product VersionVersion 2.1 
Target VersionFixed in VersionVersion 2.2 
Summary0005040: New Function: IsPowerUser
DescriptionThe following function is copy of IsAdministrator but modified to check if the logged-in user is member of the powerusers group.

function IsPowerUser: Boolean;
var
  psidAdmin: Pointer;
  Token: THandle;
  Count: DWORD;
  TokenInfo: PTokenGroups;
  HaveToken: Boolean;
  I: Integer;
const
  SE_GROUP_USE_FOR_DENY_ONLY = $00000010;
begin
  Result := (IsWinVista or IsWin7);

  if Result then
    Exit;
    
  psidAdmin := nil;
  TokenInfo := nil;
  HaveToken := False;
  try
    Token := 0;
    HaveToken := OpenThreadToken(GetCurrentThread, TOKEN_QUERY, True, Token);
    if (not HaveToken) and (GetLastError = ERROR_NO_TOKEN) then
      HaveToken := OpenProcessToken(GetCurrentProcess, TOKEN_QUERY, Token);
    if HaveToken then
    begin
      {$IFDEF FPC}
      Win32Check(AllocateAndInitializeSid(SECURITY_NT_AUTHORITY, 2,
        SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0, 0,
        psidAdmin));
      if GetTokenInformation(Token, TokenGroups, nil, 0, @Count) or
       (GetLastError <> ERROR_INSUFFICIENT_BUFFER) then
         RaiseLastOSError;
      TokenInfo := PTokenGroups(AllocMem(Count));
      Win32Check(GetTokenInformation(Token, TokenGroups, TokenInfo, Count, @Count));
      {$ELSE FPC}
      Win32Check(AllocateAndInitializeSid(SECURITY_NT_AUTHORITY, 2,
        SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0, 0,
        psidAdmin));
      if GetTokenInformation(Token, TokenGroups, nil, 0, Count) or
       (GetLastError <> ERROR_INSUFFICIENT_BUFFER) then
         RaiseLastOSError;
      TokenInfo := PTokenGroups(AllocMem(Count));
      Win32Check(GetTokenInformation(Token, TokenGroups, TokenInfo, Count, Count));
      {$ENDIF FPC}
      for I := 0 to TokenInfo^.GroupCount - 1 do
      begin
        {$RANGECHECKS OFF} // Groups is an array [0..0] of TSIDAndAttributes, ignore ERangeError
        Result := EqualSid(psidAdmin, TokenInfo^.Groups[I].Sid);
        if Result then
        begin
          //consider denied ACE with Administrator SID
          Result := TokenInfo^.Groups[I].Attributes and SE_GROUP_USE_FOR_DENY_ONLY
              <> SE_GROUP_USE_FOR_DENY_ONLY;
          Break;
        end;
        {$IFDEF RANGECHECKS_ON}
        {$RANGECHECKS ON}
        {$ENDIF RANGECHECKS_ON}
      end;
    end;
  finally
    if TokenInfo <> nil then
      FreeMem(TokenInfo);
    if HaveToken then
      CloseHandle(Token);
    if psidAdmin <> nil then
      FreeSid(psidAdmin);
  end;
end;
TagsIsPowerUser, JclSysInfo
Fixed in GIT commit
Fixed in SVN revision3091
IDE versionBDS 2006

Activities

HeikoAdams

2009-12-03 08:13

reporter   ~0016922

Last edited: 2009-12-03 08:27

Update: Return true if logged in user is admin

function IsPowerUser: Boolean;
var
  psidAdmin: Pointer;
  Token: THandle;
  Count: DWORD;
  TokenInfo: PTokenGroups;
  HaveToken: Boolean;
  I: Integer;
const
  SE_GROUP_USE_FOR_DENY_ONLY = $00000010;
begin
  Result := (IsWinVista or IsWin7) or IsAdministrator;

  if Result then
    Exit;
    
  psidAdmin := nil;
  TokenInfo := nil;
  HaveToken := False;
  try
    Token := 0;
    HaveToken := OpenThreadToken(GetCurrentThread, TOKEN_QUERY, True, Token);
    if (not HaveToken) and (GetLastError = ERROR_NO_TOKEN) then
      HaveToken := OpenProcessToken(GetCurrentProcess, TOKEN_QUERY, Token);
    if HaveToken then
    begin
      {$IFDEF FPC}
      Win32Check(AllocateAndInitializeSid(SECURITY_NT_AUTHORITY, 2,
        SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0, 0,
        psidAdmin));
      if GetTokenInformation(Token, TokenGroups, nil, 0, @Count) or
       (GetLastError <> ERROR_INSUFFICIENT_BUFFER) then
         RaiseLastOSError;
      TokenInfo := PTokenGroups(AllocMem(Count));
      Win32Check(GetTokenInformation(Token, TokenGroups, TokenInfo, Count, @Count));
      {$ELSE FPC}
      Win32Check(AllocateAndInitializeSid(SECURITY_NT_AUTHORITY, 2,
        SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0, 0,
        psidAdmin));
      if GetTokenInformation(Token, TokenGroups, nil, 0, Count) or
       (GetLastError <> ERROR_INSUFFICIENT_BUFFER) then
         RaiseLastOSError;
      TokenInfo := PTokenGroups(AllocMem(Count));
      Win32Check(GetTokenInformation(Token, TokenGroups, TokenInfo, Count, Count));
      {$ENDIF FPC}
      for I := 0 to TokenInfo^.GroupCount - 1 do
      begin
        {$RANGECHECKS OFF} // Groups is an array [0..0] of TSIDAndAttributes, ignore ERangeError
        Result := EqualSid(psidAdmin, TokenInfo^.Groups[I].Sid);
        if Result then
        begin
          //consider denied ACE with Administrator SID
          Result := TokenInfo^.Groups[I].Attributes and SE_GROUP_USE_FOR_DENY_ONLY
              <> SE_GROUP_USE_FOR_DENY_ONLY;
          Break;
        end;
        {$IFDEF RANGECHECKS_ON}
        {$RANGECHECKS ON}
        {$ENDIF RANGECHECKS_ON}
      end;
    end;
  finally
    if TokenInfo <> nil then
      FreeMem(TokenInfo);
    if HaveToken then
      CloseHandle(Token);
    if psidAdmin <> nil then
      FreeSid(psidAdmin);
  end;
end;

outchy

2009-12-03 21:31

administrator   ~0016925

I don't think this function should return true when the user is an administrator.

HeikoAdams

2009-12-07 17:15

reporter   ~0016976

IMHO it should return true because a admin is higher than a poweruser.

Maybe the description should be modified to "checks if the logged-in user is member of the powerusers- or admintrators-group."

I can't see any practical reaseon why it should return false if the logged-in user is administrator.

outchy

2009-12-07 20:00

administrator   ~0016977

You're mixing user groups and group rights.

A user can be a member of the administrator group, while it is not a member of the poweruser group, while the security strategy gives him all the rights superusers have.

the function should return whether the user is a member of the poweruser group or not, it should not make hypotheses on whether the administrator rights are a superset of the superuser rights.

Anyway we can introduce a new function IsPowerUserOrAdministrator that will behave like the one you proposed.

HeikoAdams

2009-12-08 13:33

reporter   ~0016980

Okay, you're right. So just forget the update and let's use the function from the first post ;-)

outchy

2009-12-08 22:23

administrator   ~0016985

committed in revision 3091.

I refactored the code to avoid duplicates and generalized to all group aliases.

All the new available functions are:
function IsGroupMember(RelativeGroupID: DWORD): Boolean;
function IsUser: Boolean;
function IsGuest: Boolean;
function IsPowerUser: Boolean;
function IsAccountOperator: Boolean;
function IsSystemOperator: Boolean;
function IsPrintOperator: Boolean;
function IsBackupOperator: Boolean;
function IsReplicator: Boolean;
function IsRASServer: Boolean;
function IsPreWin2000CompAccess: Boolean;
function IsRemoteDesktopUser: Boolean;
function IsNetworkConfigurationOperator: Boolean;
function IsIncomingForestTrustBuilder: Boolean;
function IsMonitoringUser: Boolean;
function IsLoggingUser: Boolean;
function IsAuthorizationAccess: Boolean;
function IsTSLicenseServer: Boolean;

Issue History

Date Modified Username Field Change
2009-12-02 17:12 HeikoAdams New Issue
2009-12-02 17:12 HeikoAdams IDE version => BDS 2006
2009-12-03 08:13 HeikoAdams Note Added: 0016922
2009-12-03 08:13 HeikoAdams Tag Attached: JclSysInfo
2009-12-03 08:13 HeikoAdams Tag Attached: IsPowerUser
2009-12-03 08:27 HeikoAdams Note Edited: 0016922
2009-12-03 21:31 outchy Note Added: 0016925
2009-12-07 17:15 HeikoAdams Note Added: 0016976
2009-12-07 20:00 outchy Note Added: 0016977
2009-12-08 13:33 HeikoAdams Note Added: 0016980
2009-12-08 22:23 outchy Note Added: 0016985
2009-12-08 22:23 outchy Assigned To => outchy
2009-12-08 22:23 outchy Status new => feedback
2009-12-17 10:18 outchy Fixed in revision => 3091
2009-12-17 10:18 outchy Status feedback => resolved
2009-12-17 10:18 outchy Fixed in Version => Version 2.2 (Subversion repository/Daily zips)
2009-12-17 10:18 outchy Resolution open => fixed