I have a service that is responsible for starting/monitoring an interactive process in user session once user logins and console session connects. Service is set to start automatically so its up and running before user login. All work fine on first login and i get the user process started/restarted correctly.
What happens is that if user signs out and re logins service is no longer able to start a user process correctly. CreateProcessAsUser returns no error but as soon as user process is started its exiting with -1073741502 (0xC0000142) exit code.
If i restart the service then its again able to launch user process without any errors.
I can post full source of how the service creates user process if required.
Edit
try
{
//WE ALREADY HAVE A CLIENT ATTACHED , DONT START A NEW ONE
if (ClientProcessId != null)
return;
var ACTIVE_CONSOLE_SESSION = ListSessions()
.Where(SESSION => SESSION.State == WTS_CONNECTSTATE_CLASS.WTSActive)
.FirstOrDefault();
if (ACTIVE_CONSOLE_SESSION == null)
return;
CONSOLE_SESSION_ID = (uint)ACTIVE_CONSOLE_SESSION.Id;
IntPtr USER_TOKEN = IntPtr.Zero;
IntPtr ENVIRONMENT = IntPtr.Zero;
IntPtr LINKED_TOKEN = IntPtr.Zero;
try
{
try
{
if (!Wtsapi32.WTSQueryUserToken(CONSOLE_SESSION_ID.Value, out USER_TOKEN))
throw new Win32Exception();
}
catch (Win32Exception wex)
{
EntryPoint.TryWriteToCacheLog($"{nameof(Wtsapi32.WTSQueryUserToken)} : console session id {CONSOLE_SESSION_ID} error {wex.ErrorCode} , native error {wex.NativeErrorCode}");
throw;
}
try
{
if (!Userenv.CreateEnvironmentBlock(out ENVIRONMENT, USER_TOKEN, true))
throw new Win32Exception();
}
catch (Win32Exception wex)
{
EntryPoint.TryWriteToCacheLog($"{nameof(Userenv.CreateEnvironmentBlock)} : error {wex.ErrorCode} , native error {wex.NativeErrorCode}");
throw;
}
try
{
LINKED_TOKEN = CoreProcess.GetLinkedTokeIfRequiered(USER_TOKEN);
}
catch (Win32Exception wex)
{
EntryPoint.TryWriteToCacheLog($"{nameof(CoreProcess.GetLinkedTokeIfRequiered)} : error {wex.ErrorCode} , native error {wex.NativeErrorCode}");
throw;
}
//GET PROCESS PATHS
string FILE_NAME = EntryPoint.PROCESS_FULL_FILE_NAME;
string WORKING_DIRECTORY = EntryPoint.PROCESS_DIRECTORY;
//GET CURRENT COMMAND LINE ARGUMENTS
var CMD_ARGS = Environment.GetCommandLineArgs();
//FIRST ARGUMENT WILL ALWAYS HAVE FULL PROCESS PATH,OTHER ARGUMENTS ARE OPTIONAL
var ARGUMENTS_STRING = CMD_ARGS
.Skip(1)
.DefaultIfEmpty()
.Aggregate((first, next) => ' ' + first + ' ' + next);
var ARGUMENTS = new StringBuilder(ARGUMENTS_STRING);
var START_INFO = new STARTUPINFO();
START_INFO.cb = Marshal.SizeOf(START_INFO);
START_INFO.lpDesktop = @"winsta0\default";
var PROCESS_INFO = new PROCESS_INFORMATION();
uint dwCreationFlags = NORMAL_PRIORITY_CLASS | (int)(PROCESS_CREATE_FLAG.CREATE_NEW_CONSOLE | PROCESS_CREATE_FLAG.CREATE_UNICODE_ENVIRONMENT);
try
{
if (!AdvApi32.CreateProcessAsUser(LINKED_TOKEN,
FILE_NAME,
ARGUMENTS,
IntPtr.Zero,
IntPtr.Zero,
true,
dwCreationFlags,
ENVIRONMENT,
WORKING_DIRECTORY,
ref START_INFO,
out PROCESS_INFO))
throw new Win32Exception();
if (PROCESS_INFO.hThread != IntPtr.Zero)
{
ClientProcessId = PROCESS_INFO.dwProcessId;
ClientSessionId = CONSOLE_SESSION_ID;
EntryPoint.TryWriteToCacheLog($"{nameof(AdvApi32.CreateProcessAsUser)} : Created porocess {ClientProcessId} in session {CONSOLE_SESSION_ID}.");
}
}
catch (Win32Exception wex)
{
EntryPoint.TryWriteToCacheLog($"{nameof(AdvApi32.CreateProcessAsUser)} : error {wex.ErrorCode} , native error {wex.NativeErrorCode}");
throw;
}
}
catch (Win32Exception wex)
{
switch (wex.NativeErrorCode)
{
case 5:
case 1008:
tryCount++;
if (tryCount >= START_RETRIES)
throw;
Thread.Sleep(RETRY_WAIT_SPAN);
if (DisableCallBacks)
return;
CreateProcess(tryCount);
break;
default:
throw;
}
}
catch
{
throw;
}
finally
{
Userenv.DestroyEnvironmentBlock(ENVIRONMENT);
Kernel32.CloseHandle(USER_TOKEN);
if (USER_TOKEN != LINKED_TOKEN)
Kernel32.CloseHandle(LINKED_TOKEN);
}
}
catch (Exception ex)
{
EntryPoint.TryWriteToCacheLog($"{nameof(CreateProcess)} failed after {tryCount} retries, console seesion id {(CONSOLE_SESSION_ID != null ? CONSOLE_SESSION_ID.ToString() : "Unobtained")}.", ex.ToString());
}
finally
{
Monitor.Exit(CREATE_LOCK);
}
public static TOKEN_ELEVATION_TYPE GetTokenElevationLevel(IntPtr hToken)
{
int TOKEN_INFO_LENGTH = Marshal.SizeOf(typeof(int));
IntPtr TOKEN_INFO_POINTER = Marshal.AllocHGlobal(TOKEN_INFO_LENGTH);
try
{
if (!AdvApi32.GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenElevationType, TOKEN_INFO_POINTER, TOKEN_INFO_LENGTH, out TOKEN_INFO_LENGTH))
throw Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error());
return (TOKEN_ELEVATION_TYPE)Marshal.ReadInt32(TOKEN_INFO_POINTER);
}
catch
{
throw;
}
finally
{
if (TOKEN_INFO_POINTER != IntPtr.Zero)
Marshal.FreeHGlobal(TOKEN_INFO_POINTER);
}
}
public static IntPtr GetLinkedTokeIfRequiered(IntPtr hToken)
{
var TOKEN_ELEVATION = GetTokenElevationLevel(hToken);
if (TOKEN_ELEVATION != TOKEN_ELEVATION_TYPE.TokenElevationTypeLimited)
return hToken;
int TOKEN_INFO_LENGHT = Marshal.SizeOf(typeof(IntPtr));
IntPtr LINKED_TOKEN_INFO = Marshal.AllocHGlobal(TOKEN_INFO_LENGHT);
try
{
if (!AdvApi32.GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenLinkedToken, LINKED_TOKEN_INFO, TOKEN_INFO_LENGHT, out TOKEN_INFO_LENGHT))
throw new Win32Exception();
return Marshal.ReadIntPtr(LINKED_TOKEN_INFO);
}
finally
{
if (LINKED_TOKEN_INFO != IntPtr.Zero)
Marshal.Release(LINKED_TOKEN_INFO);
}
}