public RestrictedProcess(string fileName, string workingDirectory, 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 = new 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;

            if (!NativeMethods.CreateProcessAsUser(
                    restrictedToken,
                    null,
                    fileName,
                    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.hProcess);

            // 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);
        }
Example #2
0
 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);
 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);
        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 = new 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);
        }