/// <summary> /// Calls <see cref="CreateProcessAsUserW"/> and safely stores the obtained handles. /// </summary> /// <param name="userToken">Token to impersonate the external process</param> /// <param name="createFlags">Flags used to create the external process</param> /// <param name="startupInfo">Startup information used to create the external process</param> /// <returns><c>true</c> if the call to <see cref="CreateProcessAsUserW"/> was successful; otherwise <c>false</c></returns> private bool SafeCreateProcessAsUserW(IntPtr userToken, CreateProcessFlags createFlags, StartupInfo startupInfo) { _processHandle = new SafeProcessHandle(); var threadHandle = new SafeThreadHandle(); bool success; // The following is necessary to make sure that processInformation.hProcess and processInformation.hThread // are safely stored in the respective SafeHandle classes. It is, unfortunately, not possible to define // processInformation.hProcess and processInformation.hThread as SafeHandles and use processInformation // as an out parameter, because the unmanaged code is not able to create these objects. We therefore use // IntPtr and ensure in the following that the IntPtrs are stored in SafeHandle objects immediately after // they have been obtained. // For details see here: https://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.runtimehelpers.prepareconstrainedregions(v=vs.110).aspx RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { ProcessInformation processInformation; success = CreateProcessAsUserW(userToken, null, GetCommandLine(), IntPtr.Zero, IntPtr.Zero, true, createFlags, IntPtr.Zero, null, startupInfo, out processInformation); if (success) { _processHandle.InitialSetHandle(processInformation.hProcess); threadHandle.InitialSetHandle(processInformation.hThread); _processId = processInformation.dwProcessId; } } // We don't need the threadHandle and therefore immediately dispose it. threadHandle.Dispose(); if (success) { return(true); } _processHandle.Dispose(); var error = Marshal.GetLastWin32Error(); _debugLogger.Error("AsyncImpersonationProcess ({0}): Cannot start process. ErrorCode: {1} ({2})", StartInfo.FileName, error, new Win32Exception(error).Message); return(false); }
/// <summary>Starts the process using the supplied start info.</summary> /// <param name="startInfo">The start info with which to start the process.</param> private unsafe bool StartWithCreateProcess(ProcessStartInfo startInfo) { // See knowledge base article Q190351 for an explanation of the following code. Noteworthy tricky points: // * The handles are duplicated as non-inheritable before they are passed to CreateProcess so // that the child process can not close them // * CreateProcess allows you to redirect all or none of the standard IO handles, so we use // GetStdHandle for the handles that are not being redirected StringBuilder commandLine = BuildCommandLine(startInfo.FileName, StartInfo.Arguments); Process.AppendArguments(commandLine, StartInfo.ArgumentList); Interop.Kernel32.STARTUPINFO startupInfo = new Interop.Kernel32.STARTUPINFO(); Interop.Kernel32.PROCESS_INFORMATION processInfo = new Interop.Kernel32.PROCESS_INFORMATION(); Interop.Kernel32.SECURITY_ATTRIBUTES unused_SecAttrs = new Interop.Kernel32.SECURITY_ATTRIBUTES(); SafeProcessHandle procSH = new SafeProcessHandle(); SafeThreadHandle threadSH = new SafeThreadHandle(); // handles used in parent process SafeFileHandle parentInputPipeHandle = null; SafeFileHandle childInputPipeHandle = null; SafeFileHandle parentOutputPipeHandle = null; SafeFileHandle childOutputPipeHandle = null; SafeFileHandle parentErrorPipeHandle = null; SafeFileHandle childErrorPipeHandle = null; lock (s_createProcessLock) { try { startupInfo.cb = sizeof(Interop.Kernel32.STARTUPINFO); // set up the streams if (startInfo.RedirectStandardInput || startInfo.RedirectStandardOutput || startInfo.RedirectStandardError) { if (startInfo.RedirectStandardInput) { CreatePipe(out parentInputPipeHandle, out childInputPipeHandle, true); } else { childInputPipeHandle = new SafeFileHandle(Interop.Kernel32.GetStdHandle(Interop.Kernel32.HandleTypes.STD_INPUT_HANDLE), false); } if (startInfo.RedirectStandardOutput) { CreatePipe(out parentOutputPipeHandle, out childOutputPipeHandle, false); } else { childOutputPipeHandle = new SafeFileHandle(Interop.Kernel32.GetStdHandle(Interop.Kernel32.HandleTypes.STD_OUTPUT_HANDLE), false); } if (startInfo.RedirectStandardError) { CreatePipe(out parentErrorPipeHandle, out childErrorPipeHandle, false); } else { childErrorPipeHandle = new SafeFileHandle(Interop.Kernel32.GetStdHandle(Interop.Kernel32.HandleTypes.STD_ERROR_HANDLE), false); } startupInfo.hStdInput = childInputPipeHandle.DangerousGetHandle(); startupInfo.hStdOutput = childOutputPipeHandle.DangerousGetHandle(); startupInfo.hStdError = childErrorPipeHandle.DangerousGetHandle(); startupInfo.dwFlags = Interop.Advapi32.StartupInfoOptions.STARTF_USESTDHANDLES; } // set up the creation flags parameter int creationFlags = 0; if (startInfo.CreateNoWindow) { creationFlags |= Interop.Advapi32.StartupInfoOptions.CREATE_NO_WINDOW; } // set up the environment block parameter string environmentBlock = null; if (startInfo._environmentVariables != null) { creationFlags |= Interop.Advapi32.StartupInfoOptions.CREATE_UNICODE_ENVIRONMENT; environmentBlock = GetEnvironmentVariablesBlock(startInfo._environmentVariables); } string workingDirectory = startInfo.WorkingDirectory; if (workingDirectory == string.Empty) { workingDirectory = Directory.GetCurrentDirectory(); } bool retVal; int errorCode = 0; if (startInfo.UserName.Length != 0) { if (startInfo.Password != null && startInfo.PasswordInClearText != null) { throw new ArgumentException(SR.CantSetDuplicatePassword); } Interop.Advapi32.LogonFlags logonFlags = (Interop.Advapi32.LogonFlags) 0; if (startInfo.LoadUserProfile) { logonFlags = Interop.Advapi32.LogonFlags.LOGON_WITH_PROFILE; } fixed(char *passwordInClearTextPtr = startInfo.PasswordInClearText ?? string.Empty) fixed(char *environmentBlockPtr = environmentBlock) { IntPtr passwordPtr = (startInfo.Password != null) ? Marshal.SecureStringToGlobalAllocUnicode(startInfo.Password) : IntPtr.Zero; try { retVal = Interop.Advapi32.CreateProcessWithLogonW( startInfo.UserName, startInfo.Domain, (passwordPtr != IntPtr.Zero) ? passwordPtr : (IntPtr)passwordInClearTextPtr, logonFlags, null, // we don't need this since all the info is in commandLine commandLine, creationFlags, (IntPtr)environmentBlockPtr, workingDirectory, ref startupInfo, // pointer to STARTUPINFO ref processInfo // pointer to PROCESS_INFORMATION ); if (!retVal) { errorCode = Marshal.GetLastWin32Error(); } } finally { if (passwordPtr != IntPtr.Zero) { Marshal.ZeroFreeGlobalAllocUnicode(passwordPtr); } } } } else { fixed(char *environmentBlockPtr = environmentBlock) { retVal = Interop.Kernel32.CreateProcess( null, // we don't need this since all the info is in commandLine commandLine, // pointer to the command line string ref unused_SecAttrs, // address to process security attributes, we don't need to inherit the handle ref unused_SecAttrs, // address to thread security attributes. true, // handle inheritance flag creationFlags, // creation flags (IntPtr)environmentBlockPtr, // pointer to new environment block workingDirectory, // pointer to current directory name ref startupInfo, // pointer to STARTUPINFO ref processInfo // pointer to PROCESS_INFORMATION ); if (!retVal) { errorCode = Marshal.GetLastWin32Error(); } } } if (processInfo.hProcess != IntPtr.Zero && processInfo.hProcess != new IntPtr(-1)) { procSH.InitialSetHandle(processInfo.hProcess); } if (processInfo.hThread != IntPtr.Zero && processInfo.hThread != new IntPtr(-1)) { threadSH.InitialSetHandle(processInfo.hThread); } if (!retVal) { if (errorCode == Interop.Errors.ERROR_BAD_EXE_FORMAT || errorCode == Interop.Errors.ERROR_EXE_MACHINE_TYPE_MISMATCH) { throw new Win32Exception(errorCode, SR.InvalidApplication); } throw new Win32Exception(errorCode); } } finally { childInputPipeHandle?.Dispose(); childOutputPipeHandle?.Dispose(); childErrorPipeHandle?.Dispose(); threadSH?.Dispose(); } } if (startInfo.RedirectStandardInput) { Encoding enc = startInfo.StandardInputEncoding ?? GetEncoding((int)Interop.Kernel32.GetConsoleCP()); _standardInput = new StreamWriter(new FileStream(parentInputPipeHandle, FileAccess.Write, 4096, false), enc, 4096); _standardInput.AutoFlush = true; } if (startInfo.RedirectStandardOutput) { Encoding enc = startInfo.StandardOutputEncoding ?? GetEncoding((int)Interop.Kernel32.GetConsoleOutputCP()); _standardOutput = new StreamReader(new FileStream(parentOutputPipeHandle, FileAccess.Read, 4096, false), enc, true, 4096); } if (startInfo.RedirectStandardError) { Encoding enc = startInfo.StandardErrorEncoding ?? GetEncoding((int)Interop.Kernel32.GetConsoleOutputCP()); _standardError = new StreamReader(new FileStream(parentErrorPipeHandle, FileAccess.Read, 4096, false), enc, true, 4096); } if (procSH.IsInvalid) { return(false); } SetProcessHandle(procSH); SetProcessId((int)processInfo.dwProcessId); return(true); }
public static bool CreateProcess(ProcessStartInfo startInfo, bool createSuspended, out SafeProcessHandle process, out SafeThreadHandle thread, out uint processID, out uint threadID) { StringBuilder cmdLine = BuildCommandLine(startInfo.FileName, startInfo.Arguments); STARTUPINFO lpStartupInfo = new STARTUPINFO(); PROCESS_INFORMATION lpProcessInformation = new PROCESS_INFORMATION(); SafeProcessHandle processHandle = new SafeProcessHandle(); SafeThreadHandle threadHandle = new SafeThreadHandle(); GCHandle environment = new GCHandle(); int creationFlags = 0; bool success; creationFlags = CREATE_DEFAULT_ERROR_MODE | CREATE_PRESERVE_CODE_AUTHZ_LEVEL; if (createSuspended) { creationFlags |= CREATE_SUSPENDED; } if (startInfo.CreateNoWindow) { creationFlags |= CREATE_NO_WINDOW; } IntPtr pinnedEnvironment = IntPtr.Zero; if (startInfo.EnvironmentVariables != null) { bool unicode = false; if (IsNt) { creationFlags |= CREATE_UNICODE_ENVIRONMENT; unicode = true; } environment = GCHandle.Alloc(EnvironmentToByteArray(startInfo.EnvironmentVariables, unicode), GCHandleType.Pinned); pinnedEnvironment = environment.AddrOfPinnedObject(); } string workingDirectory = startInfo.WorkingDirectory; if (workingDirectory == "") { workingDirectory = Environment.CurrentDirectory; } success = CreateProcess(null, cmdLine, null, null, false, creationFlags, pinnedEnvironment, workingDirectory, lpStartupInfo, lpProcessInformation); if ((lpProcessInformation.hProcess != IntPtr.Zero) && (lpProcessInformation.hProcess != INVALID_HANDLE_VALUE)) { processHandle.InitialSetHandle(lpProcessInformation.hProcess); } if ((lpProcessInformation.hThread != IntPtr.Zero) && (lpProcessInformation.hThread != INVALID_HANDLE_VALUE)) { threadHandle.InitialSetHandle(lpProcessInformation.hThread); } if (environment.IsAllocated) { environment.Free(); } lpStartupInfo.Dispose(); if (success && !processHandle.IsInvalid && !threadHandle.IsInvalid) { process = processHandle; thread = threadHandle; processID = lpProcessInformation.dwProcessId; threadID = lpProcessInformation.dwThreadId; return(true); } process = null; thread = null; processID = 0; threadID = 0; return(false); }
public static bool CreateProcess(ProcessStartInfo startInfo, bool createSuspended, out SafeProcessHandle process, out SafeThreadHandle thread, out uint processID, out uint threadID) { StringBuilder cmdLine = BuildCommandLine(startInfo.FileName, startInfo.Arguments); STARTUPINFO lpStartupInfo = new STARTUPINFO(); PROCESS_INFORMATION lpProcessInformation = new PROCESS_INFORMATION(); SafeProcessHandle processHandle = new SafeProcessHandle(); SafeThreadHandle threadHandle = new SafeThreadHandle(); GCHandle environment = new GCHandle(); int creationFlags = 0; bool success; creationFlags = CREATE_DEFAULT_ERROR_MODE | CREATE_PRESERVE_CODE_AUTHZ_LEVEL; if (createSuspended) creationFlags |= CREATE_SUSPENDED; if (startInfo.CreateNoWindow) creationFlags |= CREATE_NO_WINDOW; IntPtr pinnedEnvironment = IntPtr.Zero; if (startInfo.EnvironmentVariables != null) { bool unicode = false; if (IsNt) { creationFlags |= CREATE_UNICODE_ENVIRONMENT; unicode = true; } environment = GCHandle.Alloc(EnvironmentToByteArray(startInfo.EnvironmentVariables, unicode), GCHandleType.Pinned); pinnedEnvironment = environment.AddrOfPinnedObject(); } string workingDirectory = startInfo.WorkingDirectory; if (workingDirectory == "") workingDirectory = Environment.CurrentDirectory; success = CreateProcess(null, cmdLine, null, null, false, creationFlags, pinnedEnvironment, workingDirectory, lpStartupInfo, lpProcessInformation); if ((lpProcessInformation.hProcess != IntPtr.Zero) && (lpProcessInformation.hProcess != INVALID_HANDLE_VALUE)) processHandle.InitialSetHandle(lpProcessInformation.hProcess); if ((lpProcessInformation.hThread != IntPtr.Zero) && (lpProcessInformation.hThread != INVALID_HANDLE_VALUE)) threadHandle.InitialSetHandle(lpProcessInformation.hThread); if (environment.IsAllocated) environment.Free(); lpStartupInfo.Dispose(); if (success && !processHandle.IsInvalid && !threadHandle.IsInvalid) { process = processHandle; thread = threadHandle; processID = lpProcessInformation.dwProcessId; threadID = lpProcessInformation.dwThreadId; return true; } process = null; thread = null; processID = 0; threadID = 0; return false; }
private static unsafe int ExecWaitWithCaptureUnimpersonated(SafeUserTokenHandle userToken, string cmd, string currentDir, TempFileCollection tempFiles, ref string outputName, ref string errorName, string trueCmdLine) { IntSecurity.UnmanagedCode.Demand(); FileStream output; FileStream error; int retValue = 0; if (outputName == null || outputName.Length == 0) { outputName = tempFiles.AddExtension("out"); } if (errorName == null || errorName.Length == 0) { errorName = tempFiles.AddExtension("err"); } // Create the files output = CreateInheritedFile(outputName); error = CreateInheritedFile(errorName); bool success = false; SafeNativeMethods.PROCESS_INFORMATION pi = new SafeNativeMethods.PROCESS_INFORMATION(); SafeProcessHandle procSH = new SafeProcessHandle(); SafeThreadHandle threadSH = new SafeThreadHandle(); SafeUserTokenHandle primaryToken = null; try { // Output the command line... StreamWriter sw = new StreamWriter(output, Encoding.UTF8); sw.Write(currentDir); sw.Write("> "); // 'true' command line is used in case the command line points to // a response file sw.WriteLine(trueCmdLine != null ? trueCmdLine : cmd); sw.WriteLine(); sw.WriteLine(); sw.Flush(); NativeMethods.STARTUPINFO si = new NativeMethods.STARTUPINFO(); si.cb = Marshal.SizeOf(si); si.dwFlags = NativeMethods.STARTF_USESTDHANDLES; si.hStdOutput = output.SafeFileHandle; si.hStdError = error.SafeFileHandle; si.hStdInput = new SafeFileHandle(UnsafeNativeMethods.GetStdHandle(NativeMethods.STD_INPUT_HANDLE), false); // // Prepare the environment // #if PLATFORM_UNIX StringDictionary environment = new CaseSensitiveStringDictionary(); #else StringDictionary environment = new StringDictionary(); #endif // PLATFORM_UNIX // Add the current environment foreach (DictionaryEntry entry in Environment.GetEnvironmentVariables()) { environment.Add((string)entry.Key, (string)entry.Value); } // Add the flag to indicate restricted security in the process environment["_ClrRestrictSecAttributes"] = "1"; #if DEBUG environment["OANOCACHE"] = "1"; #endif // set up the environment block parameter byte[] environmentBytes = EnvironmentBlock.ToByteArray(environment, false); fixed(byte *environmentBytesPtr = environmentBytes) { IntPtr environmentPtr = new IntPtr((void *)environmentBytesPtr); if (userToken == null || userToken.IsInvalid) { RuntimeHelpers.PrepareConstrainedRegions(); try {} finally { success = NativeMethods.CreateProcess( null, // String lpApplicationName, new StringBuilder(cmd), // String lpCommandLine, null, // SECURITY_ATTRIBUTES lpProcessAttributes, null, // SECURITY_ATTRIBUTES lpThreadAttributes, true, // bool bInheritHandles, 0, // int dwCreationFlags, environmentPtr, // int lpEnvironment, currentDir, // String lpCurrentDirectory, si, // STARTUPINFO lpStartupInfo, pi); // PROCESS_INFORMATION lpProcessInformation); if (pi.hProcess != (IntPtr)0 && pi.hProcess != (IntPtr)NativeMethods.INVALID_HANDLE_VALUE) { procSH.InitialSetHandle(pi.hProcess); } if (pi.hThread != (IntPtr)0 && pi.hThread != (IntPtr)NativeMethods.INVALID_HANDLE_VALUE) { threadSH.InitialSetHandle(pi.hThread); } } } else { throw new NotSupportedException(); } } } finally { // Close the file handles if (!success && (primaryToken != null && !primaryToken.IsInvalid)) { primaryToken.Close(); primaryToken = null; } output.Close(); error.Close(); } if (success) { try { int ret = NativeMethods.WaitForSingleObject(procSH, ProcessTimeOut); // Check for timeout if (ret == NativeMethods.WAIT_TIMEOUT) { throw new ExternalException(SR.GetString(SR.ExecTimeout, cmd), NativeMethods.WAIT_TIMEOUT); } if (ret != NativeMethods.WAIT_OBJECT_0) { throw new ExternalException(SR.GetString(SR.ExecBadreturn, cmd), Marshal.GetLastWin32Error()); } // Check the process's exit code int status = NativeMethods.STILL_ACTIVE; if (!NativeMethods.GetExitCodeProcess(procSH, out status)) { throw new ExternalException(SR.GetString(SR.ExecCantGetRetCode, cmd), Marshal.GetLastWin32Error()); } retValue = status; } finally { procSH.Close(); threadSH.Close(); if (primaryToken != null && !primaryToken.IsInvalid) { primaryToken.Close(); } } } else { throw new ExternalException(SR.GetString(SR.ExecCantExec, cmd), Marshal.GetLastWin32Error()); } return(retValue); }
/// <summary>Starts the process using the supplied start info.</summary> /// <param name="startInfo">The start info with which to start the process.</param> private bool StartCore(ProcessStartInfo startInfo) { // See knowledge base article Q190351 for an explanation of the following code. Noteworthy tricky points: // * The handles are duplicated as non-inheritable before they are passed to CreateProcess so // that the child process can not close them // * CreateProcess allows you to redirect all or none of the standard IO handles, so we use // GetStdHandle for the handles that are not being redirected StringBuilder commandLine = BuildCommandLine(startInfo.FileName, startInfo.Arguments); Interop.Kernel32.STARTUPINFO startupInfo = new Interop.Kernel32.STARTUPINFO(); Interop.Kernel32.PROCESS_INFORMATION processInfo = new Interop.Kernel32.PROCESS_INFORMATION(); Interop.Kernel32.SECURITY_ATTRIBUTES unused_SecAttrs = new Interop.Kernel32.SECURITY_ATTRIBUTES(); SafeProcessHandle procSH = new SafeProcessHandle(); SafeThreadHandle threadSH = new SafeThreadHandle(); bool retVal; int errorCode = 0; // handles used in parent process SafeFileHandle standardInputWritePipeHandle = null; SafeFileHandle standardOutputReadPipeHandle = null; SafeFileHandle standardErrorReadPipeHandle = null; GCHandle environmentHandle = new GCHandle(); lock (s_createProcessLock) { try { // set up the streams if (startInfo.RedirectStandardInput || startInfo.RedirectStandardOutput || startInfo.RedirectStandardError) { if (startInfo.RedirectStandardInput) { CreatePipe(out standardInputWritePipeHandle, out startupInfo.hStdInput, true); } else { startupInfo.hStdInput = new SafeFileHandle(Interop.Kernel32.GetStdHandle(Interop.Kernel32.HandleTypes.STD_INPUT_HANDLE), false); } if (startInfo.RedirectStandardOutput) { CreatePipe(out standardOutputReadPipeHandle, out startupInfo.hStdOutput, false); } else { startupInfo.hStdOutput = new SafeFileHandle(Interop.Kernel32.GetStdHandle(Interop.Kernel32.HandleTypes.STD_OUTPUT_HANDLE), false); } if (startInfo.RedirectStandardError) { CreatePipe(out standardErrorReadPipeHandle, out startupInfo.hStdError, false); } else { startupInfo.hStdError = new SafeFileHandle(Interop.Kernel32.GetStdHandle(Interop.Kernel32.HandleTypes.STD_ERROR_HANDLE), false); } startupInfo.dwFlags = Interop.Advapi32.StartupInfoOptions.STARTF_USESTDHANDLES; } // set up the creation flags parameter int creationFlags = 0; if (startInfo.CreateNoWindow) { creationFlags |= Interop.Advapi32.StartupInfoOptions.CREATE_NO_WINDOW; } // set up the environment block parameter IntPtr environmentPtr = (IntPtr)0; if (startInfo._environmentVariables != null) { creationFlags |= Interop.Advapi32.StartupInfoOptions.CREATE_UNICODE_ENVIRONMENT; byte[] environmentBytes = EnvironmentVariablesToByteArray(startInfo._environmentVariables); environmentHandle = GCHandle.Alloc(environmentBytes, GCHandleType.Pinned); environmentPtr = environmentHandle.AddrOfPinnedObject(); } string workingDirectory = startInfo.WorkingDirectory; if (workingDirectory == string.Empty) { workingDirectory = Directory.GetCurrentDirectory(); } if (startInfo.UserName.Length != 0) { Interop.Advapi32.LogonFlags logonFlags = (Interop.Advapi32.LogonFlags) 0; if (startInfo.LoadUserProfile) { logonFlags = Interop.Advapi32.LogonFlags.LOGON_WITH_PROFILE; } try { } finally { retVal = Interop.Advapi32.CreateProcessWithLogonW( startInfo.UserName, startInfo.Domain, startInfo.PasswordInClearText, logonFlags, null, // we don't need this since all the info is in commandLine commandLine, creationFlags, environmentPtr, workingDirectory, startupInfo, // pointer to STARTUPINFO processInfo // pointer to PROCESS_INFORMATION ); if (!retVal) { errorCode = Marshal.GetLastWin32Error(); } if (processInfo.hProcess != IntPtr.Zero && processInfo.hProcess != (IntPtr)INVALID_HANDLE_VALUE) { procSH.InitialSetHandle(processInfo.hProcess); } if (processInfo.hThread != IntPtr.Zero && processInfo.hThread != (IntPtr)INVALID_HANDLE_VALUE) { threadSH.InitialSetHandle(processInfo.hThread); } } if (!retVal) { if (errorCode == Interop.Errors.ERROR_BAD_EXE_FORMAT || errorCode == Interop.Errors.ERROR_EXE_MACHINE_TYPE_MISMATCH) { throw new Win32Exception(errorCode, SR.InvalidApplication); } throw new Win32Exception(errorCode); } } else { try { } finally { retVal = Interop.Kernel32.CreateProcess( null, // we don't need this since all the info is in commandLine commandLine, // pointer to the command line string ref unused_SecAttrs, // address to process security attributes, we don't need to inherit the handle ref unused_SecAttrs, // address to thread security attributes. true, // handle inheritance flag creationFlags, // creation flags environmentPtr, // pointer to new environment block workingDirectory, // pointer to current directory name startupInfo, // pointer to STARTUPINFO processInfo // pointer to PROCESS_INFORMATION ); if (!retVal) { errorCode = Marshal.GetLastWin32Error(); } if (processInfo.hProcess != (IntPtr)0 && processInfo.hProcess != (IntPtr)INVALID_HANDLE_VALUE) { procSH.InitialSetHandle(processInfo.hProcess); } if (processInfo.hThread != (IntPtr)0 && processInfo.hThread != (IntPtr)INVALID_HANDLE_VALUE) { threadSH.InitialSetHandle(processInfo.hThread); } } if (!retVal) { if (errorCode == Interop.Errors.ERROR_BAD_EXE_FORMAT || errorCode == Interop.Errors.ERROR_EXE_MACHINE_TYPE_MISMATCH) { throw new Win32Exception(errorCode, SR.InvalidApplication); } throw new Win32Exception(errorCode); } } } finally { // free environment block if (environmentHandle.IsAllocated) { environmentHandle.Free(); } startupInfo.Dispose(); } } if (startInfo.RedirectStandardInput) { Encoding enc = GetEncoding((int)Interop.Kernel32.GetConsoleCP()); _standardInput = new StreamWriter(new FileStream(standardInputWritePipeHandle, FileAccess.Write, 4096, false), enc, 4096); _standardInput.AutoFlush = true; } if (startInfo.RedirectStandardOutput) { Encoding enc = startInfo.StandardOutputEncoding ?? GetEncoding((int)Interop.Kernel32.GetConsoleOutputCP()); _standardOutput = new StreamReader(new FileStream(standardOutputReadPipeHandle, FileAccess.Read, 4096, false), enc, true, 4096); } if (startInfo.RedirectStandardError) { Encoding enc = startInfo.StandardErrorEncoding ?? GetEncoding((int)Interop.Kernel32.GetConsoleOutputCP()); _standardError = new StreamReader(new FileStream(standardErrorReadPipeHandle, FileAccess.Read, 4096, false), enc, true, 4096); } bool ret = false; if (!procSH.IsInvalid) { SetProcessHandle(procSH); SetProcessId((int)processInfo.dwProcessId); threadSH.Dispose(); ret = true; } return(ret); }
private bool StartWithCreateProcess(ProcessStartInfo startInfo) { if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput) { throw new InvalidOperationException("StandardOutputEncodingNotAllowed"); } if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError) { throw new InvalidOperationException("StandardErrorEncodingNotAllowed"); } StringBuilder stringBuilder = Process2.BuildCommandLine(startInfo.FileName, startInfo.Arguments); NativeMethods.STARTUPINFO sTARTUPINFO = new NativeMethods.STARTUPINFO(); SafeNativeMethods.PROCESS_INFORMATION pROCESS_INFORMATION = new SafeNativeMethods.PROCESS_INFORMATION(); SafeProcessHandle safeProcessHandle = new SafeProcessHandle(); SafeThreadHandle safeThreadHandle = new SafeThreadHandle(); int num = 0; SafeFileHandle handle = null; SafeFileHandle handle2 = null; SafeFileHandle handle3 = null; GCHandle gCHandle = default(GCHandle); lock (Process2.s_CreateProcessLock) { try { if (startInfo.RedirectStandardInput || startInfo.RedirectStandardOutput || startInfo.RedirectStandardError) { if (startInfo.RedirectStandardInput) { CreatePipe(out handle, out sTARTUPINFO.hStdInput, true); } else { sTARTUPINFO.hStdInput = new SafeFileHandle(NativeMethods.GetStdHandle(-10), false); } if (startInfo.RedirectStandardOutput) { CreatePipe(out handle2, out sTARTUPINFO.hStdOutput, false); } else { sTARTUPINFO.hStdOutput = new SafeFileHandle(NativeMethods.GetStdHandle(-11), false); } if (startInfo.RedirectStandardError) { CreatePipe(out handle3, out sTARTUPINFO.hStdError, false); } else { sTARTUPINFO.hStdError = sTARTUPINFO.hStdOutput; } sTARTUPINFO.dwFlags = 256; } int num2 = 0; if (startInfo.CreateNoWindow) { num2 |= 134217728; } IntPtr intPtr = (IntPtr)0; //if (startInfo.environmentVariables != null) //{ // bool unicode = false; // if (ProcessManager.IsNt) // { // num2 |= 1024; // unicode = true; // } // byte[] value = EnvironmentBlock.ToByteArray(startInfo.environmentVariables, unicode); // gCHandle = GCHandle.Alloc(value, GCHandleType.Pinned); // intPtr = gCHandle.AddrOfPinnedObject(); //} string text = startInfo.WorkingDirectory; if (text == string.Empty) { text = Environment.CurrentDirectory; } bool flag2; //if (startInfo.UserName.Length != 0) //{ // NativeMethods.LogonFlags logonFlags = (NativeMethods.LogonFlags)0; // if (startInfo.LoadUserProfile) // { // logonFlags = NativeMethods.LogonFlags.LOGON_WITH_PROFILE; // } // IntPtr intPtr2 = IntPtr.Zero; // try // { // if (startInfo.Password == null) // { // intPtr2 = Marshal.StringToCoTaskMemUni(string.Empty); // } // else // { // intPtr2 = Marshal.SecureStringToCoTaskMemUnicode(startInfo.Password); // } // RuntimeHelpers.PrepareConstrainedRegions(); // try // { // } // finally // { // flag2 = NativeMethods.CreateProcessWithLogonW(startInfo.UserName, startInfo.Domain, intPtr2, logonFlags, null, stringBuilder, num2, intPtr, text, sTARTUPINFO, pROCESS_INFORMATION); // if (!flag2) // { // num = Marshal.GetLastWin32Error(); // } // if (pROCESS_INFORMATION.hProcess != (IntPtr)0 && pROCESS_INFORMATION.hProcess != NativeMethods.INVALID_HANDLE_VALUE) // { // safeProcessHandle.InitialSetHandle(pROCESS_INFORMATION.hProcess); // } // if (pROCESS_INFORMATION.hThread != (IntPtr)0 && pROCESS_INFORMATION.hThread != NativeMethods.INVALID_HANDLE_VALUE) // { // safeThreadHandle.InitialSetHandle(pROCESS_INFORMATION.hThread); // } // } // if (flag2) // { // goto IL_3B9; // } // if (num == 193 || num == 216) // { // throw new Win32Exception(num, SR.GetString("InvalidApplication")); // } // throw new Win32Exception(num); // } // finally // { // if (intPtr2 != IntPtr.Zero) // { // Marshal.ZeroFreeCoTaskMemUnicode(intPtr2); // } // } //} RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { flag2 = NativeMethods.CreateProcess(null, stringBuilder, null, null, true, num2, intPtr, text, sTARTUPINFO, pROCESS_INFORMATION); if (!flag2) { num = Marshal.GetLastWin32Error(); } if (pROCESS_INFORMATION.hProcess != (IntPtr)0 && pROCESS_INFORMATION.hProcess != NativeMethods.INVALID_HANDLE_VALUE) { safeProcessHandle.InitialSetHandle(pROCESS_INFORMATION.hProcess); } if (pROCESS_INFORMATION.hThread != (IntPtr)0 && pROCESS_INFORMATION.hThread != NativeMethods.INVALID_HANDLE_VALUE) { safeThreadHandle.InitialSetHandle(pROCESS_INFORMATION.hThread); } } if (!flag2) { if (num == 193 || num == 216) { throw new Win32Exception(num, "InvalidApplication"); } throw new Win32Exception(num); } } finally { if (gCHandle.IsAllocated) { gCHandle.Free(); } sTARTUPINFO.Dispose(); } } if (startInfo.RedirectStandardInput) { standardInput = new StreamWriter(new FileStream(handle, FileAccess.Write, 4096, false), Console.InputEncoding, 4096); standardInput.AutoFlush = true; } if (startInfo.RedirectStandardOutput) { Encoding encoding = (startInfo.StandardOutputEncoding != null) ? startInfo.StandardOutputEncoding : Console.OutputEncoding; standardOutput = new StreamReader(new FileStream(handle2, FileAccess.Read, 4096, false), encoding, true, 4096); } if (startInfo.RedirectStandardError) { Encoding encoding2 = (startInfo.StandardErrorEncoding != null) ? startInfo.StandardErrorEncoding : Console.OutputEncoding; standardError = new StreamReader(new FileStream(handle3, FileAccess.Read, 4096, false), encoding2, true, 4096); } bool result = false; if (!safeProcessHandle.IsInvalid) { SetProcessHandle(safeProcessHandle); SetProcessId(pROCESS_INFORMATION.dwProcessId); safeThreadHandle.Close(); result = true; } return result; }
private Task <IPtyConnection> StartPseudoConsoleAsync( PtyOptions options, TraceSource trace, CancellationToken cancellationToken) { // Create the in/out pipes if (!CreatePipe(out SafePipeHandle inPipePseudoConsoleSide, out SafePipeHandle inPipeOurSide, null, 0)) { throw new InvalidOperationException("Could not create an anonymous pipe", new Win32Exception()); } if (!CreatePipe(out SafePipeHandle outPipeOurSide, out SafePipeHandle outPipePseudoConsoleSide, null, 0)) { throw new InvalidOperationException("Could not create an anonymous pipe", new Win32Exception()); } var coord = new Coord(options.Cols, options.Rows); var pseudoConsoleHandle = new SafePseudoConsoleHandle(); int hr; RuntimeHelpers.PrepareConstrainedRegions(); try { // Run CreatePseudoConsole* in a CER to make sure we don't leak handles. // MSDN suggest to put all CER code in a finally block // See http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.runtimehelpers.prepareconstrainedregions(v=vs.110).aspx } finally { // Create the Pseudo Console, using the pipes hr = CreatePseudoConsole(coord, inPipePseudoConsoleSide.Handle, outPipePseudoConsoleSide.Handle, 0, out IntPtr hPC); // Remember the handle inside the CER to prevent leakage if (hPC != IntPtr.Zero && hPC != INVALID_HANDLE_VALUE) { pseudoConsoleHandle.InitialSetHandle(hPC); } } if (hr != S_OK) { Marshal.ThrowExceptionForHR(hr); } // Prepare the StartupInfoEx structure attached to the ConPTY. var startupInfo = default(STARTUPINFOEX); startupInfo.InitAttributeListAttachedToConPTY(pseudoConsoleHandle); IntPtr lpEnvironment = Marshal.StringToHGlobalUni(GetEnvironmentString(options.Environment)); try { string app = GetAppOnPath(options.App, options.Cwd, options.Environment); string arguments = options.VerbatimCommandLine ? WindowsArguments.FormatVerbatim(options.CommandLine) : WindowsArguments.Format(options.CommandLine); var commandLine = new StringBuilder(app.Length + arguments.Length + 4); bool quoteApp = app.Contains(" ") && !app.StartsWith("\"") && !app.EndsWith("\""); if (quoteApp) { commandLine.Append('"').Append(app).Append('"'); } else { commandLine.Append(app); } if (!string.IsNullOrWhiteSpace(arguments)) { commandLine.Append(' '); commandLine.Append(arguments); } bool success; int errorCode = 0; var processInfo = default(PROCESS_INFORMATION); var processHandle = new SafeProcessHandle(); var mainThreadHandle = new SafeThreadHandle(); RuntimeHelpers.PrepareConstrainedRegions(); try { // Run CreateProcess* in a CER to make sure we don't leak handles. } finally { success = CreateProcess( null, // lpApplicationName commandLine.ToString(), null, // lpProcessAttributes null, // lpThreadAttributes false, // bInheritHandles VERY IMPORTANT that this is false EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT, // dwCreationFlags lpEnvironment, options.Cwd, ref startupInfo, out processInfo); if (!success) { errorCode = Marshal.GetLastWin32Error(); } // Remember the handles inside the CER to prevent leakage if (processInfo.hProcess != IntPtr.Zero && processInfo.hProcess != INVALID_HANDLE_VALUE) { processHandle.InitialSetHandle(processInfo.hProcess); } if (processInfo.hThread != IntPtr.Zero && processInfo.hThread != INVALID_HANDLE_VALUE) { mainThreadHandle.InitialSetHandle(processInfo.hThread); } } if (!success) { var exception = new Win32Exception(errorCode); throw new InvalidOperationException($"Could not start terminal process {commandLine.ToString()}: {exception.Message}", exception); } var connectionOptions = new PseudoConsoleConnection.PseudoConsoleConnectionHandles( inPipePseudoConsoleSide, outPipePseudoConsoleSide, inPipeOurSide, outPipeOurSide, pseudoConsoleHandle, processHandle, processInfo.dwProcessId, mainThreadHandle); var result = new PseudoConsoleConnection(connectionOptions); return(Task.FromResult <IPtyConnection>(result)); } finally { startupInfo.FreeAttributeList(); if (lpEnvironment != IntPtr.Zero) { Marshal.FreeHGlobal(lpEnvironment); } } }
/// <summary> /// Calls <see cref="CreateProcessAsUserW"/> and safely stores the obtained handles. /// </summary> /// <param name="userToken">Token to impersonate the external process</param> /// <param name="createFlags">Flags used to create the external process</param> /// <param name="startupInfo">Startup information used to create the external process</param> /// <returns><c>true</c> if the call to <see cref="CreateProcessAsUserW"/> was successful; otherwise <c>false</c></returns> private bool SafeCreateProcessAsUserW(IntPtr userToken, CreateProcessFlags createFlags, StartupInfo startupInfo) { _processHandle = new SafeProcessHandle(); var threadHandle = new SafeThreadHandle(); bool success; // The following is necessary to make sure that processInformation.hProcess and processInformation.hThread // are safely stored in the respective SafeHandle classes. It is, unfortunately, not possible to define // processInformation.hProcess and processInformation.hThread as SafeHandles and use processInformation // as an out parameter, because the unmanaged code is not able to create these objects. We therefore use // IntPtr and ensure in the following that the IntPtrs are stored in SafeHandle objects immediately after // they have been obtained. // For details see here: https://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.runtimehelpers.prepareconstrainedregions(v=vs.110).aspx RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { ProcessInformation processInformation; success = CreateProcessAsUserW(userToken, null, GetCommandLine(), IntPtr.Zero, IntPtr.Zero, true, createFlags, IntPtr.Zero, null, startupInfo, out processInformation); if (success) { _processHandle.InitialSetHandle(processInformation.hProcess); threadHandle.InitialSetHandle(processInformation.hThread); _processId = processInformation.dwProcessId; } } // We don't need the threadHandle and therefore immediately dispose it. threadHandle.Dispose(); if (success) return true; _processHandle.Dispose(); var error = Marshal.GetLastWin32Error(); _debugLogger.Error("AsyncImpersonationProcess ({0}): Cannot start process. ErrorCode: {1} ({2})", StartInfo.FileName, error, new Win32Exception(error).Message); return false; }