CreateProcessWithLogonW function (Windows)

Switch View :
ScriptFree
CreateProcessWithLogonW function

Applies to: desktop apps only

Creates a new process and its primary thread. Then the new process runs the specified executable file in the security context of the specified credentials (user, domain, and password). It can optionally load the user profile for a specified user.

This function is similar to the CreateProcessAsUser and CreateProcessWithTokenW functions, except that the caller does not need to call the LogonUser function to authenticate the user and get a token.

Syntax

BOOL WINAPI CreateProcessWithLogonW(
  __in         LPCWSTR lpUsername,
  __in_opt     LPCWSTR lpDomain,
  __in         LPCWSTR lpPassword,
  __in         DWORD dwLogonFlags,
  __in_opt     LPCWSTR lpApplicationName,
  __inout_opt  LPWSTR lpCommandLine,
  __in         DWORD dwCreationFlags,
  __in_opt     LPVOID lpEnvironment,
  __in_opt     LPCWSTR lpCurrentDirectory,
  __in         LPSTARTUPINFOW lpStartupInfo,
  __out        LPPROCESS_INFORMATION lpProcessInfo
);

Parameters

lpUsername [in]

The name of the user. This is the name of the user account to log on to. If you use the UPN format, user@DNS_domain_name, the lpDomain parameter must be NULL.

The user account must have the Log On Locally permission on the local computer. This permission is granted to all users on workstations and servers, but only to administrators on domain controllers.

lpDomain [in, optional]

The name of the domain or server whose account database contains the lpUsername account. If this parameter is NULL, the user name must be specified in UPN format.

lpPassword [in]

The clear-text password for the lpUsername account.

dwLogonFlags [in]

The logon option. This parameter can be 0 (zero) or one of the following values.

ValueMeaning
LOGON_WITH_PROFILE
0x00000001

Log on, then load the user profile in the HKEY_USERS registry key. The function returns after the profile is loaded. Loading the profile can be time-consuming, so it is best to use this value only if you must access the information in the HKEY_CURRENT_USER registry key.

Windows Server 2003:  The profile is unloaded after the new process is terminated, whether or not it has created child processes.
Windows XP:  The profile is unloaded after the new process and all child processes it has created are terminated.
LOGON_NETCREDENTIALS_ONLY
0x00000002

Log on, but use the specified credentials on the network only. The new process uses the same token as the caller, but the system creates a new logon session within LSA, and the process uses the specified credentials as the default credentials.

This value can be used to create a process that uses a different set of credentials locally than it does remotely. This is useful in inter-domain scenarios where there is no trust relationship.

The system does not validate the specified credentials. Therefore, the process can start, but it may not have access to network resources.

 

lpApplicationName [in, optional]

The name of the module to be executed. This module can be a Windows-based application. It can be some other type of module (for example, MS-DOS or OS/2) if the appropriate subsystem is available on the local computer.

The string can specify the full path and file name of the module to execute or it can specify a partial name. If it is a partial name, the function uses the current drive and current directory to complete the specification. The function does not use the search path. This parameter must include the file name extension; no default extension is assumed.

The lpApplicationName parameter can be NULL, and the module name must be the first white space–delimited token in the lpCommandLine string. If you are using a long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin; otherwise, the file name is ambiguous.

For example, the following string can be interpreted in different ways:

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

The system tries to interpret the possibilities in the following order:

  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

If the executable module is a 16-bit application, lpApplicationName should be NULL, and the string pointed to by lpCommandLine should specify the executable module and its arguments.

lpCommandLine [in, out, optional]

The command line to be executed. The maximum length of this string is 1024 characters. If lpApplicationName is NULL, the module name portion of lpCommandLine is limited to MAX_PATH characters.

The function can modify the contents of this string. Therefore, this parameter cannot be a pointer to read-only memory (such as a const variable or a literal string). If this parameter is a constant string, the function may cause an access violation.

The lpCommandLine parameter can be NULL, and the function uses the string pointed to by lpApplicationName as the command line.

If both lpApplicationName and lpCommandLine are non-NULL, *lpApplicationName specifies the module to execute, and *lpCommandLine specifies the command line. The new process can use GetCommandLine to retrieve the entire command line. Console processes written in C can use the argc and argv arguments to parse the command line. Because argv[0] is the module name, C programmers typically repeat the module name as the first token in the command line.

If lpApplicationName is NULL, the first white space–delimited token of the command line specifies the module name. If you are using a long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin (see the explanation for the lpApplicationName parameter). If the file name does not contain an extension, .exe is appended. Therefore, if the file name extension is .com, this parameter must include the .com extension. If the file name ends in a period with no extension, or if the file name contains a path, .exe is not appended. If the file name does not contain a directory path, the system searches for the executable file in the following sequence:

  1. The directory from which the application loaded.
  2. The current directory for the parent process.
  3. The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory.
  4. The 16-bit Windows system directory. There is no function that obtains the path of this directory, but it is searched.
  5. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
  6. The directories that are listed in the PATH environment variable. Note that this function does not search the per-application path specified by the App Paths registry key. To include this per-application path in the search sequence, use the ShellExecute function.

The system adds a null character to the command line string to separate the file name from the arguments. This divides the original string into two strings for internal processing.

dwCreationFlags [in]

The flags that control how the process is created. The CREATE_DEFAULT_ERROR_MODE, CREATE_NEW_CONSOLE, and CREATE_NEW_PROCESS_GROUP flags are enabled by default— even if you do not set the flag, the system functions as if it were set. You can specify additional flags as noted.

ValueMeaning
CREATE_DEFAULT_ERROR_MODE
0x04000000

The new process does not inherit the error mode of the calling process. Instead, CreateProcessWithLogonW gives the new process the current default error mode. An application sets the current default error mode by calling SetErrorMode.

This flag is enabled by default.

CREATE_NEW_CONSOLE
0x00000010

The new process has a new console, instead of inheriting the parent's console. This flag cannot be used with the DETACHED_PROCESS flag.

This flag is enabled by default.

CREATE_NEW_PROCESS_GROUP
0x00000200

The new process is the root process of a new process group. The process group includes all processes that are descendants of this root process. The process identifier of the new process group is the same as the process identifier, which is returned in the lpProcessInfo parameter. Process groups are used by the GenerateConsoleCtrlEvent function to enable sending a CTRL+C or CTRL+BREAK signal to a group of console processes.

This flag is enabled by default.

CREATE_SEPARATE_WOW_VDM
0x00000800

This flag is only valid starting a 16-bit Windows-based application. If set, the new process runs in a private Virtual DOS Machine (VDM). By default, all 16-bit Windows-based applications run in a single, shared VDM. The advantage of running separately is that a crash only terminates the single VDM; any other programs running in distinct VDMs continue to function normally. Also, 16-bit Windows-based applications that run in separate VDMs have separate input queues, which means that if one application stops responding momentarily, applications in separate VDMs continue to receive input.

CREATE_SUSPENDED
0x00000004

The primary thread of the new process is created in a suspended state, and does not run until the ResumeThread function is called.

CREATE_UNICODE_ENVIRONMENT
0x00000400

Indicates the format of the lpEnvironment parameter. If this flag is set, the environment block pointed to by lpEnvironment uses Unicode characters. Otherwise, the environment block uses ANSI characters.

EXTENDED_STARTUPINFO_PRESENT
0x00080000

The process is created with extended startup information; the lpStartupInfo parameter specifies a STARTUPINFOEX structure.

Windows Server 2003 and Windows XP:  This value is not supported.

 

This parameter also controls the new process's priority class, which is used to determine the scheduling priorities of the process's threads. For a list of values, see GetPriorityClass. If none of the priority class flags is specified, the priority class defaults to NORMAL_PRIORITY_CLASS unless the priority class of the creating process is IDLE_PRIORITY_CLASS or BELOW_NORMAL_PRIORITY_CLASS. In this case, the child process receives the default priority class of the calling process.

lpEnvironment [in, optional]

A pointer to an environment block for the new process. If this parameter is NULL, the new process uses an environment created from the profile of the user specified by lpUsername.

An environment block consists of a null-terminated block of null-terminated strings. Each string is in the following form:

name=value

Because the equal sign (=) is used as a separator, it must not be used in the name of an environment variable.

An environment block can contain Unicode or ANSI characters. If the environment block pointed to by lpEnvironment contains Unicode characters, ensure that dwCreationFlags includes CREATE_UNICODE_ENVIRONMENT. If this parameter is NULL and the environment block of the parent process contains Unicode characters, you must also ensure that dwCreationFlags includes CREATE_UNICODE_ENVIRONMENT.

An ANSI environment block is terminated by two 0 (zero) bytes: one for the last string and one more to terminate the block. A Unicode environment block is terminated by four zero bytes: two for the last string and two more to terminate the block.

To retrieve a copy of the environment block for a specific user, use the CreateEnvironmentBlock function.

lpCurrentDirectory [in, optional]

The full path to the current directory for the process. The string can also specify a UNC path.

If this parameter is NULL, the new process has the same current drive and directory as the calling process. This feature is provided primarily for shells that need to start an application, and specify its initial drive and working directory.

lpStartupInfo [in]

A pointer to a STARTUPINFO or STARTUPINFOEX structure. The application must add permission for the specified user account to the specified window station and desktop, even for WinSta0\Default.

If the lpDesktop member is NULL or an empty string, the new process inherits the desktop and window station of its parent process. The application must add permission for the specified user account to the inherited window station and desktop.

Windows XP:  CreateProcessWithLogonW adds permission for the specified user account to the inherited window station and desktop.

Handles in STARTUPINFO or STARTUPINFOEX must be closed with CloseHandle when they are no longer needed.

Important  If the dwFlags member of the STARTUPINFO structure specifies STARTF_USESTDHANDLES, the standard handle fields are copied unchanged to the child process without validation. The caller is responsible for ensuring that these fields contain valid handle values. Incorrect values can cause the child process to misbehave or crash. Use the Application Verifier runtime verification tool to detect invalid handles.

lpProcessInfo [out]

A pointer to a PROCESS_INFORMATION structure that receives identification information for the new process, including a handle to the process.

Handles in PROCESS_INFORMATION must be closed with the CloseHandle function when they are not needed.

Return value

If the function succeeds, the return value is nonzero.

If the function fails, the return value is 0 (zero). To get extended error information, call GetLastError.

Note that the function returns before the process has finished initialization. If a required DLL cannot be located or fails to initialize, the process is terminated. To get the termination status of a process, call GetExitCodeProcess.

Remarks

By default, CreateProcessWithLogonW does not load the specified user profile into the HKEY_USERS registry key. This means that access to information in the HKEY_CURRENT_USER registry key may not produce results that are consistent with a normal interactive logon. It is your responsibility to load the user registry hive into HKEY_USERS before calling CreateProcessWithLogonW, by using LOGON_WITH_PROFILE, or by calling the LoadUserProfile function.

If the lpEnvironment parameter is NULL, the new process uses an environment block created from the profile of the user specified by lpUserName. If the HOMEDRIVE and HOMEPATH variables are not set, CreateProcessWithLogonW modifies the environment block to use the drive and path of the user's working directory.

When created, the new process and thread handles receive full access rights (PROCESS_ALL_ACCESS and THREAD_ALL_ACCESS). For either handle, if a security descriptor is not provided, the handle can be used in any function that requires an object handle of that type. When a security descriptor is provided, an access check is performed on all subsequent uses of the handle before access is granted. If access is denied, the requesting process cannot use the handle to gain access to the process or thread.

To retrieve a security token, pass the process handle in the PROCESS_INFORMATION structure to the OpenProcessToken function.

The process is assigned a process identifier. The identifier is valid until the process terminates. It can be used to identify the process, or it can be specified in the OpenProcess function to open a handle to the process. The initial thread in the process is also assigned a thread identifier. It can be specified in the OpenThread function to open a handle to the thread. The identifier is valid until the thread terminates and can be used to uniquely identify the thread within the system. These identifiers are returned in PROCESS_INFORMATION.

The calling thread can use the WaitForInputIdle function to wait until the new process has completed its initialization and is waiting for user input with no input pending. This can be useful for synchronization between parent and child processes, because CreateProcessWithLogonW returns without waiting for the new process to finish its initialization. For example, the creating process would use WaitForInputIdle before trying to find a window that is associated with the new process.

The preferred way to shut down a process is by using the ExitProcess function, because this function sends notification of approaching termination to all DLLs attached to the process. Other means of shutting down a process do not notify the attached DLLs. Note that when a thread calls ExitProcess, other threads of the process are terminated without an opportunity to execute any additional code (including the thread termination code of attached DLLs). For more information, see Terminating a Process.

CreateProcessWithLogonW accesses the specified directory and executable image in the security context of the target user. If the executable image is on a network and a network drive letter is specified in the path, the network drive letter is not available to the target user, as network drive letters can be assigned for each logon. If a network drive letter is specified, this function fails. If the executable image is on a network, use the UNC path.

There is a limit to the number of child processes that can be created by this function and run simultaneously. For example, on Windows XP, this limit is MAXIMUM_WAIT_OBJECTS*4. However, you may not be able to create this many processes due to system-wide quota limits.

Windows XP with SP2 and Windows Server 2003:  You cannot call CreateProcessWithLogonW from a process that is running under the "LocalSystem" account, because the function uses the logon SID in the caller token, and the token for the "LocalSystem" account does not contain this SID. As an alternative, use the CreateProcessAsUser and LogonUser functions.

To compile an application that uses this function, define _WIN32_WINNT as 0x0500 or later. For more information, see Using the Windows Headers.

Security Remarks

The lpApplicationName parameter can be NULL, and the executable name must be the first white space–delimited string in lpCommandLine. If the executable or path name has a space in it, there is a risk that a different executable could be run because of the way the function parses spaces. Avoid the following example, because the function attempts to run "Program.exe", if it exists, instead of "MyApp.exe".

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

If a malicious user creates an application called "Program.exe" on a system, any program that incorrectly calls CreateProcessWithLogonW using the Program Files directory runs the malicious user application instead of the intended application.

To avoid this issue, do not pass NULL for lpApplicationName. If you pass NULL for lpApplicationName, use quotation marks around the executable path in lpCommandLine, as shown in the following example:

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

Examples

The following example demonstrates how to call this function.

C++


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


Requirements

Minimum supported client

Windows XP

Minimum supported server

Windows Server 2003

Header

WinBase.h (include Windows.h)

Library

Advapi32.lib

DLL

Advapi32.dll

See also

CloseHandle
CreateEnvironmentBlock
CreateProcessAsUser
ExitProcess
GetEnvironmentStrings
GetExitCodeProcess
OpenProcess
Process and Thread Functions
PROCESS_INFORMATION
Processes
SetErrorMode
STARTUPINFO
WaitForInputIdle

 

 

Send comments about this topic to Microsoft

Build date: 3/7/2012

Community Content

DRFGHDE
Undocumented limitation on size of environment block
The environment block passed with parameter 'lpEnvironment' must not contain more than 5120 characters including the terminating \0 characters and the trailing \0 block delimiter.

If the environment block exceeds that limit, then the call will issue error "0x000006F7: The stub received bad data."

On Windows 7 SP1, the documented limits are 32767 bytes for the environment and 8192 bytes for each variable. However, the CreateProcessWithLogonW function has not been adapted to these new limits. It still does not accept more than 5120 characters.


ElmueSoft
Contradiction in MSDN sample code
This page is a contradiction:

The text above says:
"This function is similar to the CreateProcessAsUserand CreateProcessWithTokenfunctions,
except that the caller does not need to call the LogonUserfunction to authenticate the user and get a token."

Then below comes a code sample that first calls LogonUser and then calls CreateProcessWithLogon passing the same username and password to both functions!

What sense has calling LogonUser in the sample code if CreateProcessWithLogon already does the job ????

Alexandru Dobre
Hide Console window
If you want to bypass CREATE_NEW_CONSOLE flag ( it is enabled by default ) and hide the console window one solution is :

STARTUPINFO si;
ZeroMemory( &si, sizeof(STARTUPINFO) );
si.cb = sizeof(STARTUPINFO);
si.dwFlags |= STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
CreateProcessWithLogonW( ... ,&si, ... );

( works on Windows XP; not tested on other OS )

Graham Wideman
Re: Don't call user applications with this function!
Previously Christian Wimmer posted:
"...call user mode applications...  (like Word) ...  the usual shutdown sequence does not apply to processes launched with CreateProcessWithLogonW. ... launched applications do not get WM_QUERYENDSESSION, WM_ENDSESSION and the most important WM_QUIT message. They will just quit without warning. "

I tested this and did not see this issue.  Ie:  WinWord.exe launched using CreateProcessWithLogonWas another user, did quit properly using, for example, the "X" close box (top right of window), or from the task bar.  If I had edited the document, Word popped up a "do you want to save" message, as expected.
I tested as follows:
WinXP SP3
WinWord 2003
I used the CreateProcessWithLogonW demo program "minirunas" by Christian d'Heureuse (search google for it).  
I did verify in Task Manager that Word was running under the account of the other user.

So, that's not to say there's no issue, but perhaps it's to do with what settings CreateProcessWithLogonWas is called with.

-- Graham

dmex
C# syntax
[DllImport("advapi32.dll", CharSet=CharSet.Unicode, SetLastError=true, ExactSpelling=true)]
public static extern bool CreateProcessWithLogonW(string userName, string domain, IntPtr password, LogonFlags logonFlags, [MarshalAs(UnmanagedType.LPTStr)] string appName, StringBuilder cmdLine, int creationFlags, IntPtr environmentBlock, [MarshalAs(UnmanagedType.LPTStr)] string lpCurrentDirectory, STARTUPINFO lpStartupInfo, SafeNativeMethods.PROCESS_INFORMATION lpProcessInformation);

dmex
vb.net syntax
<DllImport("advapi32.dll", CharSet:=CharSet.Unicode, SetLastError:=True, ExactSpelling:=True)> _
Public Shared Function CreateProcessWithLogonW(ByVal userName As String, ByVal domain As String, ByVal password As IntPtr, ByVal logonFlags As LogonFlags, <MarshalAs(UnmanagedType.LPTStr)> ByVal appName As String, ByVal cmdLine As StringBuilder, ByVal creationFlags As Integer, ByVal environmentBlock As IntPtr, <MarshalAs(UnmanagedType.LPTStr)> ByVal lpCurrentDirectory As String, ByVal lpStartupInfo As STARTUPINFO, ByVal lpProcessInformation As PROCESS_INFORMATION) As Boolean
End Function

SKLEE
It opreate different in XP/Vista.
It can logon an application(ex:Word) into MOSS in Windows XP.
But, It can not logon into Windows Vista.
Why?

Christian.Wimmer
Don't call user applications with this function!
If you going to call user mode applications that offer document editing and similar stuff (like Word), all unsaved data will be lost. This is because the usual shutdown sequence does not apply to processes launched with CreateProcessWithLogonW. In this way the launched applications do not get WM_QUERYENDSESSION, WM_ENDSESSION and the most important WM_QUIT message. So they don't ask for saving the data or clean up their stuff. They will just quit without warning. This function is not user friendly and should be used with caution.

It is just "bad user experience". Nobody expects it.

rosy12
createprocesswithlogon always opens up a new console
This functions always opens a new console window, even if CREATE_NEW_CONSOLE is not set. Does anyone know how to redirect the new process output to the calling console? I have tried setting the startupinfo structure to the handle of the calling console's buffer using getStdHandle(STD_OUTPUT_HANDLE) with no luck. I have also tried using the startupinfo of the calling structure by using getstartupinfo(&si). Also no luck. The only solution I have been able to get to work is to redirect stdout to a file! and then see what the new process did. This is of course terrible. Anyone else know a different solution?

Judah Greenblatt
Possible incorrect docs for lpCurrentDirectory
I am not seeing the documented behavior when lpCurrentDirectory is NULL.

If lpCurrentDirectory is NULL, the new process appears to start in C:\Windows\System32
(at least from a Service on Windows-XP)
and not in the current directory of the calling process.

If lpCurrentDirectory is non-null, everything works as expected.

Myles Penlington
Possible incorrect docs with regard to security requirements?

I'm not seeing the documented behaviour with lpStartupInfo in terms of security.

I.e we get a DLL init issue ($C0000142) error thrown and we are passing in a blank/null desktop member of the lpStartupInfo parameter. This is on XP sp2. This is attempting to start another process from a service running as a domain account (i.e. the serice is not running as the local system account, and the process is not starting in the interactive desktop/window station), when it is starting the second process.


Bovineone
Interactions with Win32 Job Objects

CreateProcessWithLogonW executes the new process as a child of the Secondary Logon service, which has the outcome of making the process escape any Job Object membership/restrictions even if the Job Object did not allow breakaway.

Furthermore, the Secondary Logon service automatically creates its own new Job Object and assigns the new process into it.  As such, it is not possible for the caller to explicitly assign the new process to any other Job Object (since a process may only be assigned to one Job Object, and can never be removed from a Job Object once it has been assigned to one).