CreateProcessAsUserA, fonction (processthreadsapi.h)

Crée un processus et son thread principal. Le nouveau processus s’exécute dans le contexte de sécurité de l’utilisateur représenté par le jeton spécifié.

En règle générale, le processus qui appelle la fonction CreateProcessAsUser doit avoir le privilège SE_INCREASE_QUOTA_NAME et peut nécessiter le privilège SE_ASSIGNPRIMARYTOKEN_NAME si le jeton n’est pas assignable. Si cette fonction échoue avec ERROR_PRIVILEGE_NOT_HELD (1314), utilisez plutôt la fonction CreateProcessWithLogonW . CreateProcessWithLogonW ne nécessite aucun privilège spécial, mais le compte d’utilisateur spécifié doit être autorisé à se connecter de manière interactive. En règle générale, il est préférable d’utiliser CreateProcessWithLogonW pour créer un processus avec d’autres informations d’identification.

Syntaxe

BOOL CreateProcessAsUserA(
  [in, optional]      HANDLE                hToken,
  [in, optional]      LPCSTR                lpApplicationName,
  [in, out, optional] LPSTR                 lpCommandLine,
  [in, optional]      LPSECURITY_ATTRIBUTES lpProcessAttributes,
  [in, optional]      LPSECURITY_ATTRIBUTES lpThreadAttributes,
  [in]                BOOL                  bInheritHandles,
  [in]                DWORD                 dwCreationFlags,
  [in, optional]      LPVOID                lpEnvironment,
  [in, optional]      LPCSTR                lpCurrentDirectory,
  [in]                LPSTARTUPINFOA        lpStartupInfo,
  [out]               LPPROCESS_INFORMATION lpProcessInformation
);

Paramètres

[in, optional] hToken

Handle du jeton principal qui représente un utilisateur. Le handle doit disposer des droits d’accès TOKEN_QUERY, TOKEN_DUPLICATE et TOKEN_ASSIGN_PRIMARY . Pour plus d’informations, consultez Droits d’accès pour les objets Access-Token. L’utilisateur représenté par le jeton doit avoir accès en lecture et en exécution à l’application spécifiée par le paramètre lpApplicationName ou lpCommandLine .

Pour obtenir un jeton principal qui représente l’utilisateur spécifié, appelez la fonction LogonUser . Vous pouvez également appeler la fonction DuplicateTokenEx pour convertir un jeton d’emprunt d’identité en jeton principal. Cela permet à une application serveur qui emprunte l’identité d’un client de créer un processus qui a le contexte de sécurité du client.

Si hToken est une version restreinte du jeton principal de l’appelant, le privilège SE_ASSIGNPRIMARYTOKEN_NAME n’est pas obligatoire. Si les privilèges nécessaires ne sont pas encore activés, CreateProcessAsUser les active pendant la durée de l’appel. Pour plus d’informations, consultez Exécution avec des privilèges spéciaux.

Services Terminal Server : Le processus est exécuté dans la session spécifiée dans le jeton. Par défaut, il s’agit de la même session que celle appelée LogonUser. Pour modifier la session, utilisez la fonction SetTokenInformation .

[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. Dans le cas d’un nom partiel, la fonction utilise le lecteur actuel et le répertoire actif pour terminer 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. Dans ce cas, 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, considérez la chaîne « c :\program files\sub dir\program name ». Cette chaîne peut être interprétée de plusieurs façons. Le système tente d’interpréter les possibilités dans l’ordre suivant :

c:\program.exec :\program files\sub.exec :\program files\sub dir\program.exec :\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 ainsi que ses arguments. Par défaut, toutes les applications Windows 16 bits créées par CreateProcessAsUser sont exécutées dans un VDM distinct (équivalent à CREATE_SEPARATE_WOW_VDM dans CreateProcess).

[in, out, optional] lpCommandLine

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

La version Unicode de cette fonction, CreateProcessAsUserW, 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. Dans ce cas, 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 un point (.) 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, optional] lpProcessAttributes

Pointeur vers une structure de SECURITY_ATTRIBUTES qui spécifie un descripteur de sécurité pour le nouvel objet de processus et détermine si les processus enfants peuvent hériter du handle retourné au processus. Si lpProcessAttributes a la valeur NULL ou si lpSecurityDescriptor a la valeur NULL, le processus obtient un descripteur de sécurité par défaut et le handle ne peut pas être hérité. Le descripteur de sécurité par défaut est celui de l’utilisateur référencé dans le paramètre hToken . Ce descripteur de sécurité peut ne pas autoriser l’accès pour l’appelant, auquel cas le processus ne peut pas être rouvert après son exécution. Le handle de processus est valide et continuera de disposer de droits d’accès complets.

[in, optional] lpThreadAttributes

Pointeur vers une structure de SECURITY_ATTRIBUTES qui spécifie un descripteur de sécurité pour le nouvel objet thread et détermine si les processus enfants peuvent hériter du handle retourné au thread. Si lpThreadAttributes a la valeur NULL ou si lpSecurityDescriptor a la valeur NULL, le thread obtient un descripteur de sécurité par défaut et le handle ne peut pas être hérité. Le descripteur de sécurité par défaut est celui de l’utilisateur référencé dans le paramètre hToken . Ce descripteur de sécurité peut ne pas autoriser l’accès pour l’appelant.

[in] bInheritHandles

Si ce paramètre a la valeur TRUE, chaque handle pouvant être hérité dans le processus appelant est hérité par le nouveau processus. Si le paramètre a la valeur FALSE, les handles ne sont pas hérités. Notez que les handles hérités ont la même valeur et les mêmes droits d’accès que les handles d’origine. Pour plus d’informations sur les handles pouvant être hérités, consultez Remarques.

Services Terminal Server : Vous ne pouvez pas hériter de handles entre les sessions. En outre, si ce paramètre a la valeur TRUE, vous devez créer le processus dans la même session que l’appelant.

Processus PPL (Protected Process Light) : L’héritage de handle générique est bloqué lorsqu’un processus PPL crée un processus non-PPL, car PROCESS_DUP_HANDLE n’est pas autorisé d’un processus non PPL à un processus PPL. Consultez Sécurité des processus et droits d’accès

[in] dwCreationFlags

Indicateurs qui contrôlent la classe de priorité et la création du processus. 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 hérite à la fois du mode d’erreur de l’appelant et de la console parente.
  • 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 l’environnement du processus appelant.

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

Nom=value\0

É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, assurez-vous que dwCreationFlags inclut CREATE_UNICODE_ENVIRONMENT.

La version ANSI de cette fonction , CreateProcessAsUserA , échoue si la taille totale du bloc d’environnement pour le processus dépasse 32 767 caractères.

Notez qu’un bloc d’environnement ANSI est terminé par deux octets zéro : un pour la dernière chaîne, 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, deux autres pour terminer le bloc.

Windows Server 2003 et Windows XP : Si la taille de la variable d’environnement système et utilisateur combinée dépasse 8192 octets, le processus créé par CreateProcessAsUser ne s’exécute plus avec le bloc d’environnement transmis à la fonction par le processus parent. Au lieu de cela, le processus enfant s’exécute avec le bloc d’environnement retourné par la fonction CreateEnvironmentBlock .

Pour récupérer une copie du bloc d’environnement pour un utilisateur donné, 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 est NULL, le nouveau processus a le même lecteur et le même répertoire actifs que le processus appelant. (Cette fonctionnalité est fournie principalement 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 ou STARTUPINFOEX .

L’utilisateur doit avoir un accès complet à la station de fenêtre et au bureau spécifiés. Si vous souhaitez que le processus soit interactif, spécifiez winsta0\default. Si le membre lpDesktop a la valeur NULL, le nouveau processus hérite du bureau et de la station de fenêtre de son processus parent. Si ce membre est une chaîne vide, « », le nouveau processus se connecte à une station fenêtre à l’aide des règles décrites dans Traiter la connexion à une station de fenêtre.

Pour définir des attributs étendus, utilisez une structure STARTUPINFOEX et spécifiez EXTENDED_STARTUPINFO_PRESENT dans le paramètre dwCreationFlags .

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

Important L’appelant est chargé de s’assurer que les champs de handle standard dans STARTUPINFO contiennent des valeurs de handle valides. Ces champs sont copiés sans modification dans le processus enfant sans validation, même lorsque le membre dwFlags spécifie STARTF_USESTDHANDLES. 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 PROCESS_INFORMATION qui reçoit des informations d’identification sur le nouveau processus.

Les handles dans PROCESS_INFORMATION doivent être fermés avec CloseHandle lorsqu’ils ne sont plus 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 égale à zéro. 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

CreateProcessAsUser doit être en mesure d’ouvrir le jeton principal du processus appelant avec les droits d’accès TOKEN_DUPLICATE et TOKEN_IMPERSONATE .

Par défaut, CreateProcessAsUser crée le processus sur une station de fenêtre non interactive avec un bureau qui n’est pas visible et ne peut pas recevoir d’entrée utilisateur. Pour activer l’interaction utilisateur avec le nouveau processus, vous devez spécifier le nom de la station de fenêtre interactive et du bureau par défaut, « winsta0\default », dans le membre lpDesktop de la structure STARTUPINFO . En outre, avant d’appeler CreateProcessAsUser, vous devez modifier la liste de contrôle d’accès discrétionnaire (DACL) de la station de fenêtre interactive par défaut et du bureau par défaut. Les DACL de la station de fenêtre et du bureau doivent accorder l’accès à l’utilisateur ou à la session d’ouverture de session représentée par le paramètre hToken .

CreateProcessAsUser ne charge pas le profil de l’utilisateur spécifié dans la clé de Registre HKEY_USERS . Par conséquent, pour accéder aux informations de la clé de Registre HKEY_CURRENT_USER , vous devez charger les informations de profil de l’utilisateur dans HKEY_USERS avec la fonction LoadUserProfile avant d’appeler CreateProcessAsUser. Veillez à appeler UnloadUserProfile après la fin du nouveau processus.

Si le paramètre lpEnvironment a la valeur NULL, le nouveau processus hérite de l’environnement du processus appelant. CreateProcessAsUser ne modifie pas automatiquement le bloc d’environnement pour inclure des variables d’environnement spécifiques à l’utilisateur représenté par hToken. Par exemple, les variables USERNAME et USERDOMAIN sont héritées du processus appelant si lpEnvironment a la valeur NULL. Il vous incombe de préparer le bloc d’environnement pour le nouveau processus et de le spécifier dans lpEnvironment.

Les fonctions CreateProcessWithLogonW et CreateProcessWithTokenW sont similaires à CreateProcessAsUser, sauf que l’appelant n’a pas besoin d’appeler la fonction LogonUser pour authentifier l’utilisateur et obtenir un jeton.

CreateProcessAsUser vous permet d’accéder au répertoire et à l’image exécutable spécifiés dans le contexte de sécurité de l’appelant ou de l’utilisateur cible. Par défaut, CreateProcessAsUser accède au répertoire et à l’image exécutable dans le contexte de sécurité de l’appelant. Dans ce cas, si l’appelant n’a pas accès au répertoire et à l’image exécutable, la fonction échoue. Pour accéder au répertoire et à l’image exécutable à l’aide du contexte de sécurité de l’utilisateur cible, spécifiez hToken dans un appel à la fonction ImpersonateLoggedOnUser avant d’appeler CreateProcessAsUser.

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 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 la structure PROCESS_INFORMATION .

Le thread appelant peut utiliser la fonction WaitForInputIdle pour attendre que le nouveau processus ait terminé son initialisation et qu’il 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 CreateProcessAsUser 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.

Par défaut, le passage de TRUE comme valeur du paramètre bInheritHandles entraîne l’héritage de tous les handles pouvant être hérités par le nouveau processus. Cela peut être problématique pour les applications qui créent des processus à partir de plusieurs threads simultanément, tout en souhaitant que chaque processus hérite de différents handles. Les applications peuvent utiliser la fonction UpdateProcThreadAttributeList avec le paramètre PROC_THREAD_ATTRIBUTE_HANDLE_LIST pour fournir une liste de handles à hériter par un processus particulier.

Remarques sur la sécurité

Le paramètre lpApplicationName peut être NULL, auquel cas 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. L’exemple suivant est dangereux, 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"));
	CreateProcessAsUser(hToken, NULL, szCmdline, /*...*/ );

Si un utilisateur malveillant devait créer une application appelée « Program.exe » sur un système, tout programme qui appelle incorrectement CreateProcessAsUser à l’aide du répertoire Program Files exécutera cette application 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 indiqué dans l’exemple ci-dessous.

	LPTSTR szCmdline[] = _tcsdup(TEXT("\"C:\\Program Files\\MyApp\""));
	CreateProcessAsUser(hToken, NULL, szCmdline, /*...*/);

Powershell: Lorsque la fonction CreateProcessAsUser est utilisée pour implémenter une applet de commande dans PowerShell version 2.0, l’applet de commande fonctionne correctement pour les sessions à distance fan-in et fan-out. Toutefois, en raison de certains scénarios de sécurité, une applet de commande implémentée avec CreateProcessAsUser fonctionne uniquement correctement dans PowerShell version 3.0 pour les sessions à distance fan-in ; Les sessions à distance de fan-out échouent en raison de privilèges de sécurité client insuffisants. Pour implémenter une applet de commande qui fonctionne pour les sessions à distance fan-in et fan-out dans PowerShell version 3.0, utilisez la fonction CreateProcess .

Exemples

Pour obtenir un exemple, consultez Démarrage d’un processus client interactif.

Notes

L’en-tête processthreadsapi.h définit CreateProcessAsUser comme alias qui sélectionne automatiquement la version ANSI ou Unicode de cette fonction en fonction de la définition de la constante de préprocesseur UNICODE. La combinaison de l’utilisation de l’alias neutre en encodage avec du code qui n’est pas neutre en encodage peut entraîner des incompatibilités qui entraînent des erreurs de compilation ou d’exécution. Pour plus d’informations, consultez Conventions pour les prototypes de fonction.

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 processthreadsapi.h (inclure Windows.h)
Bibliothèque Advapi32.lib
DLL Advapi32.dll

Voir aussi

CloseHandle

CreateEnvironmentBlock

CreateProcess

CreateProcessWithLogonW

ExitProcess

GetEnvironmentStrings

GetExitCodeProcess

GetStartupInfo

ImpersonateLoggedOnUser

LoadUserProfile

PROCESS_INFORMATION

Fonctions de processus et de thread

Processus

SECURITY_ATTRIBUTES

SHCreateProcessAsUserW

STARTUPINFO

STARTUPINFOEX

SetErrorMode

WaitForInputIdle