Función CreateProcessWithLogonW (winbase.h)

Crea un nuevo proceso y su subproceso principal. A continuación, el nuevo proceso ejecuta el archivo ejecutable especificado en el contexto de seguridad de las credenciales especificadas (usuario, dominio y contraseña). Opcionalmente, puede cargar el perfil de usuario para un usuario especificado.

Esta función es similar a las funciones CreateProcessAsUser y CreateProcessWithTokenW , salvo que el autor de la llamada no necesita llamar a la función LogonUser para autenticar al usuario y obtener un token.

Sintaxis

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
);

Parámetros

[in] lpUsername

Nombre del usuario. Este es el nombre de la cuenta de usuario en la que iniciar sesión. Si usa el formato UPN, el usuario@DNS_domain_name, el parámetro lpDomain debe ser NULL.

La cuenta de usuario debe tener el permiso Iniciar sesión localmente en el equipo local. Este permiso se concede a todos los usuarios en estaciones de trabajo y servidores, pero solo a los administradores de controladores de dominio.

[in, optional] lpDomain

Nombre del dominio o servidor cuya base de datos de cuenta contiene la cuenta lpUsername . Si este parámetro es NULL, el nombre de usuario debe especificarse en formato UPN.

[in] lpPassword

Contraseña de texto no cifrado de la cuenta lpUsername .

[in] dwLogonFlags

Opción de inicio de sesión. Este parámetro puede ser 0 (cero) o uno de los valores siguientes.

Valor Significado
LOGON_WITH_PROFILE
0x00000001
Inicie sesión y cargue el perfil de usuario en la clave del Registro de HKEY_USERS . La función devuelve después de cargar el perfil. Cargar el perfil puede llevar mucho tiempo, por lo que es mejor usar este valor solo si debe acceder a la información de la clave del Registro HKEY_CURRENT_USER .

Windows Server 2003: El perfil se descarga después de finalizar el nuevo proceso, independientemente de si ha creado o no procesos secundarios.

Windows XP: El perfil se descarga después de que finalice el nuevo proceso y todos los procesos secundarios que ha creado.

LOGON_NETCREDENTIALS_ONLY
0x00000002
Inicie sesión, pero use las credenciales especificadas solo en la red. El nuevo proceso usa el mismo token que el autor de la llamada, pero el sistema crea una nueva sesión de inicio de sesión en LSA y el proceso usa las credenciales especificadas como credenciales predeterminadas.

Este valor se puede usar para crear un proceso que use un conjunto diferente de credenciales localmente de lo que hace de forma remota. Esto es útil en escenarios entre dominios en los que no hay ninguna relación de confianza.

El sistema no valida las credenciales especificadas. Por lo tanto, el proceso puede iniciarse, pero es posible que no tenga acceso a los recursos de red.

[in, optional] lpApplicationName

Nombre del módulo que se va a ejecutar. Este módulo puede ser una aplicación basada en Windows. Puede ser otro tipo de módulo (por ejemplo, MS-DOS o OS/2) si el subsistema adecuado está disponible en el equipo local.

La cadena puede especificar la ruta de acceso completa y el nombre de archivo del módulo que se va a ejecutar o puede especificar un nombre parcial. Si es un nombre parcial, la función usa la unidad actual y el directorio actual para completar la especificación. La función no usa la ruta de acceso de búsqueda. Este parámetro debe incluir la extensión de nombre de archivo; no se supone ninguna extensión predeterminada.

El parámetro lpApplicationName puede ser NULL y el nombre del módulo debe ser el primer token delimitado por espacios en blanco en la cadena lpCommandLine . Si usa un nombre de archivo largo que contiene un espacio, use cadenas entre comillas para indicar dónde termina el nombre de archivo y los argumentos comienzan; de lo contrario, el nombre de archivo es ambiguo.

Por ejemplo, la cadena siguiente se puede interpretar de diferentes maneras:

"c:\program files\sub dir\program name"

El sistema intenta interpretar las posibilidades en el orden siguiente:

  1. c:\program.exe archivos\subdir\nombre del programa
  2. c:\program files\sub.exe dir\nombre del programa
  3. c:\program files\sub dir\program.exe name
  4. c:\program files\sub dir\program name.exe

Si el módulo ejecutable es una aplicación de 16 bits, lpApplicationName debe ser NULL y la cadena a la que apunta lpCommandLine debe especificar el módulo ejecutable y sus argumentos.

[in, out, optional] lpCommandLine

Línea de comandos que se va a ejecutar. La longitud máxima de esta cadena es de 1024 caracteres. Si lpApplicationName es NULL, la parte del nombre del módulo de lpCommandLine se limita a MAX_PATH caracteres.

La función puede modificar el contenido de esta cadena. Por lo tanto, este parámetro no puede ser un puntero a la memoria de solo lectura (como una variable const o una cadena literal). Si este parámetro es una cadena constante, la función puede provocar una infracción de acceso.

El parámetro lpCommandLine puede ser NULL y la función usa la cadena a la que apunta lpApplicationName como línea de comandos.

Si lpApplicationName y lpCommandLine no son NULL, *lpApplicationName especifica el módulo que se va a ejecutar y *lpCommandLine especifica la línea de comandos. El nuevo proceso puede usar GetCommandLine para recuperar toda la línea de comandos. Los procesos de consola escritos en C pueden usar los argumentos argc y argv para analizar la línea de comandos. Dado que argv[0] es el nombre del módulo, los programadores de C suelen repetir el nombre del módulo como el primer token de la línea de comandos.

Si lpApplicationName es NULL, el primer token delimitado por espacios en blanco de la línea de comandos especifica el nombre del módulo. Si usa un nombre de archivo largo que contiene un espacio, use cadenas entre comillas para indicar dónde finaliza el nombre de archivo y los argumentos comienzan (vea la explicación del parámetro lpApplicationName ). Si el nombre de archivo no contiene una extensión, .exe se anexa. Por lo tanto, si la extensión de nombre de archivo es .com, este parámetro debe incluir la extensión .com. Si el nombre de archivo termina en un punto sin extensión o si el nombre de archivo contiene una ruta de acceso, .exe no se anexa. Si el nombre de archivo no contiene una ruta de acceso de directorio, el sistema busca el archivo ejecutable en la secuencia siguiente:

  1. Directorio desde el que se cargó la aplicación.
  2. Directorio actual del proceso primario.
  3. Directorio del sistema windows de 32 bits. Use la función GetSystemDirectory para obtener la ruta de acceso de este directorio.
  4. Directorio del sistema windows de 16 bits. No hay ninguna función que obtenga la ruta de acceso de este directorio, pero se busca.
  5. El directorio de Windows. Use la función GetWindowsDirectory para obtener la ruta de acceso de este directorio.
  6. Los directorios que aparecen en la variable de entorno PATH. Tenga en cuenta que esta función no busca en la ruta de acceso por aplicación especificada por la clave del Registro rutas de acceso de aplicación. Para incluir esta ruta de acceso por aplicación en la secuencia de búsqueda, use la función ShellExecute .
El sistema agrega un carácter NULL a la cadena de línea de comandos para separar el nombre de archivo de los argumentos. Esto divide la cadena original en dos cadenas para el procesamiento interno.

[in] dwCreationFlags

Marcas que controlan cómo se crea el proceso. Las marcas CREATE_DEFAULT_ERROR_MODE, CREATE_NEW_CONSOLE y CREATE_NEW_PROCESS_GROUP están habilitadas de forma predeterminada. Para obtener una lista de valores, consulte Marcas de creación de procesos.

Este parámetro también controla la clase de prioridad del nuevo proceso, que se usa para determinar las prioridades de programación de los subprocesos del proceso. Para obtener una lista de valores, consulte GetPriorityClass. Si no se especifica ninguna de las marcas de clase de prioridad, la clase de prioridad tiene como valor predeterminado NORMAL_PRIORITY_CLASS a menos que la clase de prioridad del proceso de creación sea IDLE_PRIORITY_CLASS o BELOW_NORMAL_PRIORITY_CLASS. En este caso, el proceso secundario recibe la clase de prioridad predeterminada del proceso de llamada.

Si el parámetro dwCreationFlags tiene un valor de 0:

  • El proceso obtiene el modo de error predeterminado, crea una nueva consola y crea un nuevo grupo de procesos.
  • Se supone que el bloque de entorno del nuevo proceso contiene caracteres ANSI (consulte el parámetro lpEnvironment para obtener información adicional).
  • Una aplicación basada en Windows de 16 bits se ejecuta en una máquina VIRTUAL DOS compartida (VDM).

[in, optional] lpEnvironment

Puntero a un bloque de entorno para el nuevo proceso. Si este parámetro es NULL, el nuevo proceso usa un entorno creado a partir del perfil del usuario especificado por lpUsername.

Un bloque de entorno consta de un bloque terminado en null de cadenas terminadas en NULL. Cada cadena tiene el siguiente formato:

Nombre=Valor

Dado que el signo igual (=) se usa como separador, no debe usarse en el nombre de una variable de entorno.

Un bloque de entorno puede contener caracteres Unicode o ANSI. Si el bloque de entorno al que apunta lpEnvironment contiene caracteres Unicode, asegúrese de que dwCreationFlags incluya CREATE_UNICODE_ENVIRONMENT.

Un bloque de entorno ANSI finaliza en dos bytes (cero): uno para la última cadena y otro para finalizar el bloque. Un bloque de entorno Unicode finaliza en cuatro bytes cero: dos para la última cadena y dos más para finalizar el bloque.

Para recuperar una copia del bloque de entorno para un usuario específico, use la función CreateEnvironmentBlock .

[in, optional] lpCurrentDirectory

Ruta de acceso completa al directorio actual del proceso. La cadena también puede especificar una ruta de acceso UNC.

Si este parámetro es NULL, el nuevo proceso tiene la misma unidad y directorio actuales que el proceso de llamada. Esta característica se proporciona principalmente para los shells que necesitan iniciar una aplicación y especificar su unidad inicial y directorio de trabajo.

[in] lpStartupInfo

Puntero a una estructura STARTUPINFO .

La aplicación debe agregar permiso para la cuenta de usuario especificada a la estación de ventana y el escritorio especificados, incluso para WinSta0\Default.

Si el miembro lpDesktop es NULL o una cadena vacía, el nuevo proceso hereda la estación de escritorio y ventana de su proceso primario. La aplicación debe agregar permiso para la cuenta de usuario especificada a la estación de ventana heredada y al escritorio.

Windows XP: CreateProcessWithLogonW agrega permiso para la cuenta de usuario especificada a la estación de ventana heredada y al escritorio.

Los identificadores de STARTUPINFO deben cerrarse con CloseHandle cuando ya no sean necesarios.

Importante Si el miembro dwFlags de la estructura STARTUPINFO especifica STARTF_USESTDHANDLES, los campos de identificador estándar se copian sin cambios en el proceso secundario sin validación. El autor de la llamada es responsable de garantizar que estos campos contengan valores de identificador válidos. Los valores incorrectos pueden hacer que el proceso secundario se comporte o bloquee mal. Use la herramienta de comprobación en tiempo de ejecución del comprobador de aplicaciones para detectar identificadores no válidos.
 

[out] lpProcessInformation

Puntero a una estructura de PROCESS_INFORMATION que recibe información de identificación para el nuevo proceso, incluido un identificador para el proceso.

Los identificadores de PROCESS_INFORMATION deben cerrarse con la función CloseHandle cuando no son necesarios.

Valor devuelto

Si la función se realiza correctamente, el valor devuelto es distinto de cero.

Si la función no se realiza correctamente, el valor devuelto es 0 (cero). Para obtener información de error extendida, llame a GetLastError.

Tenga en cuenta que la función devuelve antes de que el proceso haya terminado de inicializarse. Si no se puede encontrar un archivo DLL necesario o no se puede inicializar, se finaliza el proceso. Para obtener el estado de finalización de un proceso, llame a GetExitCodeProcess.

Comentarios

De forma predeterminada, CreateProcessWithLogonW no carga el perfil de usuario especificado en la clave del Registro HKEY_USERS . Esto significa que es posible que el acceso a la información de la clave del Registro de HKEY_CURRENT_USER no genere resultados coherentes con un inicio de sesión interactivo normal. Es su responsabilidad cargar el subárbol del registro de usuario en HKEY_USERS antes de llamar a CreateProcessWithLogonW, mediante LOGON_WITH_PROFILE o llamando a la función LoadUserProfile .

Si el parámetro lpEnvironment es NULL, el nuevo proceso usa un bloque de entorno creado a partir del perfil del usuario especificado por lpUserName. Si no se establecen las variables HOMEDRIVE y HOMEPATH, CreateProcessWithLogonW modifica el bloque de entorno para usar la unidad y la ruta de acceso del directorio de trabajo del usuario.

Cuando se crea, el nuevo proceso y el subproceso reciben derechos de acceso completos (PROCESS_ALL_ACCESS y THREAD_ALL_ACCESS). Para cualquiera de los identificadores, si no se proporciona un descriptor de seguridad, el identificador se puede usar en cualquier función que requiera un identificador de objeto de ese tipo. Cuando se proporciona un descriptor de seguridad, se realiza una comprobación de acceso en todos los usos posteriores del identificador antes de que se conceda acceso. Si se deniega el acceso, el proceso de solicitud no puede usar el identificador para obtener acceso al proceso o al subproceso.

Para recuperar un token de seguridad, pase el identificador de proceso en la estructura PROCESS_INFORMATION a la función OpenProcessToken .

Al proceso se le asigna un identificador de proceso. El identificador es válido hasta que finaliza el proceso. Se puede usar para identificar el proceso o se puede especificar en la función OpenProcess para abrir un identificador para el proceso. Al subproceso inicial del proceso también se le asigna un identificador de subproceso. Se puede especificar en la función OpenThread para abrir un identificador al subproceso. El identificador es válido hasta que finaliza el subproceso y se puede usar para identificar de forma única el subproceso dentro del sistema. Estos identificadores se devuelven en PROCESS_INFORMATION.

El subproceso de llamada puede usar la función WaitForInputIdle para esperar hasta que el nuevo proceso haya completado su inicialización y esté esperando la entrada del usuario sin entrada pendiente. Esto puede ser útil para la sincronización entre los procesos primarios y secundarios, ya que CreateProcessWithLogonW devuelve sin esperar a que el nuevo proceso finalice su inicialización. Por ejemplo, el proceso de creación usaría WaitForInputIdle antes de intentar buscar una ventana asociada al nuevo proceso.

La manera preferida de apagar un proceso es mediante el uso de la función ExitProcess , ya que esta función envía una notificación de terminación cercana a todos los archivos DLL adjuntos al proceso. Otros medios para apagar un proceso no notifican a los archivos DLL adjuntos. Tenga en cuenta que cuando un subproceso llama a ExitProcess, otros subprocesos del proceso se terminan sin la oportunidad de ejecutar ningún código adicional (incluido el código de terminación del subproceso de archivos DLL adjuntos). Para obtener más información, consulte Terminación de un proceso.

CreateProcessWithLogonW accede al directorio y a la imagen ejecutable especificados en el contexto de seguridad del usuario de destino. Si la imagen ejecutable está en una red y se especifica una letra de unidad de red en la ruta de acceso, la letra de unidad de red no está disponible para el usuario de destino, ya que se pueden asignar letras de unidad de red para cada inicio de sesión. Si se especifica una letra de unidad de red, se produce un error en esta función. Si la imagen ejecutable está en una red, use la ruta de acceso UNC.

Hay un límite para el número de procesos secundarios que puede crear esta función y ejecutar simultáneamente. Por ejemplo, en Windows XP, este límite es MAXIMUM_WAIT_OBJECTS*4. Sin embargo, es posible que no pueda crear estos muchos procesos debido a los límites de cuota de todo el sistema.

Windows XP con SP2,Windows Server 2003 o posterior: No puede llamar a CreateProcessWithLogonW desde un proceso que se ejecuta en la cuenta "LocalSystem", ya que la función usa el SID de inicio de sesión en el token del autor de la llamada y el token de la cuenta "LocalSystem" no contiene este SID. Como alternativa, use las funciones CreateProcessAsUser y LogonUser .

Para compilar una aplicación que use esta función, defina _WIN32_WINNT como 0x0500 o posterior. Para obtener más información, vea Uso de los encabezados de Windows.

Comentarios de seguridad

El parámetro lpApplicationName puede ser NULL y el nombre ejecutable debe ser la primera cadena delimitada por espacios en blanco en lpCommandLine. Si el nombre del archivo ejecutable o la ruta de acceso tiene un espacio en él, existe el riesgo de que se pueda ejecutar un archivo ejecutable diferente debido a la forma en que la función analiza los espacios. Evite el ejemplo siguiente, porque la función intenta ejecutar "Program.exe", si existe, en lugar de "MyApp.exe".
LPTSTR szCmdline[]=_tcsdup(TEXT("C:\\Program Files\\MyApp"));
CreateProcessWithLogonW(..., szCmdline, ...)

Si un usuario malintencionado crea una aplicación denominada "Program.exe" en un sistema, cualquier programa que llame incorrectamente a CreateProcessWithLogonW mediante el directorio Archivos de programa ejecuta la aplicación de usuario malintencionada en lugar de la aplicación prevista.

Para evitar este problema, no pase NULL para lpApplicationName. Si pasa NULL para lpApplicationName, use comillas alrededor de la ruta de acceso ejecutable en lpCommandLine, como se muestra en el ejemplo siguiente:

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

Ejemplos

En el ejemplo siguiente se muestra cómo llamar a esta función.


#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);
}

Requisitos

Requisito Value
Cliente mínimo compatible Windows XP [solo aplicaciones de escritorio]
Servidor mínimo compatible Windows Server 2003 [solo aplicaciones de escritorio]
Plataforma de destino Windows
Encabezado winbase.h (incluya Windows.h)
Library Advapi32.lib
Archivo DLL Advapi32.dll

Consulte también

CloseHandle

CreateEnvironmentBlock

CreateProcessAsUser

ExitProcess

GetEnvironmentStrings

GetExitCodeProcess

OpenProcess

PROCESS_INFORMATION

Funciones de proceso y subproceso

Procesos

STARTUPINFO

SetErrorMode

WaitForInputIdle