Skip to content

Commit

Permalink
- Accept --chdir {directory} or uppercase -D {directory} argument…
Browse files Browse the repository at this point in the history
… for compat with MS-SUDO.

- Included new ms-sudo compatible options aliases (`--preserve-env`, `--new-window`).
  • Loading branch information
gerardog committed May 26, 2024
1 parent 66f67b4 commit 6ebb465
Show file tree
Hide file tree
Showing 6 changed files with 30 additions and 4 deletions.
4 changes: 2 additions & 2 deletions src/gsudo/Commands/RunCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public async Task<int> Execute()
if (isElevationRequired & SecurityHelper.GetCurrentIntegrityLevel() < (int)IntegrityLevel.Medium)
throw new ApplicationException("Sorry, gsudo doesn't allow to elevate from low integrity level."); // This message is not a security feature, but a nicer error message. It would have failed anyway since the named pipe's ACL restricts it.

if (isRunningAsDesiredUser && isShellElevation && !InputArguments.NewWindow)
if (isRunningAsDesiredUser && isShellElevation && !InputArguments.NewWindow && !InputArguments.Direct && InputArguments.StartingDirectory == null)
throw new ApplicationException("Already running as the specified user/permission-level (and no command specified). Exiting...");

var elevationMode = GetElevationMode();
Expand All @@ -58,7 +58,7 @@ public async Task<int> Execute()
{
FileName = commandBuilder.GetExeName(),
Arguments = commandBuilder.GetArgumentsAsString(),
StartFolder = Environment.CurrentDirectory,
StartFolder = InputArguments.StartingDirectory ?? Environment.CurrentDirectory,
NewWindow = InputArguments.NewWindow,
Wait = (!commandBuilder.IsWindowsApp && !InputArguments.NewWindow) || InputArguments.Wait,
Mode = elevationMode,
Expand Down
12 changes: 11 additions & 1 deletion src/gsudo/Helpers/CommandLineParser.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using gsudo.AppSettings;
using gsudo.Commands;
using gsudo.Native;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Security.Principal;

Expand Down Expand Up @@ -132,7 +134,6 @@ ICommand ParseOption(string argChar, string argWord, out bool skipRemainingChars
else if (match(null, "--close")) { InputArguments.CloseNewWindow = true; InputArguments.KeepWindowOpen = false; InputArguments.KeepShellOpen = false; }

else if (match("s", "--system")) { InputArguments.RunAsSystem = true; }
else if (match("d", "--direct")) { InputArguments.Direct = true; }
else if (match("k", "--reset-timestamp")) { InputArguments.KillCache = true; }
else if (match(null, "--global")) { InputArguments.Global = true; }
else if (match(null, "--ti")) { InputArguments.TrustedInstaller = InputArguments.RunAsSystem = true; }
Expand All @@ -145,6 +146,15 @@ ICommand ParseOption(string argChar, string argWord, out bool skipRemainingChars
else if (match(null, "--debug")) { Settings.LogLevel.Value = LogLevel.All; InputArguments.Debug = true; }
else if (match("v", "--version")) { return new ShowVersionHelpCommand(); }
else if (match("h", "--help")) return new HelpCommand();

// ms-sudo compat:
else if (match(null, "--preserve-env")) { Settings.CopyEnvironmentVariables.Value = true; }
else if (match(null, "--new-window")) { InputArguments.NewWindow = true; }
else if (argChar == "D" && argWord == "-D" && FileApi.PathExists(args.FirstOrDefault())) { InputArguments.StartingDirectory = DeQueueArg(); }
else if (match(null, "--chdir")) { InputArguments.StartingDirectory = DeQueueArg(); }

// rest
else if (match("d", "--direct")) { InputArguments.Direct = true; }
else if (argWord.StartsWith("-", StringComparison.Ordinal))
{
if (argChar != null)
Expand Down
3 changes: 3 additions & 0 deletions src/gsudo/InputParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ public static class InputArguments
// SID of User to Impersonate
public static string UserSid { get; private set; }

// Starting Directory for the new process
public static string StartingDirectory { get; internal set; }

public static IntegrityLevel GetIntegrityLevel() => (RunAsSystem ? gsudo.IntegrityLevel.System : IntegrityLevel ?? gsudo.IntegrityLevel.High);

internal static void Clear() // added for tests repeatability
Expand Down
3 changes: 3 additions & 0 deletions src/gsudo/Native/FileApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ public struct WIN32_FIND_DATA
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool FindClose(IntPtr hFindFile);

[DllImport("shlwapi", EntryPoint = "PathFileExists", CharSet = CharSet.Unicode)]
public static extern bool PathExists(string path);

#endregion

#region Network Drives
Expand Down
2 changes: 1 addition & 1 deletion src/gsudo/ProcessHosts/AttachedConsoleHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public async Task Start(Connection connection, ElevationRequest elevationRequest
}
catch (UnauthorizedAccessException ex)
{
throw new ApplicationException($"User \"{WindowsIdentity.GetCurrent().Name}\" can not access current directory \"{elevationRequest.StartFolder}\"");
throw new ApplicationException($"User \"{WindowsIdentity.GetCurrent().Name}\" can not access directory \"{elevationRequest.StartFolder}\"");
}

var process = Helpers.ProcessFactory.StartAttached(elevationRequest.FileName, elevationRequest.Arguments);
Expand Down
10 changes: 10 additions & 0 deletions src/gsudo/ProcessRenderers/TokenSwitchRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Threading;
using System.Threading.Tasks;

Expand Down Expand Up @@ -55,6 +56,15 @@ internal TokenSwitchRenderer(Connection connection, ElevationRequest elevationRe
// Hack not needed if we are already calling CMD
exeName = elevationRequest.FileName;
args = elevationRequest.Arguments;
}

try
{
System.Environment.CurrentDirectory = elevationRequest.StartFolder;
}
catch (UnauthorizedAccessException ex)
{
throw new ApplicationException($"User \"{WindowsIdentity.GetCurrent().Name}\" can not access directory \"{elevationRequest.StartFolder}\"");
}

ProcessFactory.CreateProcessForTokenReplacement(exeName, args, dwCreationFlags, out _processHandle, out _threadHandle, out int processId);
Expand Down

0 comments on commit 6ebb465

Please sign in to comment.