check if user belongs to a certain group

delphi package - easy access to security apis
Post Reply
zifnabbe
Posts: 7
Joined: Wed May 03, 2006 2:04 pm

check if user belongs to a certain group

Post by zifnabbe »

Hi,

Is it possible to find out if a user belongs to a certain group?

Thanks
Nico Bendlin
Posts: 46
Joined: Fri Apr 28, 2006 1:17 pm

Post by Nico Bendlin »

Please define the context of "user".
If you are refferring to the user token of the current thread or current process, you might have a look at IsUserAnAdmin/SHTestTokenMembership/CheckTokenMembership.
(if you need a pre-Win2K emulation of CheckTokenMembership in Delphi: http://www.delphipraxis.net/post730030.html#730030)
If you have to deal with non-elevated admins, you might have a look at IsTokenRestricted/GetTokenInformation(TokenElevationType).
zifnabbe
Posts: 7
Joined: Wed May 03, 2006 2:04 pm

Post by zifnabbe »

With user I mean the current user account logged into windows.
I would like to know if that user belongs to a certain group (active directory). If so, I allow the user to use a certain application otherwise (s)he may not use it.
madshi
Site Admin
Posts: 10754
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

Check out NetUserGetGroups and NetGroupGetUsers and related APIs. These also work for ActiveDirectory. You can also use COM objects to access ActiveDirectory. But I find that more complicated than using the "old" APIs.

madSecurity currently does not contain functions to list group users.
iconic
Site Admin
Posts: 1065
Joined: Wed Jun 08, 2005 5:08 am

Post by iconic »

@Nico: IsUserAnAdminIn() just wraps CheckTokenMembership() and isn't advised to be called directly anymore. In the past I've used IsNTAdmin() API (advpack.dll) to test for admin rights but unfortunately this no longer works correctly under Vista variants. I just compare security identifiers from my current process to the admin group via OpenProcessToken->GetTokenInformation->EqualSID.
This seems to work fine on Windows 2000 - Windows Vista.

--Iconic
Nico Bendlin
Posts: 46
Joined: Fri Apr 28, 2006 1:17 pm

Post by Nico Bendlin »

iconic wrote:@Nico: IsUserAnAdminIn() just wraps CheckTokenMembership() and isn't advised to be called directly anymore.
Who gave/gives this advice?
(edit: Well, there is a comment in MSDN now :))

The linked Delphi source emulates the APIs if they are not present.
iconic
Site Admin
Posts: 1065
Joined: Wed Jun 08, 2005 5:08 am

Post by iconic »

@Nico,
Your emulation seems useful. My unemulated implementation is very similar to the methods that you invoke to check for admin rights. I'm actually very surprised that Microsoft has never "officially" backed an API to check for admin rights definitively. It would be nice to have one reliable API not change from the very first NT release to the current Vista build.

Code: Select all

function UserIsAdmin: BOOL;
const
  SECURITY_BUILTIN_DOMAIN_RID = $00000020;
        DOMAIN_ALIAS_RID_ADMINS = $00000220;
var
              hToken: ULONG;
               ulRet: ULONG;
          lpSIDAdmin: Pointer;
                   i: ULONG;
           sidNtAuth: SID_IDENTIFIER_AUTHORITY;
              TokInf: Array [0..$FF] of ULONG;
               lpGrp: ^_TOKEN_GROUPS;
begin
  result := False;
  ZeroMemory(@sidNtAuth.Value, 6);
  ulRet := 0;
  sidNtAuth.Value[5] := 5;
  lpGrp := @TokInf;
  if not OpenProcessToken(DWORD(-1), TOKEN_READ, hToken) then exit;
  if GetTokenInformation(hToken, TokenGroups, @TokInf, $400, ulRet) and (ulRet > 0) then
  begin
  AllocateAndInitializeSid(sidNtAuth, 2, SECURITY_BUILTIN_DOMAIN_RID,
                           DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, lpSIDAdmin);
  for i := 0 to lpGrp^.GroupCount -1 do
    begin
      result := EqualSID(lpsidAdmin, lpGrp^.Groups[i].SID);
      if (result) then break;
    end;
    FreeSID(lpsidAdmin);
  end;
  CloseHandle(hToken);
end;
Nice work!

--Iconic
Nico Bendlin
Posts: 46
Joined: Fri Apr 28, 2006 1:17 pm

Post by Nico Bendlin »

EqualSID() - without the check if the SID is disabled in the token - will lead to another behaviour than IsUserAnAdmin(). All functions of this kind are intended as an "access check" - but your function will return false positives for "limited" tokens. E.g. in Windows XP [Shift+RMB] on an executable, choose "Run as..." and enable the checkbox to limit the token. Windows XP will just disable the admin SID in the token. In this case your function still returns TRUE. If this is intended (your function is not intended as "access check", but as "group check"), this is the wrong way of doing it - because Windows is free to completely remove the SID from the new token. As I mentioned above, there other functions available to check for "is token limited", "is token un-elevated", and "is the user account in the token a member of group x" (a completely different story).

This has always been a source of confusion, IsUserAnAdmin() and similar do not answer the question "Is the user account included in the token a member of group x?", but they will tell you "Has the token the rights to access an object that is accessible by members of group x?"

Best regards,
Nico Bendlin
iconic
Site Admin
Posts: 1065
Joined: Wed Jun 08, 2005 5:08 am

Post by iconic »

True, it's a small access check with no real sanity checks, it's all I really need however for any programs that I am currently developing. If in the future I come across the need to have a more "bullet proof", versatile admin access checking function I will definitely look back at your emulated functions. Your link is much appreciated to the forum and I'm sure others can benefit from this too.

--Iconic
zifnabbe
Posts: 7
Joined: Wed May 03, 2006 2:04 pm

Post by zifnabbe »

thanks for all the advice. I'll check these asap. Right now I'm in the middle of a house move and have very limited access to internet.
Post Reply