From 1da92fb267ca74fdc9d1e2d3e2e18f2d807aa47c Mon Sep 17 00:00:00 2001 From: Chase Payne Date: Mon, 13 Mar 2023 01:17:24 -0500 Subject: [PATCH 01/15] Adds support for elevating processes that require it. It will retry the command using PowerShell forcing a UAC prompt. --- src/platform/windows/misc.cpp | 56 +++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/platform/windows/misc.cpp b/src/platform/windows/misc.cpp index c89b0f2c412..52f7cf6bc1f 100644 --- a/src/platform/windows/misc.cpp +++ b/src/platform/windows/misc.cpp @@ -23,6 +23,8 @@ #include "src/main.h" #include "src/platform/common.h" #include "src/utility.h" +#include +#include // UDP_SEND_MSG_SIZE was added in the Windows 10 20H1 SDK #ifndef UDP_SEND_MSG_SIZE @@ -464,6 +466,60 @@ bp::child run_unprivileged(const std::string &cmd, boost::filesystem::path &work (LPSTARTUPINFOW)&startup_info, &process_info); + + if(!ret) { + auto error_code = GetLastError(); + // Create a vector to hold the argument tokens + std::vector args; + int argcount; + std::wstring merged_args; + + // Use the CommandLineToArgvW function to tokenize the command string + LPWSTR *argv = CommandLineToArgvW(wcmd.c_str(), &argcount); + if(argv != NULL) { + for(int i = 0; i < argcount; i++) { + args.push_back(argv[i]); + } + + // Free the memory allocated by CommandLineToArgvW + LocalFree(argv); + } + + //loop through the args and merge them into a single string + // Skip first command as it is already included in call_command + for(int i = 1; i < args.size(); i++) { + merged_args.append(L" " + args.at(i) + L" "); + } + + + + // Creates a hidden powershell window to run the command as administrator, waiting for it to finish. This should cause a UAC prompt to appear. + std::wstring call_command = L"powershell.exe -windowstyle hidden -Command \"Start-Process '" + args.at(0) + L"' " + L"-ArgumentList '" + merged_args + L"' -verb runas -Wait\""; + // If the error code is 740, the user does not have permission to run the command. + if(error_code == 740) { + BOOST_LOG(info) << "Start directory: "sv << start_dir; + //log environment block + BOOST_LOG(info) << "Environment block: "sv; + for(int i = 0; i < env_block.size(); i++) { + BOOST_LOG(info) << env_block[i]; + } + + BOOST_LOG(info) << call_command; + BOOST_LOG(info) << "Command failed because it required elevation. Trying again with elevation, this will require user interaction for security reasons."; + ret = CreateProcessAsUserW(shell_token, + NULL, + (LPWSTR)call_command.c_str(), + NULL, + NULL, + !!(startup_info.StartupInfo.dwFlags & STARTF_USESTDHANDLES), + EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE | CREATE_BREAKAWAY_FROM_JOB, + env_block.data(), + start_dir.empty() ? NULL : start_dir.c_str(), + (LPSTARTUPINFOW)&startup_info, + &process_info); + } + } + // End impersonation of the logged on user. If this fails (which is extremely unlikely), // we will be running with an unknown user token. The only safe thing to do in that case // is terminate ourselves. From 8bf2882db24707a5c8f9a9fd77b120433eaad60e Mon Sep 17 00:00:00 2001 From: Chase Payne Date: Mon, 13 Mar 2023 01:30:12 -0500 Subject: [PATCH 02/15] Removing debug code --- src/platform/windows/misc.cpp | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/src/platform/windows/misc.cpp b/src/platform/windows/misc.cpp index 52f7cf6bc1f..5e2a46671eb 100644 --- a/src/platform/windows/misc.cpp +++ b/src/platform/windows/misc.cpp @@ -469,42 +469,31 @@ bp::child run_unprivileged(const std::string &cmd, boost::filesystem::path &work if(!ret) { auto error_code = GetLastError(); + // Create a vector to hold the argument tokens std::vector args; int argcount; std::wstring merged_args; - // Use the CommandLineToArgvW function to tokenize the command string + // need to convert the command line to an array of arguments LPWSTR *argv = CommandLineToArgvW(wcmd.c_str(), &argcount); if(argv != NULL) { for(int i = 0; i < argcount; i++) { args.push_back(argv[i]); } - // Free the memory allocated by CommandLineToArgvW LocalFree(argv); } - //loop through the args and merge them into a single string - // Skip first command as it is already included in call_command + // Skip first argument as it is already included in call_command for(int i = 1; i < args.size(); i++) { merged_args.append(L" " + args.at(i) + L" "); } - - // Creates a hidden powershell window to run the command as administrator, waiting for it to finish. This should cause a UAC prompt to appear. std::wstring call_command = L"powershell.exe -windowstyle hidden -Command \"Start-Process '" + args.at(0) + L"' " + L"-ArgumentList '" + merged_args + L"' -verb runas -Wait\""; // If the error code is 740, the user does not have permission to run the command. if(error_code == 740) { - BOOST_LOG(info) << "Start directory: "sv << start_dir; - //log environment block - BOOST_LOG(info) << "Environment block: "sv; - for(int i = 0; i < env_block.size(); i++) { - BOOST_LOG(info) << env_block[i]; - } - - BOOST_LOG(info) << call_command; BOOST_LOG(info) << "Command failed because it required elevation. Trying again with elevation, this will require user interaction for security reasons."; ret = CreateProcessAsUserW(shell_token, NULL, From 33b7f1f8156f16bd0699d317915061ea6090a41e Mon Sep 17 00:00:00 2001 From: Chase Payne Date: Mon, 13 Mar 2023 01:37:01 -0500 Subject: [PATCH 03/15] Placing code inside IF block now, since it wa previously doing work regardless if 740 or not --- src/platform/windows/misc.cpp | 41 +++++++++++++++++------------------ 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/src/platform/windows/misc.cpp b/src/platform/windows/misc.cpp index 5e2a46671eb..3423bd8a32e 100644 --- a/src/platform/windows/misc.cpp +++ b/src/platform/windows/misc.cpp @@ -470,30 +470,29 @@ bp::child run_unprivileged(const std::string &cmd, boost::filesystem::path &work if(!ret) { auto error_code = GetLastError(); - // Create a vector to hold the argument tokens - std::vector args; - int argcount; - std::wstring merged_args; - - // need to convert the command line to an array of arguments - LPWSTR *argv = CommandLineToArgvW(wcmd.c_str(), &argcount); - if(argv != NULL) { - for(int i = 0; i < argcount; i++) { - args.push_back(argv[i]); - } + // If the error code is 740, the user does not have permission to run the command. + if(error_code == 740) { + std::vector args; + int argcount; + std::wstring merged_args; + + // need to convert the command line to an array of arguments + LPWSTR *argv = CommandLineToArgvW(wcmd.c_str(), &argcount); + if(argv != NULL) { + for(int i = 0; i < argcount; i++) { + args.push_back(argv[i]); + } - LocalFree(argv); - } + LocalFree(argv); + } - // Skip first argument as it is already included in call_command - for(int i = 1; i < args.size(); i++) { - merged_args.append(L" " + args.at(i) + L" "); - } + // Skip first argument as it is already included in call_command + for(int i = 1; i < args.size(); i++) { + merged_args.append(L" " + args.at(i) + L" "); + } - // Creates a hidden powershell window to run the command as administrator, waiting for it to finish. This should cause a UAC prompt to appear. - std::wstring call_command = L"powershell.exe -windowstyle hidden -Command \"Start-Process '" + args.at(0) + L"' " + L"-ArgumentList '" + merged_args + L"' -verb runas -Wait\""; - // If the error code is 740, the user does not have permission to run the command. - if(error_code == 740) { + // Creates a hidden powershell window to run the command as administrator, waiting for it to finish. This should cause a UAC prompt to appear. + std::wstring call_command = L"powershell.exe -windowstyle hidden -Command \"Start-Process '" + args.at(0) + L"' " + L"-ArgumentList '" + merged_args + L"' -verb runas -Wait\""; BOOST_LOG(info) << "Command failed because it required elevation. Trying again with elevation, this will require user interaction for security reasons."; ret = CreateProcessAsUserW(shell_token, NULL, From 65c22a2dd311a6e4044b8871760887363c0cc361 Mon Sep 17 00:00:00 2001 From: Chase Payne Date: Thu, 16 Mar 2023 01:25:16 -0500 Subject: [PATCH 04/15] Updated the code to utilize an elevation tool and added explanation to why a tool needs to be used Powershell is no longer a dependency --- CMakeLists.txt | 8 ++++++- src/platform/windows/misc.cpp | 39 +++++++++++-------------------- tools/CMakeLists.txt | 7 ++++++ tools/elevator.cpp | 44 +++++++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 26 deletions(-) create mode 100644 tools/elevator.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 96a19d51323..f35f03d5e78 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -690,7 +690,8 @@ if(WIN32) # see options at: https://cmake.org/cmake/help/latest/cpack_gen/nsis.h install(TARGETS dxgi-info RUNTIME DESTINATION "tools" COMPONENT dxgi) install(TARGETS audio-info RUNTIME DESTINATION "tools" COMPONENT audio) install(TARGETS sunshinesvc RUNTIME DESTINATION "tools" COMPONENT sunshinesvc) - + install(TARGETS elevator RUNTIME DESTINATION "tools" COMPONENT elevator) + # Mandatory tools install(TARGETS ddprobe RUNTIME DESTINATION "tools" COMPONENT application) @@ -801,6 +802,11 @@ if(WIN32) # see options at: https://cmake.org/cmake/help/latest/cpack_gen/nsis.h set(CPACK_COMPONENT_AUDIO_DESCRIPTION "CLI tool providing information about sound devices.") set(CPACK_COMPONENT_AUDIO_GROUP "tools") + # elevation tool + set(CPACK_COMPONENT_ELEVATION_DISPLAY_NAME "elevator") + set(CPACK_COMPONENT_ELEVATION_DESCRIPTION "CLI tool providing ability to elevate Sunshine in a safe manner when ran as a service.") + set(CPACK_COMPONENT_ELEVATION_GROUP "tools") + # display tool set(CPACK_COMPONENT_DXGI_DISPLAY_NAME "dxgi-info") set(CPACK_COMPONENT_DXGI_DESCRIPTION "CLI tool providing information about graphics cards and displays.") diff --git a/src/platform/windows/misc.cpp b/src/platform/windows/misc.cpp index 3423bd8a32e..7a74d4186c9 100644 --- a/src/platform/windows/misc.cpp +++ b/src/platform/windows/misc.cpp @@ -466,37 +466,26 @@ bp::child run_unprivileged(const std::string &cmd, boost::filesystem::path &work (LPSTARTUPINFOW)&startup_info, &process_info); - if(!ret) { - auto error_code = GetLastError(); - - // If the error code is 740, the user does not have permission to run the command. - if(error_code == 740) { - std::vector args; - int argcount; - std::wstring merged_args; - - // need to convert the command line to an array of arguments - LPWSTR *argv = CommandLineToArgvW(wcmd.c_str(), &argcount); - if(argv != NULL) { - for(int i = 0; i < argcount; i++) { - args.push_back(argv[i]); - } + auto error = GetLastError(); - LocalFree(argv); - } - // Skip first argument as it is already included in call_command - for(int i = 1; i < args.size(); i++) { - merged_args.append(L" " + args.at(i) + L" "); - } + if(error == 740) { + BOOST_LOG(info) << "Could not execute previous command because it required elevation. Running the command again with elevation, for security reasons this will prompt user interaction."sv; + startup_info.StartupInfo.wShowWindow = SW_HIDE; + startup_info.StartupInfo.dwFlags = startup_info.StartupInfo.dwFlags | STARTF_USESHOWWINDOW; + std::wstring elevated_command = L"tools\\elevator.exe "; + elevated_command += wcmd; + + // For security reasons, Windows enforces that an application can only have one "interactive thread," responsible for processing input from the user and managing the user interface (UI). + // Since UAC prompts are interactive, we can't have a UAC prompt while Sunshine is already running because it would block the thread. + // To workaround this, we launch a separate process that will prompt the user for elevation and then launch the actual command. + // It's pretty much a workaround for restriction on Windows. + // Since user has to confirm the UAC prompt, we are retaining a secure method of elevation. - // Creates a hidden powershell window to run the command as administrator, waiting for it to finish. This should cause a UAC prompt to appear. - std::wstring call_command = L"powershell.exe -windowstyle hidden -Command \"Start-Process '" + args.at(0) + L"' " + L"-ArgumentList '" + merged_args + L"' -verb runas -Wait\""; - BOOST_LOG(info) << "Command failed because it required elevation. Trying again with elevation, this will require user interaction for security reasons."; ret = CreateProcessAsUserW(shell_token, NULL, - (LPWSTR)call_command.c_str(), + (LPWSTR)elevated_command.c_str(), NULL, NULL, !!(startup_info.StartupInfo.dwFlags & STARTF_USESTDHANDLES), diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index c2121a7dbea..3d07b33a3b9 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -36,3 +36,10 @@ target_link_libraries(ddprobe d3d11 ${PLATFORM_LIBRARIES}) target_compile_options(ddprobe PRIVATE ${SUNSHINE_COMPILE_OPTIONS}) + +add_executable(elevator elevator.cpp) +set_target_properties(elevator PROPERTIES CXX_STANDARD 17) +target_link_libraries(elevator + shell32 + ${PLATFORM_LIBRARIES}) +target_compile_options(elevator PRIVATE ${SUNSHINE_COMPILE_OPTIONS}) diff --git a/tools/elevator.cpp b/tools/elevator.cpp new file mode 100644 index 00000000000..7e991202bdb --- /dev/null +++ b/tools/elevator.cpp @@ -0,0 +1,44 @@ +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + if(argc < 2) { + std::cout << "Usage: " << argv[0] << " [arguments]" << std::endl; + return 1; + } + + std::wstring command = std::wstring(argv[1], argv[1] + strlen(argv[1])); + std::wstring arguments; + + for(int i = 2; i < argc; ++i) { + arguments += std::wstring(argv[i], argv[i] + strlen(argv[i])); + if(i < argc - 1) { + arguments += L" "; + } + } + + SHELLEXECUTEINFOW info = { sizeof(SHELLEXECUTEINFOW) }; + info.lpVerb = L"runas"; + info.lpFile = command.c_str(); + info.lpParameters = arguments.empty() ? NULL : arguments.c_str(); + info.nShow = SW_SHOW; + info.fMask = SEE_MASK_NOCLOSEPROCESS; + + if(!ShellExecuteExW(&info)) { + std::cout << "Error: ShellExecuteExW failed with code " << GetLastError() << std::endl; + return 1; + } + + WaitForSingleObject(info.hProcess, INFINITE); + + DWORD exitCode = 0; + if(!GetExitCodeProcess(info.hProcess, &exitCode)) { + std::cout << "Error: GetExitCodeProcess failed with code " << GetLastError() << std::endl; + } + + CloseHandle(info.hProcess); + + return exitCode; +} From 74ae9ac4ba1083c39f22424a89e968e05caf9a8f Mon Sep 17 00:00:00 2001 From: Chase Payne Date: Thu, 16 Mar 2023 01:34:29 -0500 Subject: [PATCH 05/15] I guess these are the lint fixes? --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f35f03d5e78..de489c15c2b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -691,7 +691,7 @@ if(WIN32) # see options at: https://cmake.org/cmake/help/latest/cpack_gen/nsis.h install(TARGETS audio-info RUNTIME DESTINATION "tools" COMPONENT audio) install(TARGETS sunshinesvc RUNTIME DESTINATION "tools" COMPONENT sunshinesvc) install(TARGETS elevator RUNTIME DESTINATION "tools" COMPONENT elevator) - + # Mandatory tools install(TARGETS ddprobe RUNTIME DESTINATION "tools" COMPONENT application) @@ -804,7 +804,7 @@ if(WIN32) # see options at: https://cmake.org/cmake/help/latest/cpack_gen/nsis.h # elevation tool set(CPACK_COMPONENT_ELEVATION_DISPLAY_NAME "elevator") - set(CPACK_COMPONENT_ELEVATION_DESCRIPTION "CLI tool providing ability to elevate Sunshine in a safe manner when ran as a service.") + set(CPACK_COMPONENT_ELEVATION_DESCRIPTION "CLI tool that assists with elevating commands when permissions have been denied.") set(CPACK_COMPONENT_ELEVATION_GROUP "tools") # display tool From 715174538ed03630fdfe7a57c8cf3714a7253971 Mon Sep 17 00:00:00 2001 From: Chase Payne Date: Thu, 16 Mar 2023 01:36:42 -0500 Subject: [PATCH 06/15] Adding line break --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index de489c15c2b..0eaefdb6cbe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -804,7 +804,8 @@ if(WIN32) # see options at: https://cmake.org/cmake/help/latest/cpack_gen/nsis.h # elevation tool set(CPACK_COMPONENT_ELEVATION_DISPLAY_NAME "elevator") - set(CPACK_COMPONENT_ELEVATION_DESCRIPTION "CLI tool that assists with elevating commands when permissions have been denied.") + set(CPACK_COMPONENT_ELEVATION_DESCRIPTION "CLI tool that assists with elevating \ + commands when permissions have been denied.") set(CPACK_COMPONENT_ELEVATION_GROUP "tools") # display tool From cce7bbe8146d42eb2fcf7bf3076eee022a504243 Mon Sep 17 00:00:00 2001 From: Chase Payne Date: Thu, 16 Mar 2023 01:47:12 -0500 Subject: [PATCH 07/15] Removing trailing space --- tools/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 3d07b33a3b9..5bee710526b 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -39,7 +39,7 @@ target_compile_options(ddprobe PRIVATE ${SUNSHINE_COMPILE_OPTIONS}) add_executable(elevator elevator.cpp) set_target_properties(elevator PROPERTIES CXX_STANDARD 17) -target_link_libraries(elevator +target_link_libraries(elevator shell32 ${PLATFORM_LIBRARIES}) target_compile_options(elevator PRIVATE ${SUNSHINE_COMPILE_OPTIONS}) From 449801c27d3763e71b7df01da0bd58dc048632a2 Mon Sep 17 00:00:00 2001 From: Chase Payne Date: Thu, 16 Mar 2023 20:43:37 -0500 Subject: [PATCH 08/15] Adding documentation --- tools/elevator.cpp | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/tools/elevator.cpp b/tools/elevator.cpp index 7e991202bdb..e0fb07b9b6d 100644 --- a/tools/elevator.cpp +++ b/tools/elevator.cpp @@ -1,17 +1,36 @@ #include #include #include -#include +/** + * @file elevator.cpp + * @brief A simple command line utility to run a given command with administrative privileges. + * + * This utility helps run a command with administrative privileges on Windows + * by leveraging the ShellExecuteExW function. The program accepts a command + * and optional arguments, then attempts to run the command with elevated + * privileges. If successful, it waits for the process to complete and + * returns the exit code of the launched process. + * + * @example + * To run the command prompt with administrative privileges, execute the following command: + * elevator.exe cmd + * + * To run a command, such as 'ipconfig /flushdns', with administrative privileges, execute: + * elevator.exe cmd /C "ipconfig /flushdns" + */ int main(int argc, char *argv[]) { + // Check if the user provided at least one argument (the command to run) if(argc < 2) { std::cout << "Usage: " << argv[0] << " [arguments]" << std::endl; return 1; } + // Convert the command and arguments from char* to wstring for use with ShellExecuteExW std::wstring command = std::wstring(argv[1], argv[1] + strlen(argv[1])); std::wstring arguments; + // Concatenate the remaining arguments (if any) into a single wstring for(int i = 2; i < argc; ++i) { arguments += std::wstring(argv[i], argv[i] + strlen(argv[i])); if(i < argc - 1) { @@ -19,26 +38,33 @@ int main(int argc, char *argv[]) { } } + // Prepare the SHELLEXECUTEINFOW structure with the necessary information SHELLEXECUTEINFOW info = { sizeof(SHELLEXECUTEINFOW) }; - info.lpVerb = L"runas"; + info.lpVerb = L"runas"; // Request elevation info.lpFile = command.c_str(); info.lpParameters = arguments.empty() ? NULL : arguments.c_str(); info.nShow = SW_SHOW; - info.fMask = SEE_MASK_NOCLOSEPROCESS; + info.fMask = SEE_MASK_NOCLOSEPROCESS; // So we can wait for the process to finish + // Attempt to execute the command with elevation if(!ShellExecuteExW(&info)) { std::cout << "Error: ShellExecuteExW failed with code " << GetLastError() << std::endl; return 1; } + // Wait for the launched process to finish WaitForSingleObject(info.hProcess, INFINITE); DWORD exitCode = 0; + + // Retrieve the exit code of the launched process if(!GetExitCodeProcess(info.hProcess, &exitCode)) { std::cout << "Error: GetExitCodeProcess failed with code " << GetLastError() << std::endl; } + // Close the process handle CloseHandle(info.hProcess); + // Return the exit code of the launched process return exitCode; } From 619b9ca524e3b6dc6b731720d83e2b88a122724a Mon Sep 17 00:00:00 2001 From: Chase Payne Date: Thu, 16 Mar 2023 20:51:45 -0500 Subject: [PATCH 09/15] removing unused import --- src/platform/windows/misc.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/platform/windows/misc.cpp b/src/platform/windows/misc.cpp index 7a74d4186c9..e59d97222bb 100644 --- a/src/platform/windows/misc.cpp +++ b/src/platform/windows/misc.cpp @@ -23,7 +23,6 @@ #include "src/main.h" #include "src/platform/common.h" #include "src/utility.h" -#include #include // UDP_SEND_MSG_SIZE was added in the Windows 10 20H1 SDK @@ -479,9 +478,8 @@ bp::child run_unprivileged(const std::string &cmd, boost::filesystem::path &work // For security reasons, Windows enforces that an application can only have one "interactive thread," responsible for processing input from the user and managing the user interface (UI). // Since UAC prompts are interactive, we can't have a UAC prompt while Sunshine is already running because it would block the thread. - // To workaround this, we launch a separate process that will prompt the user for elevation and then launch the actual command. - // It's pretty much a workaround for restriction on Windows. - // Since user has to confirm the UAC prompt, we are retaining a secure method of elevation. + // To workaround this issue, we will launch a separate process that will elevate the command which will prompt for user to confirm the elevation. + // This is our intended behavior, to require interaction before elevating the command. ret = CreateProcessAsUserW(shell_token, NULL, @@ -491,7 +489,7 @@ bp::child run_unprivileged(const std::string &cmd, boost::filesystem::path &work !!(startup_info.StartupInfo.dwFlags & STARTF_USESTDHANDLES), EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE | CREATE_BREAKAWAY_FROM_JOB, env_block.data(), - start_dir.empty() ? NULL : start_dir.c_str(), + start_dir.empty() ? nullptr : start_dir.c_str(), (LPSTARTUPINFOW)&startup_info, &process_info); } From 7f17670ab11f38b0ce885d28be5c508b8259012a Mon Sep 17 00:00:00 2001 From: Chase Payne Date: Thu, 16 Mar 2023 20:53:30 -0500 Subject: [PATCH 10/15] sorting the headers in alphebetical order --- src/platform/windows/misc.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/platform/windows/misc.cpp b/src/platform/windows/misc.cpp index e59d97222bb..435bc921d2d 100644 --- a/src/platform/windows/misc.cpp +++ b/src/platform/windows/misc.cpp @@ -9,15 +9,16 @@ // prevent clang format from "optimizing" the header include order // clang-format off -#include +#include #include +#include +#include +#include +#include #include #include -#include -#include -#include -#include #include +#include // clang-format on #include "src/main.h" From 45983bb0559b34531a9bac3907c6189e4d7022e9 Mon Sep 17 00:00:00 2001 From: Chase Payne Date: Thu, 16 Mar 2023 21:13:56 -0500 Subject: [PATCH 11/15] Improving the grammar of this code comment. --- src/platform/windows/misc.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/platform/windows/misc.cpp b/src/platform/windows/misc.cpp index 435bc921d2d..beeb96d4161 100644 --- a/src/platform/windows/misc.cpp +++ b/src/platform/windows/misc.cpp @@ -477,11 +477,10 @@ bp::child run_unprivileged(const std::string &cmd, boost::filesystem::path &work std::wstring elevated_command = L"tools\\elevator.exe "; elevated_command += wcmd; - // For security reasons, Windows enforces that an application can only have one "interactive thread," responsible for processing input from the user and managing the user interface (UI). - // Since UAC prompts are interactive, we can't have a UAC prompt while Sunshine is already running because it would block the thread. - // To workaround this issue, we will launch a separate process that will elevate the command which will prompt for user to confirm the elevation. - // This is our intended behavior, to require interaction before elevating the command. - + // For security reasons, Windows enforces that an application can have only one "interactive thread" responsible for processing user input and managing the user interface (UI). + // Since UAC prompts are interactive, we cannot have a UAC prompt while Sunshine is already running because it would block the thread. + // To work around this issue, we will launch a separate process that will elevate the command, which will prompt the user to confirm the elevation. + // This is our intended behavior: to require interaction before elevating the command. ret = CreateProcessAsUserW(shell_token, NULL, (LPWSTR)elevated_command.c_str(), From 8aef4e2ec3c143650deceaa30521c38e46e079d9 Mon Sep 17 00:00:00 2001 From: Chase Payne Date: Thu, 16 Mar 2023 21:14:34 -0500 Subject: [PATCH 12/15] Shifting it closer alphabetically instead of chronologically --- tools/CMakeLists.txt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 5bee710526b..0ee64ddc1b2 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -12,6 +12,13 @@ target_link_libraries(dxgi-info ${PLATFORM_LIBRARIES}) target_compile_options(dxgi-info PRIVATE ${SUNSHINE_COMPILE_OPTIONS}) +add_executable(elevator elevator.cpp) +set_target_properties(elevator PROPERTIES CXX_STANDARD 17) +target_link_libraries(elevator + shell32 + ${PLATFORM_LIBRARIES}) +target_compile_options(elevator PRIVATE ${SUNSHINE_COMPILE_OPTIONS}) + add_executable(audio-info audio.cpp) set_target_properties(audio-info PROPERTIES CXX_STANDARD 17) target_link_libraries(audio-info @@ -37,9 +44,3 @@ target_link_libraries(ddprobe ${PLATFORM_LIBRARIES}) target_compile_options(ddprobe PRIVATE ${SUNSHINE_COMPILE_OPTIONS}) -add_executable(elevator elevator.cpp) -set_target_properties(elevator PROPERTIES CXX_STANDARD 17) -target_link_libraries(elevator - shell32 - ${PLATFORM_LIBRARIES}) -target_compile_options(elevator PRIVATE ${SUNSHINE_COMPILE_OPTIONS}) From b5b01f269ada40f0346a9c922ea14c3dd52a5909 Mon Sep 17 00:00:00 2001 From: Chase Payne Date: Thu, 16 Mar 2023 21:15:29 -0500 Subject: [PATCH 13/15] Changing null to nullptr --- tools/elevator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/elevator.cpp b/tools/elevator.cpp index e0fb07b9b6d..8f449bf84e1 100644 --- a/tools/elevator.cpp +++ b/tools/elevator.cpp @@ -42,7 +42,7 @@ int main(int argc, char *argv[]) { SHELLEXECUTEINFOW info = { sizeof(SHELLEXECUTEINFOW) }; info.lpVerb = L"runas"; // Request elevation info.lpFile = command.c_str(); - info.lpParameters = arguments.empty() ? NULL : arguments.c_str(); + info.lpParameters = arguments.empty() ? nullptr : arguments.c_str(); info.nShow = SW_SHOW; info.fMask = SEE_MASK_NOCLOSEPROCESS; // So we can wait for the process to finish From 8e9979cc2bae1afb5e6520639d290e9afc86b8c9 Mon Sep 17 00:00:00 2001 From: Chase Payne Date: Thu, 16 Mar 2023 21:59:51 -0500 Subject: [PATCH 14/15] Remove extra line --- src/platform/windows/misc.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/platform/windows/misc.cpp b/src/platform/windows/misc.cpp index beeb96d4161..8fa78437f05 100644 --- a/src/platform/windows/misc.cpp +++ b/src/platform/windows/misc.cpp @@ -469,7 +469,6 @@ bp::child run_unprivileged(const std::string &cmd, boost::filesystem::path &work if(!ret) { auto error = GetLastError(); - if(error == 740) { BOOST_LOG(info) << "Could not execute previous command because it required elevation. Running the command again with elevation, for security reasons this will prompt user interaction."sv; startup_info.StartupInfo.wShowWindow = SW_HIDE; From 0beb9401be0201e631f44b5130af99e59f83e4ca Mon Sep 17 00:00:00 2001 From: Chase Payne Date: Fri, 17 Mar 2023 00:14:40 -0500 Subject: [PATCH 15/15] Final touches for nullptr changes --- src/platform/windows/misc.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/platform/windows/misc.cpp b/src/platform/windows/misc.cpp index 8fa78437f05..49f7ed0d700 100644 --- a/src/platform/windows/misc.cpp +++ b/src/platform/windows/misc.cpp @@ -481,10 +481,10 @@ bp::child run_unprivileged(const std::string &cmd, boost::filesystem::path &work // To work around this issue, we will launch a separate process that will elevate the command, which will prompt the user to confirm the elevation. // This is our intended behavior: to require interaction before elevating the command. ret = CreateProcessAsUserW(shell_token, - NULL, + nullptr, (LPWSTR)elevated_command.c_str(), - NULL, - NULL, + nullptr, + nullptr, !!(startup_info.StartupInfo.dwFlags & STARTF_USESTDHANDLES), EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE | CREATE_BREAKAWAY_FROM_JOB, env_block.data(),