![]() |
Per ProcessId prüfen, ob der Benutzer Admin ist (oder: ProcessId -> UserTokenHandle)
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
Delphi-Quellcode:
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
GetCurrentProcessId
![]()
Delphi-Quellcode:
Die UserInGroup-Funktion stammt in dem Fall von
// 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; ![]() ![]() 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... |
AW: Per ProcessId prüfen, ob der Benutzer Admin ist (oder: ProcessId -> UserTokenHand
Was passiert, wenn du mal auf die wahnwitzige Idee kommst und die Rückgabewerte mit prüfen tätest? :stupid:
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; |
AW: Per ProcessId prüfen, ob der Benutzer Admin ist (oder: ProcessId -> UserTokenHand
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:
:gruebel:
'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'. |
AW: Per ProcessId prüfen, ob der Benutzer Admin ist (oder: ProcessId -> UserTokenHand
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:
Zumindest wirft das keine Exception mehr. CheckTokenMembership schließt aber anschließend mit IsMember=False ab (was nicht stimmt).
var UserToken: TJwSecurityToken;
UserToken := TJwSecurityToken.CreateTokenByProcessId(ProcessId, MAXIMUM_ALLOWED); UserToken.ConvertToImpersonatedToken(SecurityImpersonation, MAXIMUM_ALLOWED); //<-NEU bAdmin := UserInGroup(DOMAIN_ALIAS_RID_ADMINS, UserToken.TokenHandle); 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:
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.
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); Was stimmt denn da nicht? :'( |
AW: Per ProcessId prüfen, ob der Benutzer Admin ist (oder: ProcessId -> UserTokenHand
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 ... |
AW: Per ProcessId prüfen, ob der Benutzer Admin ist (oder: ProcessId -> UserTokenHand
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. |
AW: Per ProcessId prüfen, ob der Benutzer Admin ist (oder: ProcessId -> UserTokenHand
Zitat:
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. |
AW: Per ProcessId prüfen, ob der Benutzer Admin ist (oder: ProcessId -> UserTokenHand
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.
|
AW: Per ProcessId prüfen, ob der Benutzer Admin ist (oder: ProcessId -> UserTokenHand
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 - ... |
AW: Per ProcessId prüfen, ob der Benutzer Admin ist (oder: ProcessId -> UserTokenHand
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. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:29 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz