Ich habe mir das ganze nochmal durch den Kopf gehen lassen. In meinem Fall nützt mir auch ein eingeschränktes Admin Token nichts, denn das Programm muss mit dem Token des eigentlich angemeldeten Benutzers laufen. Den Task Scheduler kann man deaktivieren, daher fällt er für mich als potentielle Lösung schon aus. Ein Dienst ist vermutlich Overkill für meinen speziellen Fall.
Ich habe daher auf einen deiner ersten Vorschläge zurück gegriffen: Mit OpenProcessToken das Token einer Anwendung beschaffen, die mit Nutzerrechten läuft. Dabei bin ich wieder auf mein ursprüngliches Problem gestoßen (CreateProcessAsUser schlägt mit ERROR_PRIVILEGE_NOT_HELD fehl) und kann dieses wohl jetzt zumindest erklären.
Zitat von
http://msdn.microsoft.com/en-us/library/ms682429(VS.85).aspx:
Typically, the process that calls the CreateProcessAsUser function must have the SE_INCREASE_QUOTA_NAME privilege and may require the SE_ASSIGNPRIMARYTOKEN_NAME privilege if the token is not assignable.
If hToken is a restricted version of the caller's primary token, the SE_ASSIGNPRIMARYTOKEN_NAME privilege is not required. If the necessary privileges are not already enabled, CreateProcessAsUser enables them for the duration of the call.
Siehe dazu auch
diese Diskussion.
Standardmäßig besitzen Admins das SE_ASSIGNPRIMARYTOKEN_NAME Privileg nicht, Dienste hingegen schon. Benötigt wird dieses Privileg nur dann nicht, wenn man mit CreateRestrictedToken ein eingeschränktes Token aus dem Token das aktuellen Prozesses baut. Daher kann man das LinkedToken und auch fremde Token als (normaler) Admin nicht mit CreateProcessAsUser nutzen. Da SE_ASSIGNPRIMARYTOKEN_NAME gar nicht vorhanden ist, kann es auch nicht automatisch durch CreateProcessAsUser aktiviert werden.
Ich versuche das ganze jetzt über
CreateProcessWithTokenW zum laufen zu bringen.
Edit: Es klappt, manchmal.
Windows Vista Ultimate SP2, Ich bin als Admin angemeldet,
UAC ist an. Mein Programm hat ein requireAdministrator Manifest. Beim Programmstart muss ich bestätigen, dass das Programm Adminrechte bekommt. Alles geht. Das von mir gestartete Programm läuft ohne Adminrechte.
Selbes System, ich bin als normaler Nutzer angemeldet, starte mein Programm, logge mich per
UAC als Admin ein. Jetzt bekomme ich bei CreateTokenByProcessId (genauer bei OpenProcessToken) "Zugriff verweigert". Darf ich als Admin nicht auf Prozesse fremder User zugreifen oder gibt es da einen tollen Trick?
Die PID schreibe ich zur Zeit per Hand in den Code, nachdem ich sie per Taskmanager ausgelesen habe. Ja ich habe die Nummer richtig übertragen und entsprechend angepasst für den normalen Benutzer.
Delphi-Quellcode:
var
lToken, lToken2: TJwSecurityToken;
lStartupInfo: PStartupInfoW;
lProcessInfo: PProcessInformation;
...
lToken := TJwSecurityToken.CreateTokenByProcessId('1234', MAXIMUM_ALLOWED); // hier nicht TOKEN_ALL_ACCESS
lToken2 := TJwSecurityToken.CreateDuplicateExistingToken(lToken, TOKEN_ALL_ACCESS);
lToken2.ConvertToPrimaryToken(TOKEN_ALL_ACCESS);
GetMem(lStartupInfo2, SizeOf(TStartupInfoW));
GetMem(lProcessInfo2, SizeOf(TProcessInformation));
ZeroMemory(lStartupInfo2, SizeOf(TStartupInfoW));
ZeroMemory(lProcessInfo2, SizeOf(TProcessInformation));
lStartupInfo2^.cb := SizeOf(TStartupInfoW);
CreateProcessWithTokenW(lToken2.TokenHandle, 0, PWideChar('...'), nil, 0, nil, nil, lStartupInfo, lProcessInfo);
Edit2: DOH! Es kann so einfach sein. Der faule Programmierer schreibt natürlich TOKEN_ALL_ACCESS, damit er nicht suchen muss welche Rechte tatsächlich benötigt werden. MAXIMUM_ALLOWED ist ähnlich faul, funktioniert aber. Das Problem ist damit für mich zufriedenstellend gelöst. Habe den Code entsprechend angepasst.
Kleine Anmerkung: CreateProcessWithTokenW gibt es erst seit Vista/Server 2003. Das spielt bei mir keine Rolle, da ich den Code nur verwende, wenn die
UAC an ist. Trotzdem muss man JWApi dynamisch linken damit das Programm auch unter <= XP startet.
Danke für deine Unterstützung und vor allem DANKE für die
JWSCL