Skip to content

Commit

Permalink
Migration to use CsWin32 PInvoke code generator, Part 2
Browse files Browse the repository at this point in the history
  • Loading branch information
gerardog committed Mar 6, 2024
1 parent 0ff826d commit cf5b4f9
Show file tree
Hide file tree
Showing 8 changed files with 62 additions and 168 deletions.
30 changes: 16 additions & 14 deletions src/gsudo/Helpers/ConsoleHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,46 +53,48 @@ private static BOOL IgnoreConsoleCancelKeyPressMethod(uint ctrlType)

public static uint[] GetConsoleAttachedPids()
{
var processIds = new uint[1];
var num = ConsoleApi.GetConsoleProcessList(processIds, 1);
var processIds = new uint[1].AsSpan();
var num = PInvoke.GetConsoleProcessList(processIds);
if (num == 0) throw new System.ComponentModel.Win32Exception();

processIds = new uint[num];
processIds = new uint[num].AsSpan();

num = ConsoleApi.GetConsoleProcessList(processIds, num);
num = PInvoke.GetConsoleProcessList(processIds);
if (num == 0) throw new System.ComponentModel.Win32Exception();

//** weird workaround for .net 7.0 NativeAOT + git-bash **
if (processIds[0] == 0)
num = ConsoleApi.GetConsoleProcessList(processIds, num);
num = PInvoke.GetConsoleProcessList(processIds);
if (processIds[0] == 0)
num = ConsoleApi.GetConsoleProcessList(processIds, num);
num = PInvoke.GetConsoleProcessList(processIds);
//**************************************************
return processIds;
return processIds.ToArray();
}

public static void GetConsoleInfo(out int width, out int height, out int cursorLeftPos, out int cursorTopPos)
{
if (Console.IsOutputRedirected && Console.IsErrorRedirected)
{
var hConsole = Native.FileApi.CreateFile("CONOUT$",
FileApi.GENERIC_READ, 0, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero);
var hConsole = PInvoke.CreateFile("CONOUT$", FileApi.GENERIC_READ,
Windows.Win32.Storage.FileSystem.FILE_SHARE_MODE.FILE_SHARE_NONE, null,
Windows.Win32.Storage.FileSystem.FILE_CREATION_DISPOSITION.OPEN_EXISTING,
0, null);

if (hConsole == Native.FileApi.INVALID_HANDLE_VALUE)
if (hConsole.IsInvalid)
throw new System.ComponentModel.Win32Exception();

var consoleScreenBufferInfoEx = new CONSOLE_SCREEN_BUFFER_INFO_EX();
consoleScreenBufferInfoEx.cbSize = Marshal.SizeOf<CONSOLE_SCREEN_BUFFER_INFO_EX>();
var consoleScreenBufferInfoEx = new CONSOLE_SCREEN_BUFFER_INFOEX();
consoleScreenBufferInfoEx.cbSize = (uint)Marshal.SizeOf<CONSOLE_SCREEN_BUFFER_INFOEX>();

if (!GetConsoleScreenBufferInfoEx(hConsole, ref consoleScreenBufferInfoEx))
if (!PInvoke.GetConsoleScreenBufferInfoEx(hConsole, ref consoleScreenBufferInfoEx))
throw new System.ComponentModel.Win32Exception();

width = consoleScreenBufferInfoEx.srWindow.Right - consoleScreenBufferInfoEx.srWindow.Left + 1;
height = consoleScreenBufferInfoEx.srWindow.Bottom - consoleScreenBufferInfoEx.srWindow.Top + 1;
cursorLeftPos = consoleScreenBufferInfoEx.dwCursorPosition.X;
cursorTopPos = consoleScreenBufferInfoEx.dwCursorPosition.Y;

FileApi.CloseHandle(hConsole);
hConsole.Close();
}
else
{
Expand Down
49 changes: 26 additions & 23 deletions src/gsudo/Helpers/SymbolicLinkSupport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;

using Windows.Win32;

namespace gsudo.Helpers
{
static class SymbolicLinkSupport
Expand Down Expand Up @@ -48,33 +49,35 @@ public static string ResolveSymbolicLink(string symLinkFullPath)
}
private static string GetFinalPathName(string path)
{
var h = Native.FileApi.CreateFile(path,
using (var h = PInvoke.CreateFile(path,
Native.FileApi.FILE_READ_EA,
FileShare.ReadWrite | FileShare.Delete,
IntPtr.Zero,
FileMode.Open,
Native.FileApi.FILE_FLAG_BACKUP_SEMANTICS,
IntPtr.Zero);
Windows.Win32.Storage.FileSystem.FILE_SHARE_MODE.FILE_SHARE_READ | Windows.Win32.Storage.FileSystem.FILE_SHARE_MODE.FILE_SHARE_WRITE | Windows.Win32.Storage.FileSystem.FILE_SHARE_MODE.FILE_SHARE_DELETE,
null,
Windows.Win32.Storage.FileSystem.FILE_CREATION_DISPOSITION.OPEN_EXISTING,
Windows.Win32.Storage.FileSystem.FILE_FLAGS_AND_ATTRIBUTES.FILE_FLAG_BACKUP_SEMANTICS,
null))
{
if (h.IsInvalid)
return path;

if (h == Native.FileApi.INVALID_HANDLE_VALUE)
return path;
uint res;

try
{
var sb = new StringBuilder(1024);
var res = Native.FileApi.GetFinalPathNameByHandle(h, sb, 1024, 0);
Span<char> text = stackalloc char[1024]; // value gotten from GetWindowTextLength
unsafe
{
fixed (char* pText = text)
{
res = PInvoke.GetFinalPathNameByHandle(h, pText, 1024, 0);
}

if (res == 0)
{
Logger.Instance.Log($"{nameof(SymbolicLinkSupport)}.{nameof(GetFinalPathName)} failed with: {new Win32Exception()}", LogLevel.Debug);
return path; // Sad workaround: do not resolve the symlink.
}
if (res == 0)
{
Logger.Instance.Log($"{nameof(SymbolicLinkSupport)}.{nameof(GetFinalPathName)} failed with: {new Win32Exception()}", LogLevel.Debug);
return path; // Sad workaround: do not resolve the symlink.
}

return sb.ToString();
}
finally
{
Native.FileApi.CloseHandle(h);
return text.Slice(0, (int)res).ToString();
}
}
}
}
Expand Down
78 changes: 0 additions & 78 deletions src/gsudo/Native/ConsoleApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,83 +18,5 @@ internal enum CtrlTypes : uint
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT
}

[DllImport("kernel32.dll", SetLastError = true)]
public static extern uint GetConsoleProcessList(uint[] processList, uint processCount);

/// <summary>
/// Retrieves a handle to the Shell's desktop window.
/// <para>
/// Go to https://msdn.microsoft.com/en-us/library/windows/desktop/ms633512%28v=vs.85%29.aspx for more
/// information
/// </para>
/// </summary>
/// <returns>
/// C++ ( Type: HWND )<br />The return value is the handle of the Shell's desktop window. If no Shell process is
/// present, the return value is NULL.
/// </returns>
[DllImport("user32.dll")]
internal static extern IntPtr GetShellWindow();

[DllImport("user32.dll", SetLastError = true)]
internal static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool GetConsoleScreenBufferInfoEx(
IntPtr hConsoleOutput,
ref CONSOLE_SCREEN_BUFFER_INFO_EX ConsoleScreenBufferInfo
);

[StructLayout(LayoutKind.Sequential)]
public struct CONSOLE_SCREEN_BUFFER_INFO_EX
{
public int cbSize;
public COORD dwSize;
public COORD dwCursorPosition;
public short wAttributes;
public SMALL_RECT srWindow;
public COORD dwMaximumWindowSize;

public ushort wPopupAttributes;
public bool bFullscreenSupported;

internal COLORREF black;
internal COLORREF darkBlue;
internal COLORREF darkGreen;
internal COLORREF darkCyan;
internal COLORREF darkRed;
internal COLORREF darkMagenta;
internal COLORREF darkYellow;
internal COLORREF gray;
internal COLORREF darkGray;
internal COLORREF blue;
internal COLORREF green;
internal COLORREF cyan;
internal COLORREF red;
internal COLORREF magenta;
internal COLORREF yellow;
internal COLORREF white;

// has been a while since I did this, test before use
// but should be something like:
//
// [MarshalAs(UnmanagedType.ByValArray, SizeConst=16)]
// public COLORREF[] ColorTable;
}

[StructLayout(LayoutKind.Sequential)]
public struct COLORREF
{
public uint ColorDWORD;
}
public struct SMALL_RECT
{

public short Left;
public short Top;
public short Right;
public short Bottom;

}
}
}
19 changes: 0 additions & 19 deletions src/gsudo/Native/FileApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,12 @@ namespace gsudo.Native
{
static class FileApi
{
internal static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);

internal const uint FILE_READ_EA = 0x0008;
internal const uint FILE_FLAG_BACKUP_SEMANTICS = 0x2000000;

public const uint GENERIC_READ = (0x80000000);
public const uint GENERIC_WRITE = (0x40000000);

[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern uint GetFinalPathNameByHandle(IntPtr hFile, StringBuilder lpszFilePath, uint cchFilePath, uint dwFlags);

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool CloseHandle(IntPtr hObject);

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern IntPtr CreateFile(
[MarshalAs(UnmanagedType.LPWStr)] string filename,
[MarshalAs(UnmanagedType.U4)] uint access,
[MarshalAs(UnmanagedType.U4)] FileShare share,
IntPtr securityAttributes, // optional SECURITY_ATTRIBUTES struct or IntPtr.Zero
[MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
[MarshalAs(UnmanagedType.U4)] uint flagsAndAttributes,
IntPtr templateFile);

#region IsWindowsApp Win32 Api
[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
internal static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbFileInfo, uint uFlags);
Expand Down
26 changes: 0 additions & 26 deletions src/gsudo/Native/NativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,32 +43,6 @@ internal static partial class NativeMethods
TOKEN_ADJUST_DEFAULT |
TOKEN_ADJUST_SESSIONID;

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern IntPtr GetCurrentProcess();

[DllImport("Advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool OpenProcessToken(IntPtr processHandle,
uint desiredAccesss,
out IntPtr tokenHandle);

[DllImport("Advapi32.dll", SetLastError = true)]
internal static extern bool OpenThreadToken(IntPtr ThreadToken, TokenAccessLevels DesiredAccess, bool OpenAsSelf, out SafeTokenHandle TokenHandle);

[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr GetCurrentThread();

[DllImport("Advapi32.dll", SetLastError = true)]
public static extern bool SetThreadToken(IntPtr Thread, SafeTokenHandle Token);


[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool CloseHandle(IntPtr hObject);

[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool GetKernelObjectSecurity(IntPtr Handle, uint securityInformation, IntPtr pSecurityDescriptor, uint nLength, out uint lpnLengthNeeded);

[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool SetKernelObjectSecurity(IntPtr Handle, uint securityInformation, IntPtr pSecurityDescriptor);

Expand Down
11 changes: 9 additions & 2 deletions src/gsudo/NativeMethods.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,19 @@ GetConsoleMode

AttachConsole
FreeConsole
#AllocConsole
AllocConsole

// Ctr-C Handling
SetConsoleCtrlHandler
GenerateConsoleCtrlEvent

GetCommandLine
// GetConsoleProcessList => Unable to migrate for net46
GetConsoleProcessList
GetConsoleScreenBufferInfoEx

GetShellWindow
GetWindowThreadProcessId

CreateFile
GetFinalPathNameByHandle
GetWindowText
7 changes: 5 additions & 2 deletions src/gsudo/ProcessHosts/AttachedConsoleHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ namespace gsudo.ProcessHosts
// This mode is not enabled unless you use --attached.
class AttachedConsoleHost : IProcessHost
{
public bool SupportsSimultaneousElevations { get; } = false;
public bool SupportsSimultaneousElevations { get; } = true;

public async Task Start(Connection connection, ElevationRequest elevationRequest)
{
Expand Down Expand Up @@ -46,6 +46,9 @@ public async Task Start(Connection connection, ElevationRequest elevationRequest

var process = Helpers.ProcessFactory.StartAttached(elevationRequest.FileName, elevationRequest.Arguments);

PInvoke.FreeConsole();
PInvoke.AllocConsole();

WaitHandle.WaitAny(new WaitHandle[] { process.GetProcessWaitHandle(), connection.DisconnectedWaitHandle });
if (process.HasExited)
exitCode = process.ExitCode;
Expand Down Expand Up @@ -81,7 +84,7 @@ public async Task Start(Connection connection, ElevationRequest elevationRequest
finally
{
PInvoke.SetConsoleCtrlHandler(ConsoleHelper.IgnoreConsoleCancelKeyPress, false);
PInvoke.FreeConsole();
//PInvoke.FreeConsole();
await connection.FlushAndCloseAll().ConfigureAwait(false);
}
}
Expand Down
10 changes: 6 additions & 4 deletions src/gsudo/Tokens/TokenProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
using System.Linq;
using System.Security.Principal;
using gsudo.Helpers;

using Windows.Win32;

namespace gsudo.Tokens
{
internal class TokenProvider : IDisposable
Expand Down Expand Up @@ -204,7 +205,7 @@ public TokenProvider GetLinkedToken(uint desiredAccess = MAXIMUM_ALLOWED)
return this;
}

internal static TokenProvider CreateUnelevated(IntegrityLevel level)
internal static unsafe TokenProvider CreateUnelevated(IntegrityLevel level)
{
if (SecurityHelper.IsAdministrator())
{
Expand All @@ -231,8 +232,9 @@ internal static TokenProvider CreateUnelevated(IntegrityLevel level)
}
else
{
IntPtr hwnd = ConsoleApi.GetShellWindow();
_ = ConsoleApi.GetWindowThreadProcessId(hwnd, out uint pid);
var hwnd = PInvoke.GetShellWindow();
uint pid;
_ = PInvoke.GetWindowThreadProcessId(hwnd, &pid);
return TokenProvider.CreateFromProcessToken((int) pid);
}
}
Expand Down

0 comments on commit cf5b4f9

Please sign in to comment.