AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Win32/Win64 API (native code) Delphi Per ProcessId prüfen, ob der Benutzer Admin ist (oder: ProcessId -> UserTokenHandle)
Thema durchsuchen
Ansicht
Themen-Optionen

Per ProcessId prüfen, ob der Benutzer Admin ist (oder: ProcessId -> UserTokenHandle)

Ein Thema von CodeX · begonnen am 15. Aug 2014 · letzter Beitrag vom 4. Sep 2014
Antwort Antwort
Seite 1 von 2  1 2      
CodeX

Registriert seit: 30. Okt 2004
475 Beiträge
 
Delphi 12 Athens
 
#1

Per ProcessId prüfen, ob der Benutzer Admin ist (oder: ProcessId -> UserTokenHandle)

  Alt 15. Aug 2014, 02:29
Ich habe heute sehr viel Zeit mit diesem Problem verbracht und weiß irgendwie nicht mehr weiter. Vielleicht ist es auch nur eine Kleinigkeit oder ein blöder Denkfehler.

Grundsätzliche Problemstellung: Aus einem Service heraus anhand der bereits vorhandenen ProcessId eines laufenden Programms herausfinden, ob der zugehörige Benutzer Mitglied der Administratorgruppe ist.

Im Programm wird die ProcessId per GetCurrentProcessId bestimmt und an den Service übermittelt (darauf habe ich nur bedingt Einfluss). Im Service muss ich nun mit dieser ProcessId arbeiten. Meine Herangehensweise ist nun, dass ich darüber das zugehörige UserToken bzw. das UserTokenHandle bestimme und dieses per MSDN-Library durchsuchenCheckTokenMembership prüfe.
Delphi-Quellcode:
// Variante 1 mit JWSCL (Jedi Security Library) (verkürzt):
  var UserToken: TJwSecurityToken;
  UserToken := TJwSecurityToken.CreateTokenByProcessId(ProcessId, MAXIMUM_ALLOWED);
  bAdmin := UserInGroup(DOMAIN_ALIAS_RID_ADMINS, UserToken.TokenHandle);

// Variante 2:
  var hProcessHandle, hUserToken: THandle;
  hProcessHandle := OpenProcess(PROCESS_ALL_ACCESS, False, ProcessId);
  if hProcessHandle <> 0 then
  try
    if OpenProcessToken(hProcessHandle, TOKEN_ALL_ACCESS, hUserToken) then
      bAdmin := UserInGroup(DOMAIN_ALIAS_RID_ADMINS, hUserToken);
  finally
    CloseHandle(hProcessHandle);
  end;
Die UserInGroup-Funktion stammt in dem Fall von hier, ich teste es aber parallel auch mit dieser etwas umfangreicheren TokenTools-Unit mit gleichem Ergebnis.

Der Benutzer wird einfach nicht als Admin erkannt. Vermutlich hat es mit dem Service nichts zu tun, denn ich habe die komplette Abfrage mal in eine normale Anwendung gepackt, mit dem gleichen Ergebnis, aber der Vollständigkeit halber sei die Service-Nutzung erwähnt. Interessant ist aber, dass wenn ich in der Anwendung 0 als UserTokenHandle (= User des aktuellen Prozesses) verwende, der Test vollständig wie gewünscht funktioniert (Erkennen von Admin und Nicht-Admin)! Ich deute es daher so, dass die UserInGroup-Funktion bzw. die TokenTools-Unit richtig funktionieren, aber irgendetwas mit dem erzeugten UserTokenHandle nicht stimmt (und zwar in beiden Varianten), oder auch schon GetCurrentProcessId der falsche Ansatz ist.

Ich hoffe, es weiß jemand Rat...
Nur Delphi schafft es, einem ein Lächeln zu schenken, wenn man sich beim Schreiben von := vertippt und stattdessen ein :) erscheint.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#2

AW: Per ProcessId prüfen, ob der Benutzer Admin ist (oder: ProcessId -> UserTokenHand

  Alt 15. Aug 2014, 09:03
Was passiert, wenn du mal auf die wahnwitzige Idee kommst und die Rückgabewerte mit prüfen tätest?

Und warum wurde hUserToken nicht wieder geschlossen?

z.B.:
Delphi-Quellcode:
  hProcessHandle := OpenProcess(PROCESS_ALL_ACCESS, False, ProcessId);
  if hProcessHandle = 0 then
    RaiseLasrOSError; // man mag es nicht glauben, aber viele APIs sagen, warum sie nicht funktionierten
  try
    if not OpenProcessToken(hProcessHandle, TOKEN_ALL_ACCESS, hUserToken) then
      RaiseLasrOSError;
    try
      bAdmin := UserInGroup(DOMAIN_ALIAS_RID_ADMINS, hUserToken);
    finally
      CloseHandle(hUserToken); // das fehlte auch noch
    end;
  finally
    CloseHandle(hProcessHandle);
  end



function UserInGroup(Group: DWORD; hUserToken: ...): Boolean;
var
  pIdentifierAuthority: TSIDIdentifierAuthority;
  pSid : Windows.PSID;
  IsMember: BOOL;
begin
  pIdentifierAuthority := SECURITY_NT_AUTHORITY;
  Result := AllocateAndInitializeSid(pIdentifierAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, Group, 0, 0, 0, 0, 0, 0, pSid);
  if Result then
    try
      if not CheckTokenMembership(hUserToken, pSid, IsMember) then
        RaiseLastOSError;
      Result := IsMember;
    finally
      FreeSid(pSid);
    end
  else
    RaiseLastOSError;
end;
$2B or not $2B

Geändert von himitsu (15. Aug 2014 um 09:08 Uhr)
  Mit Zitat antworten Zitat
CodeX

Registriert seit: 30. Okt 2004
475 Beiträge
 
Delphi 12 Athens
 
#3

AW: Per ProcessId prüfen, ob der Benutzer Admin ist (oder: ProcessId -> UserTokenHand

  Alt 15. Aug 2014, 10:48
Kurz vorab: Ich habe den geposteten Code stark gekützt. Im Original-Code habe ich mehrere Debug-Log-Ausgaben und auch alle Handles werden geschlossen (das hätte ich natürlich auch mitkopieren sollen).

Was ich allerdings tatsächlich noch nicht gemacht hatte, die bereits gegebenen Funktionen mit RaiseLastOSError-Ausgaben auszustatten. Danke für den Hinweis!

CheckTokenMembership wirft:
Code:
'System Error. Code: 1309.
Ein Thread, der zurzeit nicht die Identität eines Clients angenommen hat, hat versucht, ein Identitätstoken einem Vorgang zu unterziehen'.
Nur Delphi schafft es, einem ein Lächeln zu schenken, wenn man sich beim Schreiben von := vertippt und stattdessen ein :) erscheint.
  Mit Zitat antworten Zitat
CodeX

Registriert seit: 30. Okt 2004
475 Beiträge
 
Delphi 12 Athens
 
#4

AW: Per ProcessId prüfen, ob der Benutzer Admin ist (oder: ProcessId -> UserTokenHand

  Alt 15. Aug 2014, 11:48
Ich habe ein wenig recherchiert und bin nur etwas weiter. Zumindest bei der Jwscl-Variante muss das UserToken wohl erst konvertiert werden.
Ich vermute, das müsste so gehen:
Delphi-Quellcode:
  var UserToken: TJwSecurityToken;
  UserToken := TJwSecurityToken.CreateTokenByProcessId(ProcessId, MAXIMUM_ALLOWED);
  UserToken.ConvertToImpersonatedToken(SecurityImpersonation, MAXIMUM_ALLOWED); //<-NEU
  bAdmin := UserInGroup(DOMAIN_ALIAS_RID_ADMINS, UserToken.TokenHandle);
Zumindest wirft das keine Exception mehr. CheckTokenMembership schließt aber anschließend mit IsMember=False ab (was nicht stimmt).
Also entweder meine Konvertierung ist falsch oder es liegt noch wo anders dran.
In der zweiten Variante weiß ich nicht, wie ich das UserTokenHandle konvertieren könnte...

Edit1: Das beschriebene Ergebnis ist aus dem Service heraus (so wie ich es letztlich brauche)! Beim Test aus der Desktopanwendung scheint es zu funktionieren. Was muss man denn im Service anders machen?

Edit2: Für die zweite Variante wäre das wohl:
Delphi-Quellcode:
  if not OpenProcessToken(hProcessHandle, TOKEN_ALL_ACCESS, hUserToken) then
    RaiseLastOSError;
  try
    if not DuplicateToken(hUserToken, SecurityIdentification, @hUserTokenDuplicate) then //<-NEU
      RaiseLastOSError;
    try
      bAdmin := UserInGroup(DOMAIN_ALIAS_RID_ADMINS, hUserTokenDuplicate);
Aber das hat das gleiche Resultat wie der zuvor beschriebene Jwscl-Versuch: Das Ergebnis ist IsMember=False, was nicht stimmt, da das ProcessHandle von einer Anwendung stammt, die in einem Administrator-Account gestartet wurde.

Was stimmt denn da nicht? :'(
Nur Delphi schafft es, einem ein Lächeln zu schenken, wenn man sich beim Schreiben von := vertippt und stattdessen ein :) erscheint.

Geändert von CodeX (15. Aug 2014 um 15:00 Uhr)
  Mit Zitat antworten Zitat
CodeX

Registriert seit: 30. Okt 2004
475 Beiträge
 
Delphi 12 Athens
 
#5

AW: Per ProcessId prüfen, ob der Benutzer Admin ist (oder: ProcessId -> UserTokenHand

  Alt 28. Aug 2014, 00:32
Falls es jemanden interessieren sollte: Ich bin dem Problem auf die Spur gekommen. Die Ursache für das "falsche" Ergebnis der Abfrage liegt darin, dass anscheinend das UserToken bei einem durch UAC kontrollierten Benutzerkonto nicht wirklich den Gruppen-Benutzer representiert, den man glaubt zu prüfen. Das UserToken ist ein eingeschränktes Token (klar) und ist daher wohl automatisch lediglich Mitglied der normalen Benutzergruppe (nicht so klar). Das echte Token des eingeloggten Benutzers ist das LinkedToken davon. Dieses hat nicht nur die echten Administrator-Rechte sondern nur dieses lässt sich auf die korrekte Gruppenzugehörigkeit prüfen.
Ich wundere mich nur, dass ich dutzende Beispiele zur Prüfung der Gruppenzugehörigkeit gefunden habe, aber in keinem auch nur ein Wort zu dieser Problematik verloren wurde. Arbeiten alle mit Windows XP? Oder ohne UAC? Oder merkt einfach keiner, dass der Test ein falsches Ergebnis liefert?

Naja, hier ein bisschen Code dazu (nur der relevante Teil zur Veranschaulichung!), falls irgendwann mal jemand über das gleiche Problem stoßen sollte. In dem Fall habe ich es mit JWSCL gelöst.
Delphi-Quellcode:
...
  DuplicateTokenEx(UserToken.LinkedToken.TokenHandle, MAXIMUM_ALLOWED, nil, SecurityImpersonation, TokenPrimary, hElevatedToken);
  UserTokenElevated := TJwSecurityToken.CreateDuplicateExistingToken(hElevatedToken, MAXIMUM_ALLOWED);
  UserTokenElevated.ConvertToImpersonatedToken(SecurityImpersonation, MAXIMUM_ALLOWED);
  if UserInGroup(DOMAIN_ALIAS_RID_ADMINS, UserTokenElevated.TokenHandle) then
...
Nur Delphi schafft es, einem ein Lächeln zu schenken, wenn man sich beim Schreiben von := vertippt und stattdessen ein :) erscheint.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#6

AW: Per ProcessId prüfen, ob der Benutzer Admin ist (oder: ProcessId -> UserTokenHand

  Alt 28. Aug 2014, 09:52
Wirklich nicht klar?

Das UAC simuliert doch das, was die Leute sich weigerten zu machen => Das Arbeiten als Benutzer und nur Admin wenn nötig.
* Programme arbeiten standardmäßig mit "Benutzer"-Rechten
* und nur wenn nötig, werden nach Rückfrage die vollen Rechte einem Programm gewährt.

Somit sollte auch klar sein, daß die Token im Programm normalerweise nur den eingeschränkten Rechten entsprechen dürften, denn sonst könnte sich das Programm ja darüber mehr Rechte besorgen.
$2B or not $2B
  Mit Zitat antworten Zitat
CodeX

Registriert seit: 30. Okt 2004
475 Beiträge
 
Delphi 12 Athens
 
#7

AW: Per ProcessId prüfen, ob der Benutzer Admin ist (oder: ProcessId -> UserTokenHand

  Alt 28. Aug 2014, 11:45
Somit sollte auch klar sein, daß die Token im Programm normalerweise nur den eingeschränkten Rechten entsprechen dürften
Es geht ja eben nicht um die Prüfung von Rechten, sondern von einer Gruppenzugehörigkeit. Das sind zwei verschiedene Paar Schuhe!
DOMAIN_ALIAS_RID_ADMINS fragt nach der Gruppe und eben nicht nach den zugehörigen Rechten. Ein Mitglied der Administratorgruppe muss nicht zwingend Administratorrechte haben - diese können über andere Richtlinien wieder eingeschränkt worden sein. Und umgekehrt.

Aber wenn das alles so klar ist, warum hast Du dann nicht vorher drauf hingewiesen?
Zudem wundere ich mich, dass zum Thema "Gruppenzugehörigkeit in Delphi prüfen" keine einzige Seite, auf der Codebeispiele zur Prüfung zu finden sind, auf diesen Umstand hinweist. Alle beschreiben schlicht die Prüfung des normalen UserTokens, was anscheinend seit Vista totaler Quatsch ist.
Nur Delphi schafft es, einem ein Lächeln zu schenken, wenn man sich beim Schreiben von := vertippt und stattdessen ein :) erscheint.
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#8

AW: Per ProcessId prüfen, ob der Benutzer Admin ist (oder: ProcessId -> UserTokenHand

  Alt 28. Aug 2014, 13:12
Liste alle Mitglieder der Administratorengruppe auf und guck, ob ein Mitglied die SID des Benutzers hat, vom dem du wissen willst, ob er Admin-Privilegien hat.
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#9

AW: Per ProcessId prüfen, ob der Benutzer Admin ist (oder: ProcessId -> UserTokenHand

  Alt 28. Aug 2014, 13:42
Des Benutzers, welcher grade den Desktop sieht (der, unter dessen Account die Session läuft), oder des Benutzers, welcher das Programm gestartet hat?

"Ausführen als ..."



Im Prinzip gibt es locker mal 4 Benutzertoken, von welchen man sich schon einen aussuchen sollte.
- der von der Session (ich vermute mal den will man hier wohl will)
- der UAC-Eingeschränkte, welchen Programme standardmäßig bekommen
- "Ausführen als ..."
- "Ausführen als ..." mit UAC-einschränkung


Dann kann man das gerne weitertreiben
- weitere "Ausführen als ..." von anderen Prozessen
- per Impersonate umgebogene Rechte einzelner Threads
- ...
$2B or not $2B
  Mit Zitat antworten Zitat
CodeX

Registriert seit: 30. Okt 2004
475 Beiträge
 
Delphi 12 Athens
 
#10

AW: Per ProcessId prüfen, ob der Benutzer Admin ist (oder: ProcessId -> UserTokenHand

  Alt 28. Aug 2014, 13:47
Mein Usecase steht doch eigentlich schon in der Überschrift: ProcessId -> UserTokenHandle
Da gibt es imho keine Mehrdeutigkeiten, oder? Eine ProcessId kann nur zu einem Benutzer gehören und von diesem möchte ich wissen, ob er sich in der Administratorgruppe befindet.
Nur Delphi schafft es, einem ein Lächeln zu schenken, wenn man sich beim Schreiben von := vertippt und stattdessen ein :) erscheint.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:35 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz