Skip to content

Commit

Permalink
Redirect I/O of elevated process
Browse files Browse the repository at this point in the history
  • Loading branch information
nxtn committed Nov 15, 2020
1 parent d832e5c commit d0c969d
Showing 1 changed file with 87 additions and 33 deletions.
120 changes: 87 additions & 33 deletions src/WinSW/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
Expand All @@ -33,6 +34,8 @@ namespace WinSW
// NOTE: Keep description strings in sync with docs.
public static class Program
{
private const string NoPipe = "-";

private static readonly ILog Log = LogManager.GetLogger(typeof(Program));

internal static Action<Exception, InvocationContext>? TestExceptionHandler;
Expand Down Expand Up @@ -63,13 +66,37 @@ internal static int Main(string[] args)
_ = ConsoleApis.FreeConsole();
_ = ConsoleApis.AttachConsole(ConsoleApis.ATTACH_PARENT_PROCESS);

string stdinName = args[1];
if (stdinName != NoPipe)
{
var stdin = new NamedPipeClientStream(".", stdinName, PipeDirection.In, PipeOptions.Asynchronous);
stdin.Connect();
Console.SetIn(new StreamReader(stdin));
}

string stdoutName = args[2];
if (stdoutName != NoPipe)
{
var stdout = new NamedPipeClientStream(".", stdoutName, PipeDirection.Out, PipeOptions.Asynchronous);
stdout.Connect();
Console.SetOut(new StreamWriter(stdout) { AutoFlush = true });
}

string stderrName = args[3];
if (stderrName != NoPipe)
{
var stderr = new NamedPipeClientStream(".", stderrName, PipeDirection.Out, PipeOptions.Asynchronous);
stderr.Connect();
Console.SetError(new StreamWriter(stderr) { AutoFlush = true });
}

#if NETCOREAPP
args = args[1..];
args = args[4..];
#else
string[] oldArgs = args;
int newLength = oldArgs.Length - 1;
int newLength = oldArgs.Length - 4;
args = new string[newLength];
Array.Copy(oldArgs, 1, args, 0, newLength);
Array.Copy(oldArgs, 4, args, 0, newLength);
#endif
}
else if (Environment.OSVersion.Version.Major == 5)
Expand Down Expand Up @@ -767,10 +794,13 @@ void RestartSelf(string? pathToConfig)
IntPtr.Zero,
null,
default,
out _))
out ProcessApis.PROCESS_INFORMATION processInfo))
{
Throw.Command.Win32Exception("Failed to invoke restart.");
}

_ = HandleApis.CloseHandle(processInfo.ProcessHandle);
_ = HandleApis.CloseHandle(processInfo.ThreadHandle);
}

static int Status(string? pathToConfig)
Expand Down Expand Up @@ -906,15 +936,15 @@ static unsafe void DevPs(string? pathToConfig, bool all)
}
}
else
{
XmlServiceConfig config = LoadConfig(pathToConfig);
{
XmlServiceConfig config = LoadConfig(pathToConfig);

using ServiceManager scm = ServiceManager.Open(ServiceManagerAccess.Connect);
using Service sc = scm.OpenService(config.Name, ServiceAccess.QueryStatus);
using ServiceManager scm = ServiceManager.Open(ServiceManagerAccess.Connect);
using Service sc = scm.OpenService(config.Name, ServiceAccess.QueryStatus);

int processId = sc.ProcessId;
if (processId >= 0)
{
int processId = sc.ProcessId;
if (processId >= 0)
{
using Process process = Process.GetProcessById(processId);
Draw(process, string.Empty, true);
}
Expand All @@ -927,30 +957,30 @@ static void Draw(Process process, string indentation, bool isLastChild)
const string Cross = " \u251c\u2500";
const string Space = " ";

Console.Write(indentation);
Console.Write(indentation);

if (isLastChild)
{
Console.Write(Corner);
indentation += Space;
}
else
{
Console.Write(Cross);
indentation += Vertical;
}
if (isLastChild)
{
Console.Write(Corner);
indentation += Space;
}
else
{
Console.Write(Cross);
indentation += Vertical;
}

Console.WriteLine(process.Format());
Console.WriteLine(process.Format());

List<Process> children = process.GetChildren();
int count = children.Count;
for (int i = 0; i < count; i++)
{
using Process child = children[i];
Draw(child, indentation, i == count - 1);
}
List<Process> children = process.GetChildren();
int count = children.Count;
for (int i = 0; i < count; i++)
{
using Process child = children[i];
Draw(child, indentation, i == count - 1);
}
}
}

void DevKill(string? pathToConfig, bool noElevate)
{
Expand Down Expand Up @@ -1016,17 +1046,23 @@ static void Elevate(bool noElevate)
Throw.Command.Win32Exception(Errors.ERROR_ACCESS_DENIED);
}

using Process current = Process.GetCurrentProcess();
string? stdinName = Console.IsInputRedirected ? Guid.NewGuid().ToString() : null;
string? stdoutName = Console.IsOutputRedirected ? Guid.NewGuid().ToString() : null;
string? stderrName = Console.IsErrorRedirected ? Guid.NewGuid().ToString() : null;

string exe = Environment.GetCommandLineArgs()[0];
string commandLine = Environment.CommandLine;
string arguments = "--elevated" + commandLine.Remove(commandLine.IndexOf(exe), exe.Length).TrimStart('"');
string arguments = "--elevated" +
" " + (stdinName ?? NoPipe) +
" " + (stdoutName ?? NoPipe) +
" " + (stderrName ?? NoPipe) +
commandLine.Remove(commandLine.IndexOf(exe), exe.Length).TrimStart('"');

ProcessStartInfo startInfo = new ProcessStartInfo
{
UseShellExecute = true,
Verb = "runas",
FileName = current.MainModule!.FileName!,
FileName = ExecutablePath,
Arguments = arguments,
WindowStyle = ProcessWindowStyle.Hidden,
};
Expand All @@ -1035,6 +1071,24 @@ static void Elevate(bool noElevate)
{
using Process elevated = Process.Start(startInfo)!;

if (stdinName is not null)
{
var stdin = new NamedPipeServerStream(stdinName, PipeDirection.Out, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
stdin.WaitForConnectionAsync().ContinueWith(_ => Console.OpenStandardInput().CopyToAsync(stdin));
}

if (stdoutName is not null)
{
var stdout = new NamedPipeServerStream(stdoutName, PipeDirection.In, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
stdout.WaitForConnectionAsync().ContinueWith(_ => stdout.CopyToAsync(Console.OpenStandardOutput()));
}

if (stderrName is not null)
{
var stderr = new NamedPipeServerStream(stderrName, PipeDirection.In, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
stderr.WaitForConnectionAsync().ContinueWith(_ => stderr.CopyToAsync(Console.OpenStandardError()));
}

elevated.WaitForExit();
Environment.Exit(elevated.ExitCode);
}
Expand Down

0 comments on commit d0c969d

Please sign in to comment.