Skip to content

Commit

Permalink
[Peek]Create Setting to run not elevated (microsoft#26308)
Browse files Browse the repository at this point in the history
* [Peek]Create Setting to run not elevated

* Optionally add access permissions to the handles
  • Loading branch information
jaimecbernardo authored and BLM16 committed Jun 22, 2023
1 parent c0ceeda commit c2fac8d
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 23 deletions.
4 changes: 2 additions & 2 deletions src/common/utils/elevation.h
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ struct ProcessInfo
DWORD processID = {};
};

inline std::optional<ProcessInfo> RunNonElevatedFailsafe(const std::wstring& file, const std::wstring& params, const std::wstring& working_dir)
inline std::optional<ProcessInfo> RunNonElevatedFailsafe(const std::wstring& file, const std::wstring& params, const std::wstring& working_dir, DWORD handleAccess = 0)
{
bool launched = RunNonElevatedEx(file, params, working_dir);
if (!launched)
Expand All @@ -373,7 +373,7 @@ inline std::optional<ProcessInfo> RunNonElevatedFailsafe(const std::wstring& fil
}
}

auto handles = getProcessHandlesByName(std::filesystem::path{ file }.filename().wstring(), PROCESS_QUERY_INFORMATION | SYNCHRONIZE);
auto handles = getProcessHandlesByName(std::filesystem::path{ file }.filename().wstring(), PROCESS_QUERY_INFORMATION | SYNCHRONIZE | handleAccess );

if (handles.empty())
return std::nullopt;
Expand Down
87 changes: 66 additions & 21 deletions src/modules/peek/peek/dllmain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <atlbase.h>
#include <exdisp.h>
#include <comdef.h>
#include <common/utils/elevation.h>

extern "C" IMAGE_DOS_HEADER __ImageBase;

Expand Down Expand Up @@ -40,6 +41,7 @@ namespace
const wchar_t JSON_KEY_SHIFT[] = L"shift";
const wchar_t JSON_KEY_CODE[] = L"code";
const wchar_t JSON_KEY_ACTIVATION_SHORTCUT[] = L"ActivationShortcut";
const wchar_t JSON_KEY_ALWAYS_RUN_NOT_ELEVATED[] = L"AlwaysRunNotElevated";
}

// The PowerToy name that will be shown in the settings.
Expand All @@ -56,7 +58,10 @@ class Peek : public PowertoyModuleIface

Hotkey m_hotkey;

HANDLE m_hProcess;
// If we should always try to run Peek non-elevated.
bool m_alwaysRunNotElevated = true;

HANDLE m_hProcess = 0;

HANDLE m_hInvokeEvent;

Expand Down Expand Up @@ -89,22 +94,32 @@ class Peek : public PowertoyModuleIface
}
catch (...)
{
Logger::error("Failed to initialize Peek start settings");
Logger::error("Failed to initialize Peek hotkey settings");

set_default_key_settings();
}
try
{
auto jsonAlwaysRunNotElevatedObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_ALWAYS_RUN_NOT_ELEVATED);
m_alwaysRunNotElevated = jsonAlwaysRunNotElevatedObject.GetNamedBoolean(L"value");
}
catch (...)
{
Logger::error("Failed to initialize Always Run Not Elevated option. Setting to default.");

set_default_settings();
m_alwaysRunNotElevated = true;
}
}
else
{
Logger::info("Peek settings are empty");

set_default_settings();
set_default_key_settings();
}
}

void set_default_settings()
void set_default_key_settings()
{
Logger::info("Peek is going to use default settings");
Logger::info("Peek is going to use default key settings");
m_hotkey.win = false;
m_hotkey.alt = false;
m_hotkey.shift = false;
Expand Down Expand Up @@ -236,6 +251,10 @@ class Peek : public PowertoyModuleIface

bool is_viewer_running()
{
if (m_hProcess == 0)
{
return false;
}
return WaitForSingleObject(m_hProcess, 0) == WAIT_TIMEOUT;
}

Expand All @@ -248,24 +267,43 @@ class Peek : public PowertoyModuleIface
std::wstring executable_args = L"";
executable_args.append(std::to_wstring(powertoys_pid));

SHELLEXECUTEINFOW sei{ sizeof(sei) };

sei.fMask = { SEE_MASK_NOCLOSEPROCESS };
sei.lpVerb = L"open";
sei.lpFile = L"modules\\Peek\\Powertoys.Peek.UI.exe";
sei.nShow = SW_SHOWNORMAL;
sei.lpParameters = executable_args.data();

if (ShellExecuteExW(&sei))
if (m_alwaysRunNotElevated && is_process_elevated(false))
{
Logger::trace("Successfully started the PeekViewer process");
Logger::trace("Starting Peek non elevated from elevated process");
const auto modulePath = get_module_folderpath();
std::wstring runExecutablePath = modulePath;
runExecutablePath += L"\\modules\\Peek\\PowerToys.Peek.UI.exe";
std::optional<ProcessInfo> processStartedInfo = RunNonElevatedFailsafe(runExecutablePath, executable_args, modulePath, PROCESS_QUERY_INFORMATION | SYNCHRONIZE | PROCESS_TERMINATE);
if (processStartedInfo.has_value())
{
m_hProcess = processStartedInfo.value().processHandle.release();
}
else
{
Logger::error(L"PeekViewer failed to start not elevated.");
}
}
else
{
Logger::error(L"PeekViewer failed to start. {}", get_last_error_or_default(GetLastError()));
}
SHELLEXECUTEINFOW sei{ sizeof(sei) };

sei.fMask = { SEE_MASK_NOCLOSEPROCESS };
sei.lpVerb = L"open";
sei.lpFile = L"modules\\Peek\\PowerToys.Peek.UI.exe";
sei.nShow = SW_SHOWNORMAL;
sei.lpParameters = executable_args.data();

if (ShellExecuteExW(&sei))
{
Logger::trace("Successfully started the PeekViewer process");
}
else
{
Logger::error(L"PeekViewer failed to start. {}", get_last_error_or_default(GetLastError()));
}

m_hProcess = sei.hProcess;
m_hProcess = sei.hProcess;
}
}

public:
Expand Down Expand Up @@ -355,7 +393,14 @@ class Peek : public PowertoyModuleIface
if (m_enabled)
{
ResetEvent(m_hInvokeEvent);
TerminateProcess(m_hProcess, 1);
auto result = TerminateProcess(m_hProcess, 1);
if (result == 0)
{
int error = GetLastError();
Logger::trace("Couldn't terminate the process. Last error: {}", error);
}
CloseHandle(m_hProcess);
m_hProcess = 0;
}

m_enabled = false;
Expand Down
2 changes: 2 additions & 0 deletions src/modules/peek/peek/peek.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220914.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220914.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
</ImportGroup>
<Import Project="..\..\..\..\deps\spdlog.props" />
<ImportGroup Label="ExtensionTargets">
Expand All @@ -72,5 +73,6 @@
</PropertyGroup>
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220914.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220914.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
</Target>
</Project>
3 changes: 3 additions & 0 deletions src/settings-ui/Settings.UI.Library/PeekProperties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@ public class PeekProperties
public PeekProperties()
{
ActivationShortcut = new HotkeySettings(false, true, false, false, 0x20);
AlwaysRunNotElevated = new BoolProperty(true);
}

public HotkeySettings ActivationShortcut { get; set; }

public BoolProperty AlwaysRunNotElevated { get; set; }

public override string ToString() => JsonSerializer.Serialize(this);
}
}
10 changes: 10 additions & 0 deletions src/settings-ui/Settings.UI/Strings/en-us/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -2840,6 +2840,16 @@ From there, simply click on one of the supported files in the File Explorer and
<value>Enable Peek</value>
<comment>Peek is a product name, do not loc</comment>
</data>
<data name="Peek_BehaviorHeader.Header" xml:space="preserve">
<value>Behavior</value>
</data>
<data name="Peek_AlwaysRunNotElevated.Header" xml:space="preserve">
<value>Always run not elevated, even when PowerToys is elevated</value>
</data>
<data name="Peek_AlwaysRunNotElevated.Description" xml:space="preserve">
<value>Tries to run Peek without elevated permissions, to fix access to network shares. You need to disable and re-enable Peek for changes to this value to take effect.</value>
<comment>Peek is a product name, do not loc</comment>
</data>
<data name="FancyZones_DisableRoundCornersOnWindowSnap.Content" xml:space="preserve">
<value>Disable round corners when window is snapped</value>
</data>
Expand Down
14 changes: 14 additions & 0 deletions src/settings-ui/Settings.UI/ViewModels/PeekViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,20 @@ public HotkeySettings ActivationShortcut
}
}

public bool AlwaysRunNotElevated
{
get => _peekSettings.Properties.AlwaysRunNotElevated.Value;
set
{
if (_peekSettings.Properties.AlwaysRunNotElevated.Value != value)
{
_peekSettings.Properties.AlwaysRunNotElevated.Value = value;
OnPropertyChanged(nameof(AlwaysRunNotElevated));
NotifySettingsChanged();
}
}
}

private void NotifySettingsChanged()
{
// Using InvariantCulture as this is an IPC message
Expand Down
8 changes: 8 additions & 0 deletions src/settings-ui/Settings.UI/Views/PeekPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@
<controls:ShortcutControl MinWidth="{StaticResource SettingActionControlMinWidth}" HotkeySettings="{x:Bind Path=ViewModel.ActivationShortcut, Mode=TwoWay}" />
</labs:SettingsCard>
</controls:SettingsGroup>
<controls:SettingsGroup x:Uid="Peek_BehaviorHeader" IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled}">
<labs:SettingsCard x:Uid="Peek_AlwaysRunNotElevated" HeaderIcon="{ui:FontIcon FontFamily={StaticResource SymbolThemeFontFamily}, Glyph=&#xE7EF;}">
<ToggleSwitch
x:Uid="ToggleSwitch"
IsOn="{x:Bind Mode=TwoWay, Path=ViewModel.AlwaysRunNotElevated}" />
</labs:SettingsCard>
</controls:SettingsGroup>

</StackPanel>
</controls:SettingsPageControl.ModuleContent>
<controls:SettingsPageControl.PrimaryLinks>
Expand Down

0 comments on commit c2fac8d

Please sign in to comment.