2017-05-09 1 views
1

Je dois exécuter une application de ligne de commande à partir d'un service Windows, en l'exécutant comme un autre utilisateur Windows (en fournissant domain\user et password).Comment utiliser CreateProcessWithLogonW à partir d'une application de service?

J'enveloppa l'API Windows CreateProcessWithLogonW() dans ma propre fonction RunAppAsAnotherWindowsUser() de cette façon:

function CreateProcessWithLogonW(
    lpUsername, 
    lpDomain, 
    lpPassword: PWideChar; 
    dwLogonFlags: DWORD; 
    lpApplicationName: PWideChar; 
    lpCommandLine: PWideChar; 
    dwCreationFlags: DWORD; 
    lpEnvironment: Pointer; 
    lpCurrentDirectory: PWideChar; 
    lpStartupInfo: PStartupInfoW; 
    lpProcessInformation: PProcessInformation 
): BOOL; stdcall; external 'advapi32.dll'; 

function RunAppAsAnotherWindowsUser(const User, Domain, PW, Application, CmdLineParams: WideString): LongWord;  

const 
    LOGON_WITH_PROFILE = $00000001; 

implementation 

function RunAppAsAnotherWindowsUser(const User, Domain, PW, Application, CmdLineParams: WideString): LongWord; 
var 
    si   : TStartupInfoW; 
    pif   : TProcessInformation; 
begin 
    ZeroMemory(@si, sizeof(si)); 
    si.cb := sizeof(si); 
    si.dwFlags := STARTF_USESHOWWINDOW; 
    si.wShowWindow := 1; 

    SetLastError(0); 
    CreateProcessWithLogonW(PWideChar(User), PWideChar(Domain), PWideChar(PW), 
    LOGON_WITH_PROFILE, nil, PWideChar(Application+' '+CmdLineParams), 
    CREATE_DEFAULT_ERROR_MODE, nil, nil, @si, @pif); 
    Result := GetLastError; 
end; 

ci-dessus était adapted from here.

Lorsque j'utilise RunAppAsAnotherWindowsUser() à partir d'une application Win32 VCL que j'ai créée pour le test, cela fonctionne correctement. Lorsque je l'appelle à partir d'un service Windows, cela ne fonctionne pas.

J'ai lu this page comme advised here, mais dans mon cas, je n'ai pas de processus interactif, car mon application de ligne de commande ne fait que des requêtes de base de données et écrit dans un fichier temporaire.

J'ai essayé d'exécuter le service à la fois en tant que système local que en tant qu'administrateur de domaine, mais le comportement est le même.

Le service est une application IntraWeb (VCL pour le Web) construite en tant que service. La même application construite comme exe fonctionne bien. J'écris ceci juste pour expliquer le contexte dans lequel je travaille.

Pourriez-vous m'aider s'il vous plaît à identifier le problème?

+3

Quel est le problème réel que vous avez avec elle? Obtenez-vous un code d'erreur? Si oui, lequel? S'il vous plaît être plus précis? –

+3

Les services s'exécutent dans une session isolée, vous devez lancer le processus dans la console ou une session utilisateur. – Remko

+0

J'ai essayé d'exécuter le processus en tant qu'utilisateur (en fait en tant qu'administrateur pc), cela résout une partie du problème en fait GetLastError (voir code ci-dessus) est 0 (donc pas d'erreur ), alors qu'il était 5 (pour répondre à @RemyLebeau) avant. Quoi qu'il en soit l'exe que je cours avec RunAppAsAnotherWindowsUser ne peut pas écrire un fichier, même si je mets un accès complet à tout le monde dans le dossier dédié. De toute façon, c'est juste une question ou des permissions. L'exécution du serveur en tant qu'utilisateur était un progrès important, maintenant je dois me battre avec les permissions des dossiers Windows (qui ne sont vraiment pas si évidentes). – LaBracca

Répondre

1

À partir d'un service, vous devez démarrer le processus dans la session de l'utilisateur (sur un ordinateur physique, généralement la session de la console). Tel est le cas depuis Windows Vista:

services ont toujours exécuté en session 0. Avant Windows Vista, le premier utilisateur de se connecter a également été affecté à la session 0. Maintenant, la session 0 est réservé exclusivement aux services et d'autres applications non associées à une session utilisateur interactive. (Le premier utilisateur à se connecter est connecté à la session 1, le deuxième utilisateur à se connecter est connecté à session 2, et ainsi de suite.) Session 0 ne prend pas en charge les processus qui interagir avec l'utilisateur.

Voir here pour un exemple très basique sur mon blog en utilisant Jedi Apilib.

Depuis ce blog:

uses JwaWinbase, JwaWtsApi32;  

var hToken: THandle; 
    si: _STARTUPINFOA; 
    pi: _PROCESS_INFORMATION; 
var Ret: Cardinal; 
    sTitle: string; 
    sMsg: string; 
begin 
    ZeroMemory(@si, SizeOf(si)); 
    si.cb := SizeOf(si); 
    si.lpDesktop := nil;  

    if WTSQueryUserToken(WtsGetActiveConsoleSessionID, hToken) then 
    begin 
    if CreateProcessAsUser(hToken, nil, 'notepad.exe', nil, nil, False, 
     0, nil, nil, si, pi) then 
    begin 
     // Do some stuff 
    end; 
    end; 
end; 
+0

Salut, mais puisque je dois utiliser CreateProcessWithLogonW et non CreateProcessAsUser comment puis-je faire depuis CreateProcessWithLogonW n'a pas de jeton en tant que paramètre? – LaBracca

+1

Obtenez un handle de jeton avec 'LogonUser' (https://msdn.microsoft.com/fr-fr/bibliothèque/windows/desktop/aa378184 (v = vs.85) .aspx) puis changez sessionid avec SetTokenInformation (https://msdn.microsoft.com/fr-fr/library/windows/desktop /aa379591(v=vs.85).aspx). Transmettez le jeton à 'CreateProcessAsUser'. Il doit bien sûr y avoir un utilisateur connecté, dans la session de services, vous ne pouvez pas lancer de processus interactifs. – Remko

+0

Pourquoi avez-vous besoin d'appeler CreateProcessWithLogon? Ne pouvez-vous pas usurper l'identité de l'utilisateur et exécuter le code requis dans le contexte de l'utilisateur? – Remko