Skip to content

Commit

Permalink
Setup: Don't start the process as administrator.
Browse files Browse the repository at this point in the history
  • Loading branch information
Sewer56 committed Sep 19, 2024
1 parent 1663764 commit b6e2e93
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 125 deletions.
67 changes: 65 additions & 2 deletions source/Reloaded.Mod.Installer/MainWindowViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
using System.IO.Compression;
using System.Net.Http;
using System.Security.Principal;
using Windows.Win32.Security;
using Windows.Win32.System.Threading;
using static Windows.Win32.PInvoke;
using static Reloaded.Mod.Installer.DependencyInstaller.DependencyInstaller;
using MessageBox = System.Windows.MessageBox;
using Path = System.IO.Path;
Expand Down Expand Up @@ -73,9 +77,13 @@ await CheckAndInstallMissingRuntimesAsync(settings.InstallLocation, tempDownload
}

CurrentStepDescription = "All Set";

if (settings.StartReloaded)
Process.Start(executablePath);
{
// We're in an admin process; but we want to de-escalate as Reloaded-II is not
// meant to be used in admin mode.
StartProcessWithReducedPrivileges(executablePath);
}
}
catch (TaskCanceledException)
{
Expand Down Expand Up @@ -136,4 +144,59 @@ private static void ExtractReloaded(string extractFolderPath, string downloadedP
File.Delete(downloadedPackagePath);
slice.Report(1);
}

private static unsafe void StartProcessWithReducedPrivileges(string executablePath)
{
SAFER_LEVEL_HANDLE saferHandle = default;
try
{
// 1. Create a new new access token
if (!SaferCreateLevel(SAFER_SCOPEID_USER, SAFER_LEVELID_NORMALUSER,
SAFER_LEVEL_OPEN, &saferHandle, null))
throw new Win32Exception(Marshal.GetLastWin32Error());

if (!SaferComputeTokenFromLevel(saferHandle, null, out var newAccessToken, 0, null))
throw new Win32Exception(Marshal.GetLastWin32Error());

// Set the token to medium integrity because SaferCreateLevel doesn't reduce the
// integrity level of the token and keep it as high.
if (!ConvertStringSidToSid("S-1-16-8192", out var psid))
throw new Win32Exception(Marshal.GetLastWin32Error());

TOKEN_MANDATORY_LABEL tml = default;
tml.Label.Attributes = SE_GROUP_INTEGRITY;
tml.Label.Sid = (PSID)psid.DangerousGetHandle();

var length = (uint)Marshal.SizeOf(tml);
if (!SetTokenInformation(newAccessToken, TOKEN_INFORMATION_CLASS.TokenIntegrityLevel, &tml, length))
throw new Win32Exception(Marshal.GetLastWin32Error());

// 2. Start process using the new access token
// Cannot use Process.Start as there is no way to set the access token to use
fixed (char* commandLinePtr = executablePath)
{
STARTUPINFOW si = default;
Span<char> span = new Span<char>(commandLinePtr, executablePath.Length);
if (CreateProcessAsUser(newAccessToken, null, ref span, null, null, bInheritHandles: false, default,
null, null, in si, out var pi))
{
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
}

}
catch
{
// In case of WINE, or some other unexpected event.
Process.Start(executablePath);
}
finally
{
if (saferHandle != default)
{
SaferCloseLevel(saferHandle);
}
}
}
}
12 changes: 12 additions & 0 deletions source/Reloaded.Mod.Installer/NativeMethods.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
SaferCreateLevel
SaferComputeTokenFromLevel
SaferCloseLevel
SAFER_SCOPEID_*
SAFER_LEVELID_*
SAFER_LEVEL_*
CreateProcessAsUser
TOKEN_MANDATORY_LABEL
SE_GROUP_INTEGRITY
ConvertStringSidToSid
SetTokenInformation
LocalFree
8 changes: 6 additions & 2 deletions source/Reloaded.Mod.Installer/Reloaded.Mod.Installer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
<PropertyGroup>
<WeaverConfiguration>
<Weavers>
<Costura IncludeDebugSymbols='false' Condition="'$(TargetFramework)' == 'net472'" />
<PropertyChanged/>
<Costura IncludeDebugSymbols="false" Condition="'$(TargetFramework)' == 'net472'" />
<PropertyChanged />
</Weavers>
</WeaverConfiguration>
</PropertyGroup>
Expand All @@ -35,6 +35,10 @@
<IncludeAssets>runtime; compile; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="HandyControl" Version="3.2.0" />
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.106">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="PropertyChanged.Fody" Version="3.4.1">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
Expand Down
108 changes: 0 additions & 108 deletions source/Reloaded.Mod.Installer/Utilities/IOEx.cs
Original file line number Diff line number Diff line change
@@ -1,98 +1,8 @@
using Path = System.IO.Path;

namespace Reloaded.Mod.Installer.Utilities
{
// ReSharper disable once InconsistentNaming
public static class IOEx
{
/// <summary>
/// Moves a directory from a given source path to a target path, overwriting all files.
/// </summary>
/// <param name="source">The source path.</param>
/// <param name="target">The target path.</param>
public static void MoveDirectory(string source, string target)
{
MoveDirectory(source, target, (x, y) =>
{
File.Copy(x, y, true);
File.Delete(x);
});
}

/// <summary>
/// Copies a directory from a given source path to a target path, overwriting all files.
/// </summary>
/// <param name="source">The source path.</param>
/// <param name="target">The target path.</param>
public static void CopyDirectory(string source, string target)
{
MoveDirectory(source, target, (x, y) => File.Copy(x, y, true));
}

private static void MoveDirectory(string source, string target, Action<string, string> moveDirectoryAction)
{
Directory.CreateDirectory(target);

// Get all files in source directory.
var sourceFilePaths = Directory.EnumerateFiles(source);

// Move them.
foreach (var sourceFilePath in sourceFilePaths)
{
// Get destination file path
var destFileName = Path.GetFileName(sourceFilePath);
var destFilePath = Path.Combine(target, destFileName);

while (File.Exists(destFilePath) && !CheckFileAccess(destFilePath, FileMode.Open, FileAccess.Write))
Thread.Sleep(100);

if (File.Exists(destFilePath))
File.Delete(destFilePath);

moveDirectoryAction(sourceFilePath, destFilePath);
}

// Get all subdirectories in source directory.
var sourceSubDirPaths = Directory.EnumerateDirectories(source);

// Recursively move them.
foreach (var sourceSubDirPath in sourceSubDirPaths)
{
var destSubDirName = Path.GetFileName(sourceSubDirPath);
var destSubDirPath = Path.Combine(target, destSubDirName);
MoveDirectory(sourceSubDirPath, destSubDirPath, moveDirectoryAction);
}
}

/// <summary>
/// Tries to open a stream for a specified file.
/// Returns null if it fails due to file lock.
/// </summary>
public static FileStream? TryOpenOrCreateFileStream(string filePath, FileMode mode = FileMode.OpenOrCreate, FileAccess access = FileAccess.ReadWrite)
{
try
{
return File.Open(filePath, mode, access);
}
catch (UnauthorizedAccessException)
{
return null;
}
catch (IOException)
{
return null;
}
}

/// <summary>
/// Checks whether a file with a specific path can be opened.
/// </summary>
public static bool CheckFileAccess(string filePath, FileMode mode = FileMode.Open, FileAccess access = FileAccess.ReadWrite)
{
using var stream = TryOpenOrCreateFileStream(filePath, mode, access);
return stream != null;
}

/// <summary>
/// Tries to delete a directory, if possible.
/// </summary>
Expand All @@ -101,23 +11,5 @@ public static void TryDeleteDirectory(string path, bool recursive = true)
try { Directory.Delete(path, recursive); }
catch (Exception) { /* Ignored */ }
}

/// <summary>
/// Tries to delete a directory, if possible.
/// </summary>
public static void TryDeleteFile(string path)
{
try { File.Delete(path); }
catch (Exception) { /* Ignored */ }
}

/// <summary>
/// Tries to empty a directory, if possible.
/// </summary>
public static void TryEmptyDirectory(string path)
{
TryDeleteDirectory(path, true);
Directory.CreateDirectory(path);
}
}
}
7 changes: 0 additions & 7 deletions source/Reloaded.Mod.Installer/Utilities/Native.cs

This file was deleted.

6 changes: 0 additions & 6 deletions source/Reloaded.Mod.Installer/Utilities/ObservableObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,4 @@ namespace Reloaded.Mod.Installer.Utilities;
public abstract class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;

protected void RaisePropertyChangedEvent(string propertyName)
{
var handler = PropertyChanged;
handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

0 comments on commit b6e2e93

Please sign in to comment.