internal static extern bool CreateProcessAsUser( IntPtr hToken, string lpApplicationName, string lpCommandLine, SecurityAttributes lpProcessAttributes, SecurityAttributes lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, StartupInfo lpStartupInfo, out ProcessInformation lpProcessInformation);
private void CreatePipe(out SafeFileHandle parentHandle, out SafeFileHandle childHandle, bool parentInputs, int bufferSize) { var securityAttributesParent = new SecurityAttributes { InheritHandle = true }; SafeFileHandle tempHandle = null; try { if (parentInputs) { this.CreatePipeWithSecurityAttributes(out childHandle, out tempHandle, securityAttributesParent, bufferSize); } else { this.CreatePipeWithSecurityAttributes(out tempHandle, out childHandle, securityAttributesParent, bufferSize); } // Duplicate the parent handle to be non-inheritable so that the child process // doesn't have access. This is done for correctness sake, exact reason is unclear. // One potential theory is that child process can do something brain dead like // closing the parent end of the pipe and there by getting into a blocking situation // as parent will not be draining the pipe at the other end anymore. // Create a duplicate of the output write handle for the std error write handle. // This is necessary in case the child application closes one of its std output handles. if (!NativeMethods.DuplicateHandle( new HandleRef(this, NativeMethods.GetCurrentProcess()), tempHandle, new HandleRef(this, NativeMethods.GetCurrentProcess()), out parentHandle, // Address of new handle. 0, false, // Make it un-inheritable. (int)DuplicateOptions.DUPLICATE_SAME_ACCESS)) { throw new Win32Exception(); } } finally { // Close inheritable copies of the handles you do not want to be inherited. if (tempHandle != null && !tempHandle.IsInvalid) { tempHandle.Close(); } } }
internal static extern bool CreatePipe( out SafeFileHandle hReadPipe, out SafeFileHandle hWritePipe, SecurityAttributes lpPipeAttributes, int nSize);
private void CreatePipeWithSecurityAttributes(out SafeFileHandle readPipe, out SafeFileHandle writePipe, SecurityAttributes pipeAttributes, int size) { if (!NativeMethods.CreatePipe(out readPipe, out writePipe, pipeAttributes, size) || readPipe.IsInvalid || writePipe.IsInvalid) { throw new Win32Exception(); } }
public RestrictedProcess(string fileName, string workingDirectory, IEnumerable <string> arguments = null, int bufferSize = 4096) { // Initialize fields this.fileName = fileName; this.IsDisposed = false; // Prepare startup info and redirect standard IO handles var startupInfo = new StartupInfo(); this.RedirectStandardIoHandles(ref startupInfo, bufferSize); // Create restricted token var restrictedToken = this.CreateRestrictedToken(); // Set mandatory label this.SetTokenMandatoryLabel(restrictedToken, SecurityMandatoryLabel.Low); var processSecurityAttributes = new SecurityAttributes(); var threadSecurityAttributes = new SecurityAttributes(); this.processInformation = default(ProcessInformation); const uint CreationFlags = (uint)( CreateProcessFlags.CREATE_SUSPENDED | CreateProcessFlags.CREATE_BREAKAWAY_FROM_JOB | CreateProcessFlags.CREATE_UNICODE_ENVIRONMENT | CreateProcessFlags.CREATE_NEW_PROCESS_GROUP | CreateProcessFlags.DETACHED_PROCESS | // http://stackoverflow.com/questions/6371149/what-is-the-difference-between-detach-process-and-create-no-window-process-creat CreateProcessFlags.CREATE_NO_WINDOW) | (uint)ProcessPriorityClass.High; string commandLine; if (arguments != null) { var commandLineBuilder = new StringBuilder(); commandLineBuilder.AppendFormat("\"{0}\"", fileName); foreach (var argument in arguments) { commandLineBuilder.Append(' '); commandLineBuilder.Append(argument); } commandLine = commandLineBuilder.ToString(); } else { commandLine = fileName; } if (!NativeMethods.CreateProcessAsUser( restrictedToken, null, commandLine, processSecurityAttributes, threadSecurityAttributes, true, // In order to standard input, output and error redirection work, the handles must be inheritable and the CreateProcess() API must specify that inheritable handles are to be inherited by the child process by specifying TRUE in the bInheritHandles parameter. CreationFlags, IntPtr.Zero, workingDirectory, startupInfo, out this.processInformation)) { throw new Win32Exception(); } this.safeProcessHandle = new SafeProcessHandle(this.processInformation.Process); // This is a very important line! Without disposing the startupInfo handles, reading the standard output (or error) will hang forever. // Same problem described here: http://social.msdn.microsoft.com/Forums/vstudio/en-US/3c25a2e8-b1ea-4fc4-927b-cb865d435147/how-does-processstart-work-in-getting-output startupInfo.Dispose(); NativeMethods.CloseHandle(restrictedToken); }