public IProcess StartHost(Interpreter interpreter, string profilePath, string userName, WindowsIdentity useridentity, string commandLine)
        {
            string brokerPath   = Path.GetDirectoryName(typeof(Program).Assembly.GetAssemblyPath());
            string rhostExePath = Path.Combine(brokerPath, RHostExe);

            commandLine = FormattableString.Invariant($"\"{rhostExePath}\" {commandLine}");
            var usernameBldr = new StringBuilder(NativeMethods.CREDUI_MAX_USERNAME_LENGTH + 1);
            var domainBldr   = new StringBuilder(NativeMethods.CREDUI_MAX_DOMAIN_LENGTH + 1);

            // Get R_HOME value
            var shortHome = new StringBuilder(NativeMethods.MAX_PATH);

            NativeMethods.GetShortPathName(interpreter.Info.Path, shortHome, shortHome.Capacity);

            var loggedOnUser = useridentity != null && WindowsIdentity.GetCurrent().User != useridentity.User;

            // build user environment block
            Win32EnvironmentBlock eb;

            if (loggedOnUser)
            {
                uint error = NativeMethods.CredUIParseUserName(userName, usernameBldr, usernameBldr.Capacity, domainBldr, domainBldr.Capacity);
                if (error != 0)
                {
                    _sessionLogger.LogError(Resources.Error_UserNameParse, userName, error);
                    throw new ArgumentException(Resources.Error_UserNameParse.FormatInvariant(userName, error));
                }

                string username = usernameBldr.ToString();
                string domain   = domainBldr.ToString();

                eb = CreateEnvironmentBlockForUser(useridentity, username, profilePath);
            }
            else
            {
                eb = Win32EnvironmentBlock.Create((useridentity ?? WindowsIdentity.GetCurrent()).Token);
            }

            // add additional variables to the environment block
            eb["R_HOME"] = shortHome.ToString();
            _sessionLogger.LogTrace(Resources.Trace_EnvironmentVariable, "R_HOME", eb["R_HOME"]);
            eb["PATH"] = FormattableString.Invariant($"{interpreter.Info.BinPath};{Environment.GetEnvironmentVariable("PATH")}");
            _sessionLogger.LogTrace(Resources.Trace_EnvironmentVariable, "PATH", eb["PATH"]);

            Win32Process win32Process;

            using (Win32NativeEnvironmentBlock nativeEnv = eb.GetNativeEnvironmentBlock()) {
                if (loggedOnUser)
                {
                    win32Process = Win32Process.StartProcessAsUser(useridentity, rhostExePath, commandLine, Path.GetDirectoryName(rhostExePath), nativeEnv);
                }
                else
                {
                    win32Process = Win32Process.StartProcessAsUser(null, rhostExePath, commandLine, Path.GetDirectoryName(rhostExePath), nativeEnv);
                }
            }

            win32Process.WaitForExit(250);
            if (win32Process.HasExited && win32Process.ExitCode < 0)
            {
                var message = ErrorCodeConverter.MessageFromErrorCode(win32Process.ExitCode);
                if (!string.IsNullOrEmpty(message))
                {
                    throw new Win32Exception(message);
                }
                throw new Win32Exception(win32Process.ExitCode);
            }

            return(win32Process);
        }
Example #2
0
        public void StartHost(string profilePath, string logFolder, ILogger outputLogger, LogVerbosity verbosity)
        {
            if (_hostEnd != null)
            {
                throw new InvalidOperationException("Host process is already running");
            }

            var useridentity = User as WindowsIdentity;
            // In remote broker User Identity type is always WindowsIdentity
            string suppressUI     = (useridentity == null) ? string.Empty : "--rhost-suppress-ui ";
            string isRepl         = _isInteractive ? "--rhost-interactive " : string.Empty;
            string brokerPath     = Path.GetDirectoryName(typeof(Program).Assembly.GetAssemblyPath());
            string rhostExePath   = Path.Combine(brokerPath, RHostExe);
            string logFolderParam = string.IsNullOrEmpty(logFolder) ? string.Empty : Invariant($"--rhost-log-dir \"{logFolder}\"");
            string commandLine    = Invariant($"\"{rhostExePath}\" {suppressUI}{isRepl}--rhost-name \"{Id}\" {logFolderParam} --rhost-log-verbosity {(int)verbosity} {CommandLineArguments}");
            var    usernameBldr   = new StringBuilder(NativeMethods.CREDUI_MAX_USERNAME_LENGTH + 1);
            var    domainBldr     = new StringBuilder(NativeMethods.CREDUI_MAX_DOMAIN_LENGTH + 1);

            // Get R_HOME value
            var shortHome = new StringBuilder(NativeMethods.MAX_PATH);

            NativeMethods.GetShortPathName(Interpreter.Info.Path, shortHome, shortHome.Capacity);

            Stream stdout, stdin, stderror;
            bool   loggedOnUser = useridentity != null && WindowsIdentity.GetCurrent().User != useridentity.User;

            // build user environment block
            Win32EnvironmentBlock eb;

            if (loggedOnUser)
            {
                uint error = NativeMethods.CredUIParseUserName(User.Name, usernameBldr, usernameBldr.Capacity, domainBldr, domainBldr.Capacity);
                if (error != 0)
                {
                    _sessionLogger.LogError(Resources.Error_UserNameParse, User.Name, error);
                    throw new ArgumentException(Resources.Error_UserNameParse.FormatInvariant(User.Name, error));
                }

                string username = usernameBldr.ToString();
                string domain   = domainBldr.ToString();

                eb = CreateEnvironmentBlockForUser(useridentity, username, profilePath);
            }
            else
            {
                eb = Win32EnvironmentBlock.Create((useridentity ?? WindowsIdentity.GetCurrent()).Token);
            }

            // add additional variables to the environment block
            eb["R_HOME"] = shortHome.ToString();
            _sessionLogger.LogTrace(Resources.Trace_EnvironmentVariable, "R_HOME", eb["R_HOME"]);
            eb["PATH"] = Invariant($"{Interpreter.Info.BinPath};{Environment.GetEnvironmentVariable("PATH")}");
            _sessionLogger.LogTrace(Resources.Trace_EnvironmentVariable, "PATH", eb["PATH"]);


            _sessionLogger.LogInformation(Resources.Info_StartingRHost, Id, User.Name, commandLine);
            using (Win32NativeEnvironmentBlock nativeEnv = eb.GetNativeEnvironmentBlock()) {
                if (loggedOnUser)
                {
                    _process = Win32Process.StartProcessAsUser(useridentity, rhostExePath, commandLine, Path.GetDirectoryName(rhostExePath), nativeEnv, out stdin, out stdout, out stderror);
                }
                else
                {
                    _process = Win32Process.StartProcessAsUser(null, rhostExePath, commandLine, Path.GetDirectoryName(rhostExePath), nativeEnv, out stdin, out stdout, out stderror);
                }
            }

            _process.Exited += delegate(object o, Win32ProcessExitEventArgs exitState){
                _hostEnd?.Dispose();
                _hostEnd = null;
                State    = SessionState.Terminated;
                if (exitState.HasError())
                {
                    _sessionLogger.LogInformation(Resources.Error_ExitRHost, exitState.ExitCode);
                }
            };

            _process.WaitForExit(250);
            if (_process.HasExited && _process.ExitCode < 0)
            {
                var message = ErrorCodeConverter.MessageFromErrorCode(_process.ExitCode);
                if (!string.IsNullOrEmpty(message))
                {
                    throw new Win32Exception(message);
                }
                throw new Win32Exception(_process.ExitCode);
            }

            _sessionLogger.LogInformation(Resources.Info_StartedRHost, Id, User.Name);

            var hostEnd = _pipe.ConnectHost(_process.ProcessId);

            _hostEnd = hostEnd;

            ClientToHostWorker(stdin, hostEnd).DoNotWait();
            HostToClientWorker(stdout, hostEnd).DoNotWait();

            HostToClientErrorWorker(stderror, _process.ProcessId, (int processid, string errdata) => {
                outputLogger?.LogTrace(Resources.Trace_ErrorDataReceived, processid, errdata);
            }).DoNotWait();
        }