Fonction CreateProcessWithLogonW (winbase.h)

Crée un processus et son thread principal. Ensuite, le nouveau processus exécute le fichier exécutable spécifié dans le contexte de sécurité des informations d’identification spécifiées (utilisateur, domaine et mot de passe). Il peut éventuellement charger le profil utilisateur d’un utilisateur spécifié.

Cette fonction est similaire aux fonctions CreateProcessAsUser et CreateProcessWithTokenW , sauf que l’appelant n’a pas besoin d’appeler la fonction LogonUser pour authentifier l’utilisateur et obtenir un jeton.

Syntaxe

BOOL CreateProcessWithLogonW(
  [in]                LPCWSTR               lpUsername,
  [in, optional]      LPCWSTR               lpDomain,
  [in]                LPCWSTR               lpPassword,
  [in]                DWORD                 dwLogonFlags,
  [in, optional]      LPCWSTR               lpApplicationName,
  [in, out, optional] LPWSTR                lpCommandLine,
  [in]                DWORD                 dwCreationFlags,
  [in, optional]      LPVOID                lpEnvironment,
  [in, optional]      LPCWSTR               lpCurrentDirectory,
  [in]                LPSTARTUPINFOW        lpStartupInfo,
  [out]               LPPROCESS_INFORMATION lpProcessInformation
);

Paramètres

[in] lpUsername

Nom de l'utilisateur. Il s’agit du nom du compte d’utilisateur auquel se connecter. Si vous utilisez le format UPN, l’utilisateur@DNS_domain_name, le paramètre lpDomain doit être NULL.

Le compte d’utilisateur doit disposer de l’autorisation Se connecter localement sur l’ordinateur local. Cette autorisation est accordée à tous les utilisateurs sur les stations de travail et les serveurs, mais uniquement aux administrateurs sur les contrôleurs de domaine.

[in, optional] lpDomain

Nom du domaine ou du serveur dont la base de données de compte contient le compte lpUsername . Si ce paramètre a la valeur NULL, le nom d’utilisateur doit être spécifié au format UPN.

[in] lpPassword

Mot de passe en texte clair du compte lpUsername .

[in] dwLogonFlags

Option d’ouverture de session. Ce paramètre peut être 0 (zéro) ou l’une des valeurs suivantes.

Valeur Signification
LOGON_WITH_PROFILE
0x00000001
Ouvrez une session, puis chargez le profil utilisateur dans la clé de Registre HKEY_USERS . La fonction retourne une fois le profil chargé. Le chargement du profil peut prendre du temps. Il est donc préférable d’utiliser cette valeur uniquement si vous devez accéder aux informations de la clé de Registre HKEY_CURRENT_USER .

Windows Server 2003 : Le profil est déchargé après l’arrêt du nouveau processus, qu’il ait ou non créé des processus enfants.

Windows XP : Le profil est déchargé une fois le nouveau processus terminé et tous les processus enfants qu’il a créés.

LOGON_NETCREDENTIALS_ONLY
0x00000002
Ouvrez une session, mais utilisez les informations d’identification spécifiées sur le réseau uniquement. Le nouveau processus utilise le même jeton que l’appelant, mais le système crée une session d’ouverture de session dans LSA, et le processus utilise les informations d’identification spécifiées comme informations d’identification par défaut.

Cette valeur peut être utilisée pour créer un processus qui utilise un ensemble d’informations d’identification différent localement de celui qu’il utilise à distance. Cela est utile dans les scénarios inter-domaines où il n’existe aucune relation d’approbation.

Le système ne valide pas les informations d’identification spécifiées. Par conséquent, le processus peut démarrer, mais il se peut qu’il n’ait pas accès aux ressources réseau.

[in, optional] lpApplicationName

Nom du module à exécuter. Ce module peut être une application Windows. Il peut s’agir d’un autre type de module (par exemple, MS-DOS ou OS/2) si le sous-système approprié est disponible sur l’ordinateur local.

La chaîne peut spécifier le chemin d’accès complet et le nom de fichier du module à exécuter ou spécifier un nom partiel. S’il s’agit d’un nom partiel, la fonction utilise le lecteur actuel et le répertoire actif pour compléter la spécification. La fonction n’utilise pas le chemin de recherche. Ce paramètre doit inclure l’extension de nom de fichier ; aucune extension par défaut n’est supposée.

Le paramètre lpApplicationName peut être NULL et le nom du module doit être le premier jeton délimité par des espaces blancs dans la chaîne lpCommandLine . Si vous utilisez un nom de fichier long qui contient un espace, utilisez des chaînes entre guillemets pour indiquer où le nom de fichier se termine et où les arguments commencent ; sinon, le nom de fichier est ambigu.

Par exemple, la chaîne suivante peut être interprétée de différentes manières :

« c :\program files\sub dir\program name »

Le système tente d’interpréter les possibilités dans l’ordre suivant :

  1. c:\program.exe files\sub dir\program name
  2. c :\program files\sub.exe dir\program name
  3. c :\program files\sub dir\program.exe name
  4. c :\program files\sub dir\program name.exe

Si le module exécutable est une application 16 bits, lpApplicationName doit avoir la valeur NULL et la chaîne pointée par lpCommandLine doit spécifier le module exécutable et ses arguments.

[in, out, optional] lpCommandLine

Ligne de commande à exécuter. La longueur maximale de cette chaîne est de 1 024 caractères. Si lpApplicationName a la valeur NULL, la partie du nom de module de lpCommandLine est limitée à MAX_PATH caractères.

La fonction peut modifier le contenu de cette chaîne. Par conséquent, ce paramètre ne peut pas être un pointeur vers la mémoire en lecture seule (par exemple, une variable const ou une chaîne littérale). Si ce paramètre est une chaîne constante, la fonction peut provoquer une violation d’accès.

Le paramètre lpCommandLine peut être NULL et la fonction utilise la chaîne pointée vers lpApplicationName comme ligne de commande.

Si lpApplicationName et lpCommandLine ne sont pas NULL, *lpApplicationName spécifie le module à exécuter et *lpCommandLine spécifie la ligne de commande. Le nouveau processus peut utiliser GetCommandLine pour récupérer l’intégralité de la ligne de commande. Les processus de console écrits en C peuvent utiliser les arguments argc et argv pour analyser la ligne de commande. Étant donné que argv[0] est le nom du module, les programmeurs C répètent généralement le nom du module comme premier jeton dans la ligne de commande.

Si lpApplicationName a la valeur NULL, le premier jeton délimité par des espaces blancs de la ligne de commande spécifie le nom du module. Si vous utilisez un nom de fichier long qui contient un espace, utilisez des chaînes entre guillemets pour indiquer où le nom de fichier se termine et où les arguments commencent (voir l’explication du paramètre lpApplicationName ). Si le nom de fichier ne contient pas d’extension, .exe est ajouté. Par conséquent, si l’extension de nom de fichier est .com, ce paramètre doit inclure l’extension .com. Si le nom de fichier se termine par une période sans extension, ou si le nom de fichier contient un chemin d’accès, .exe n’est pas ajouté. Si le nom de fichier ne contient pas de chemin de répertoire, le système recherche le fichier exécutable dans l’ordre suivant :

  1. Répertoire à partir duquel l’application a été chargée.
  2. Répertoire actif du processus parent.
  3. Répertoire système Windows 32 bits. Utilisez la fonction GetSystemDirectory pour obtenir le chemin d’accès de ce répertoire.
  4. Répertoire système Windows 16 bits. Aucune fonction n’obtient le chemin d’accès de ce répertoire, mais elle fait l’objet d’une recherche.
  5. Répertoire Windows. Utilisez la fonction GetWindowsDirectory pour obtenir le chemin d’accès de ce répertoire.
  6. Répertoires répertoriés dans la variable d’environnement PATH. Notez que cette fonction ne recherche pas le chemin d’accès par application spécifié par la clé de Registre Chemins d’accès d’application . Pour inclure ce chemin d’accès par application dans la séquence de recherche, utilisez la fonction ShellExecute .
Le système ajoute un caractère null à la chaîne de ligne de commande pour séparer le nom de fichier des arguments. Cela divise la chaîne d’origine en deux chaînes pour le traitement interne.

[in] dwCreationFlags

Indicateurs qui contrôlent la façon dont le processus est créé. Les indicateurs CREATE_DEFAULT_ERROR_MODE, CREATE_NEW_CONSOLE et CREATE_NEW_PROCESS_GROUP sont activés par défaut. Pour obtenir la liste des valeurs, consultez Indicateurs de création de processus.

Ce paramètre contrôle également la classe de priorité du nouveau processus, qui est utilisée pour déterminer les priorités de planification des threads du processus. Pour obtenir la liste des valeurs, consultez GetPriorityClass. Si aucun indicateur de classe de priorité n’est spécifié, la classe de priorité est par défaut NORMAL_PRIORITY_CLASS , sauf si la classe de priorité du processus de création est IDLE_PRIORITY_CLASS ou BELOW_NORMAL_PRIORITY_CLASS. Dans ce cas, le processus enfant reçoit la classe de priorité par défaut du processus appelant.

Si le paramètre dwCreationFlags a la valeur 0 :

  • Le processus obtient le mode d’erreur par défaut, crée une console et crée un groupe de processus.
  • Le bloc d’environnement du nouveau processus est supposé contenir des caractères ANSI (pour plus d’informations, consultez le paramètre lpEnvironment ).
  • Une application Windows 16 bits s’exécute sur une machine Virtual DOS (VDM) partagée.

[in, optional] lpEnvironment

Pointeur vers un bloc d’environnement pour le nouveau processus. Si ce paramètre a la valeur NULL, le nouveau processus utilise un environnement créé à partir du profil de l’utilisateur spécifié par lpUsername.

Un bloc d’environnement se compose d’un bloc null de chaînes terminées par null. Chaque chaîne se présente sous la forme suivante :

Nom=Valeur

Étant donné que le signe égal (=) est utilisé comme séparateur, il ne doit pas être utilisé dans le nom d’une variable d’environnement.

Un bloc d’environnement peut contenir des caractères Unicode ou ANSI. Si le bloc d’environnement pointé par lpEnvironment contient des caractères Unicode, vérifiez que dwCreationFlags inclut CREATE_UNICODE_ENVIRONMENT.

Un bloc d’environnement ANSI se termine par deux octets 0 (zéro) : un pour la dernière chaîne et un autre pour terminer le bloc. Un bloc d’environnement Unicode est terminé par quatre octets zéro : deux pour la dernière chaîne et deux autres pour terminer le bloc.

Pour récupérer une copie du bloc d’environnement pour un utilisateur spécifique, utilisez la fonction CreateEnvironmentBlock .

[in, optional] lpCurrentDirectory

Chemin d’accès complet au répertoire actif pour le processus. La chaîne peut également spécifier un chemin UNC.

Si ce paramètre a la valeur NULL, le nouveau processus a le même lecteur et le même répertoire actuels que le processus appelant. Cette fonctionnalité est principalement fournie pour les interpréteurs de commandes qui doivent démarrer une application et spécifier son lecteur initial et son répertoire de travail.

[in] lpStartupInfo

Pointeur vers une structure STARTUPINFO .

L’application doit ajouter l’autorisation pour le compte d’utilisateur spécifié à la station de fenêtre et au bureau spécifiés, même pour WinSta0\Default.

Si le membre lpDesktop a la valeur NULL ou une chaîne vide, le nouveau processus hérite du bureau et de la station de fenêtre de son processus parent. L’application doit ajouter l’autorisation pour le compte d’utilisateur spécifié à la station de fenêtre et au bureau hérités.

Windows XP : CreateProcessWithLogonW ajoute l’autorisation pour le compte d’utilisateur spécifié à la station de fenêtre et au bureau hérités.

Les handles dans STARTUPINFO doivent être fermés avec CloseHandle lorsqu’ils ne sont plus nécessaires.

Important Si le membre dwFlags de la structure STARTUPINFO spécifie STARTF_USESTDHANDLES, les champs de handle standard sont copiés sans modification dans le processus enfant sans validation. L’appelant est chargé de s’assurer que ces champs contiennent des valeurs de handle valides. Des valeurs incorrectes peuvent entraîner un mauvais comportement ou un blocage du processus enfant. Utilisez l’outil de vérification du runtime du vérificateur d’application pour détecter les handles non valides.
 

[out] lpProcessInformation

Pointeur vers une structure de PROCESS_INFORMATION qui reçoit des informations d’identification pour le nouveau processus, y compris un handle pour le processus.

Les handles dans PROCESS_INFORMATION doivent être fermés avec la fonction CloseHandle lorsqu’ils ne sont pas nécessaires.

Valeur retournée

Si la fonction réussit, la valeur de retour est différente de zéro.

Si la fonction échoue, la valeur de retour est zéro (0). Pour obtenir des informations détaillées sur l’erreur, appelez GetLastError.

Notez que la fonction retourne avant la fin de l’initialisation du processus. Si une DLL requise ne peut pas être trouvée ou ne parvient pas à s’initialiser, le processus est arrêté. Pour obtenir la status d’arrêt d’un processus, appelez GetExitCodeProcess.

Remarques

Par défaut, CreateProcessWithLogonW ne charge pas le profil utilisateur spécifié dans la clé de Registre HKEY_USERS . Cela signifie que l’accès aux informations dans la clé de Registre HKEY_CURRENT_USER peut ne pas produire de résultats cohérents avec une ouverture de session interactive normale. Il est de votre responsabilité de charger la ruche du registre d’utilisateurs dans HKEY_USERS avant d’appeler CreateProcessWithLogonW, à l’aide de LOGON_WITH_PROFILE ou en appelant la fonction LoadUserProfile .

Si le paramètre lpEnvironment est NULL, le nouveau processus utilise un bloc d’environnement créé à partir du profil de l’utilisateur spécifié par lpUserName. Si les variables HOMEDRIVE et HOMEPATH ne sont pas définies, CreateProcessWithLogonW modifie le bloc d’environnement pour utiliser le lecteur et le chemin d’accès du répertoire de travail de l’utilisateur.

Une fois créés, les nouveaux handles de processus et de thread reçoivent des droits d’accès complets (PROCESS_ALL_ACCESS et THREAD_ALL_ACCESS). Pour l’un ou l’autre handle, si aucun descripteur de sécurité n’est fourni, le handle peut être utilisé dans n’importe quelle fonction qui nécessite un handle d’objet de ce type. Lorsqu’un descripteur de sécurité est fourni, un case activée d’accès est effectué sur toutes les utilisations ultérieures du handle avant l’octroi de l’accès. Si l’accès est refusé, le processus demandeur ne peut pas utiliser le handle pour accéder au processus ou au thread.

Pour récupérer un jeton de sécurité, passez le handle de processus dans la structure PROCESS_INFORMATION à la fonction OpenProcessToken .

Un identificateur de processus est affecté au processus. L’identificateur est valide jusqu’à l’arrêt du processus. Il peut être utilisé pour identifier le processus, ou il peut être spécifié dans la fonction OpenProcess pour ouvrir un handle au processus. Un identificateur de thread est également affecté au thread initial du processus. Il peut être spécifié dans la fonction OpenThread pour ouvrir un handle au thread. L’identificateur est valide jusqu’à ce que le thread se termine et peut être utilisé pour identifier le thread de manière unique dans le système. Ces identificateurs sont retournés dans PROCESS_INFORMATION.

Le thread appelant peut utiliser la fonction WaitForInputIdle pour attendre que le nouveau processus ait terminé son initialisation et attende une entrée utilisateur sans aucune entrée en attente. Cela peut être utile pour la synchronisation entre les processus parents et enfants, car CreateProcessWithLogonW retourne sans attendre que le nouveau processus termine son initialisation. Par exemple, le processus de création utilise WaitForInputIdle avant d’essayer de trouver une fenêtre associée au nouveau processus.

La meilleure façon d’arrêter un processus consiste à utiliser la fonction ExitProcess , car cette fonction envoie une notification d’arrêt proche à toutes les DLL attachées au processus. D’autres moyens d’arrêter un processus ne notifient pas les DLL jointes. Notez que lorsqu’un thread appelle ExitProcess, d’autres threads du processus sont arrêtés sans possibilité d’exécuter de code supplémentaire (y compris le code d’arrêt de thread des DLL jointes). Pour plus d’informations, consultez Fin d’un processus.

CreateProcessWithLogonW accède au répertoire et à l’image exécutable spécifiés dans le contexte de sécurité de l’utilisateur cible. Si l’image exécutable se trouve sur un réseau et qu’une lettre de lecteur réseau est spécifiée dans le chemin d’accès, la lettre de lecteur réseau n’est pas disponible pour l’utilisateur cible, car des lettres de lecteur réseau peuvent être affectées pour chaque ouverture de session. Si une lettre de lecteur réseau est spécifiée, cette fonction échoue. Si l’image exécutable se trouve sur un réseau, utilisez le chemin UNC.

Il existe une limite au nombre de processus enfants qui peuvent être créés par cette fonction et exécutés simultanément. Par exemple, sur Windows XP, cette limite est MAXIMUM_WAIT_OBJECTS*4. Toutefois, vous ne pourrez peut-être pas créer ce nombre de processus en raison de limites de quota à l’échelle du système.

Windows XP avec SP2, Windows Server 2003 ou version ultérieure : Vous ne pouvez pas appeler CreateProcessWithLogonW à partir d’un processus qui s’exécute sous le compte « LocalSystem », car la fonction utilise le SID d’ouverture de session dans le jeton de l’appelant et le jeton du compte « LocalSystem » ne contient pas ce SID. Vous pouvez également utiliser les fonctions CreateProcessAsUser et LogonUser .

Pour compiler une application qui utilise cette fonction, définissez _WIN32_WINNT comme 0x0500 ou version ultérieure. Pour plus d’informations, consultez Utilisation des en-têtes Windows.

Remarques sur la sécurité

Le paramètre lpApplicationName peut être NULL et le nom de l’exécutable doit être la première chaîne délimitée par des espaces blancs dans lpCommandLine. Si le nom de l’exécutable ou du chemin contient un espace, il existe un risque qu’un autre exécutable soit exécuté en raison de la façon dont la fonction analyse les espaces. Évitez l’exemple suivant, car la fonction tente d’exécuter « Program.exe », s’il existe, au lieu de « MyApp.exe ».
LPTSTR szCmdline[]=_tcsdup(TEXT("C:\\Program Files\\MyApp"));
CreateProcessWithLogonW(..., szCmdline, ...)

Si un utilisateur malveillant crée une application appelée « Program.exe » sur un système, tout programme qui appelle incorrectement CreateProcessWithLogonW à l’aide du répertoire Program Files exécute l’application utilisateur malveillante au lieu de l’application prévue.

Pour éviter ce problème, ne passez pas NULL pour lpApplicationName. Si vous transmettez NULL pour lpApplicationName, utilisez des guillemets autour du chemin d’accès exécutable dans lpCommandLine, comme illustré dans l’exemple suivant :

LPTSTR szCmdline[]=_tcsdup(TEXT("\"C:\\Program Files\\MyApp\""));
CreateProcessWithLogonW(..., szCmdline, ...)

Exemples

L’exemple suivant montre comment appeler cette fonction.


#include <windows.h>
#include <stdio.h>
#include <userenv.h>

void DisplayError(LPWSTR pszAPI)
{
    LPVOID lpvMessageBuffer;

    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 
        FORMAT_MESSAGE_FROM_SYSTEM,
        NULL, GetLastError(), 
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
        (LPWSTR)&lpvMessageBuffer, 0, NULL);

    //
    //... now display this string
    //
    wprintf(L"ERROR: API        = %s.\n", pszAPI);
    wprintf(L"       error code = %d.\n", GetLastError());
    wprintf(L"       message    = %s.\n", (LPWSTR)lpvMessageBuffer);

    //
    // Free the buffer allocated by the system
    //
    LocalFree(lpvMessageBuffer);

    ExitProcess(GetLastError());
}

void wmain(int argc, WCHAR *argv[])
{
    DWORD     dwSize;
    HANDLE    hToken;
    LPVOID    lpvEnv;
    PROCESS_INFORMATION pi = {0};
    STARTUPINFO         si = {0};
    WCHAR               szUserProfile[256] = L"";

    si.cb = sizeof(STARTUPINFO);
    
    if (argc != 4)
    {
        wprintf(L"Usage: %s [user@domain] [password] [cmd]", argv[0]);
        wprintf(L"\n\n");
        return;
    }

    //
    // TO DO: change NULL to '.' to use local account database
    //
    if (!LogonUser(argv[1], NULL, argv[2], LOGON32_LOGON_INTERACTIVE, 
            LOGON32_PROVIDER_DEFAULT, &hToken))
        DisplayError(L"LogonUser");

    if (!CreateEnvironmentBlock(&lpvEnv, hToken, TRUE))
        DisplayError(L"CreateEnvironmentBlock");

    dwSize = sizeof(szUserProfile)/sizeof(WCHAR);

    if (!GetUserProfileDirectory(hToken, szUserProfile, &dwSize))
        DisplayError(L"GetUserProfileDirectory");

    //
    // TO DO: change NULL to '.' to use local account database
    //
    if (!CreateProcessWithLogonW(argv[1], NULL, argv[2], 
            LOGON_WITH_PROFILE, NULL, argv[3], 
            CREATE_UNICODE_ENVIRONMENT, lpvEnv, szUserProfile, 
            &si, &pi))
        DisplayError(L"CreateProcessWithLogonW");

    if (!DestroyEnvironmentBlock(lpvEnv))
        DisplayError(L"DestroyEnvironmentBlock");

    CloseHandle(hToken);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
}

Configuration requise

Condition requise Valeur
Client minimal pris en charge Windows XP [applications de bureau uniquement]
Serveur minimal pris en charge Windows Server 2003 [applications de bureau uniquement]
Plateforme cible Windows
En-tête winbase.h (inclure Windows.h)
Bibliothèque Advapi32.lib
DLL Advapi32.dll

Voir aussi

CloseHandle

CreateEnvironmentBlock

CreateProcessAsUser

ExitProcess

GetEnvironmentStrings

GetExitCodeProcess

OpenProcess

PROCESS_INFORMATION

Fonctions de processus et de thread

Processus

STARTUPINFO

SetErrorMode

WaitForInputIdle