| // Copyright 2022 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/updater/test/unit_test_util_win.h" |
| |
| #include <windows.h> |
| |
| #include <string> |
| |
| #include "base/base_paths_win.h" |
| #include "base/command_line.h" |
| #include "base/files/file_util.h" |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/path_service.h" |
| #include "base/process/launch.h" |
| #include "base/strings/strcat.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/test/test_timeouts.h" |
| #include "base/win/atl.h" |
| #include "base/win/registry.h" |
| #include "chrome/updater/test/unit_test_util.h" |
| #include "chrome/updater/updater_scope.h" |
| #include "chrome/updater/util/win_util.h" |
| #include "chrome/updater/win/win_constants.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace updater::test { |
| |
| namespace { |
| |
| void CreateAppCommandRegistryHelper(UpdaterScope scope, |
| const std::wstring& app_id, |
| const std::wstring& cmd_id, |
| const std::wstring& cmd_line, |
| bool auto_run_on_os_upgrade) { |
| CreateAppClientKey(scope, app_id); |
| base::win::RegKey command_key; |
| EXPECT_EQ(command_key.Create(UpdaterScopeToHKeyRoot(scope), |
| GetAppCommandKey(app_id, cmd_id).c_str(), |
| Wow6432(KEY_WRITE)), |
| ERROR_SUCCESS); |
| EXPECT_EQ(command_key.WriteValue(kRegValueCommandLine, cmd_line.c_str()), |
| ERROR_SUCCESS); |
| if (auto_run_on_os_upgrade) { |
| EXPECT_EQ(command_key.WriteValue(kRegValueAutoRunOnOSUpgrade, 1U), |
| ERROR_SUCCESS); |
| } |
| } |
| |
| } // namespace |
| |
| base::win::RegKey CreateAppClientKey(UpdaterScope scope, |
| const std::wstring& app_id) { |
| base::win::RegKey client_key; |
| EXPECT_EQ( |
| client_key.Create(UpdaterScopeToHKeyRoot(scope), |
| GetAppClientsKey(app_id).c_str(), Wow6432(KEY_WRITE)), |
| ERROR_SUCCESS); |
| return client_key; |
| } |
| |
| void DeleteAppClientKey(UpdaterScope scope, const std::wstring& app_id) { |
| base::win::RegKey(UpdaterScopeToHKeyRoot(scope), L"", Wow6432(DELETE)) |
| .DeleteKey(GetAppClientsKey(app_id).c_str()); |
| } |
| |
| base::win::RegKey CreateAppClientStateKey(UpdaterScope scope, |
| const std::wstring& app_id) { |
| base::win::RegKey client_state_key; |
| EXPECT_EQ(client_state_key.Create(UpdaterScopeToHKeyRoot(scope), |
| GetAppClientStateKey(app_id).c_str(), |
| Wow6432(KEY_WRITE)), |
| ERROR_SUCCESS); |
| return client_state_key; |
| } |
| |
| void DeleteAppClientStateKey(UpdaterScope scope, const std::wstring& app_id) { |
| base::win::RegKey(UpdaterScopeToHKeyRoot(scope), L"", Wow6432(DELETE)) |
| .DeleteKey(GetAppClientStateKey(app_id).c_str()); |
| } |
| |
| void CreateLaunchCmdElevatedRegistry(const std::wstring& app_id, |
| const std::wstring& name, |
| const std::wstring& pv, |
| const std::wstring& command_id, |
| const std::wstring& command_line) { |
| base::win::RegKey client_key = |
| CreateAppClientKey(UpdaterScope::kSystem, app_id); |
| EXPECT_EQ(client_key.WriteValue(kRegValueName, name.c_str()), ERROR_SUCCESS); |
| EXPECT_EQ(client_key.WriteValue(kRegValuePV, pv.c_str()), ERROR_SUCCESS); |
| EXPECT_EQ(client_key.WriteValue(command_id.c_str(), command_line.c_str()), |
| ERROR_SUCCESS); |
| } |
| |
| void CreateAppCommandRegistry(UpdaterScope scope, |
| const std::wstring& app_id, |
| const std::wstring& cmd_id, |
| const std::wstring& cmd_line) { |
| CreateAppCommandRegistryHelper(scope, app_id, cmd_id, cmd_line, false); |
| } |
| |
| void CreateAppCommandOSUpgradeRegistry(UpdaterScope scope, |
| const std::wstring& app_id, |
| const std::wstring& cmd_id, |
| const std::wstring& cmd_line) { |
| CreateAppCommandRegistryHelper(scope, app_id, cmd_id, cmd_line, true); |
| } |
| |
| void SetupCmdExe(UpdaterScope scope, |
| base::CommandLine& cmd_exe_command_line, |
| base::ScopedTempDir& temp_programfiles_dir) { |
| static constexpr wchar_t kCmdExe[] = L"cmd.exe"; |
| |
| base::FilePath system_path; |
| ASSERT_TRUE(base::PathService::Get(base::DIR_SYSTEM, &system_path)); |
| |
| const base::FilePath cmd_exe_system_path = system_path.Append(kCmdExe); |
| if (!IsSystemInstall(scope)) { |
| cmd_exe_command_line = base::CommandLine(cmd_exe_system_path); |
| return; |
| } |
| |
| base::FilePath programfiles_path; |
| ASSERT_TRUE( |
| base::PathService::Get(base::DIR_PROGRAM_FILES, &programfiles_path)); |
| ASSERT_TRUE( |
| temp_programfiles_dir.CreateUniqueTempDirUnderPath(programfiles_path)); |
| base::FilePath cmd_exe_path; |
| cmd_exe_path = temp_programfiles_dir.GetPath().Append(kCmdExe); |
| |
| ASSERT_TRUE(base::CopyFile(cmd_exe_system_path, cmd_exe_path)); |
| cmd_exe_command_line = base::CommandLine(cmd_exe_path); |
| } |
| |
| [[nodiscard]] bool CreateService(const std::wstring& service_name, |
| const std::wstring& display_name, |
| const std::wstring& command_line) { |
| ScopedScHandle scm(::OpenSCManager( |
| nullptr, nullptr, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE)); |
| if (!scm.IsValid()) { |
| return false; |
| } |
| |
| ScopedScHandle service(::CreateService( |
| scm.Get(), service_name.c_str(), display_name.c_str(), |
| DELETE | SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG, |
| SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, |
| command_line.c_str(), nullptr, nullptr, nullptr, nullptr, nullptr)); |
| return service.IsValid() || ::GetLastError() == ERROR_SERVICE_EXISTS; |
| } |
| |
| [[nodiscard]] bool DisableService(const std::wstring& service_name) { |
| ScopedScHandle scm(::OpenSCManager( |
| nullptr, nullptr, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE)); |
| if (!scm.IsValid()) { |
| return false; |
| } |
| |
| ScopedScHandle service( |
| ::OpenService(scm.Get(), service_name.c_str(), |
| SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG)); |
| if (!service.IsValid()) { |
| return true; |
| } |
| |
| return ::ChangeServiceConfig(service.Get(), SERVICE_NO_CHANGE, |
| SERVICE_DISABLED, SERVICE_NO_CHANGE, nullptr, |
| nullptr, nullptr, nullptr, nullptr, nullptr, |
| nullptr) || |
| (::GetLastError() == ERROR_SERVICE_MARKED_FOR_DELETE); |
| } |
| |
| CSecurityDesc GetEveryoneDaclSecurityDescriptor(ACCESS_MASK accessmask) { |
| CSecurityDesc sd; |
| CDacl dacl; |
| dacl.AddAllowedAce(Sids::System(), accessmask); |
| dacl.AddAllowedAce(Sids::Admins(), accessmask); |
| dacl.AddAllowedAce(Sids::Interactive(), accessmask); |
| |
| sd.SetDacl(dacl); |
| sd.MakeAbsolute(); |
| return sd; |
| } |
| |
| test::EventHolder CreateEveryoneWaitableEventForTest() { |
| const std::wstring event_name = |
| base::StrCat({base::UTF8ToWide(test::GetTestName()), L" ", |
| base::NumberToWString(::GetCurrentProcessId())}); |
| CSecurityAttributes sa(GetEveryoneDaclSecurityDescriptor(GENERIC_ALL)); |
| return {base::WaitableEvent(base::win::ScopedHandle( |
| ::CreateEvent(&sa, FALSE, FALSE, event_name.c_str()))), |
| event_name}; |
| } |
| |
| int RunVPythonCommand(const base::CommandLine& command_line) { |
| base::CommandLine python_command = command_line; |
| python_command.PrependWrapper(FILE_PATH_LITERAL("vpython3.bat")); |
| |
| int exit_code = -1; |
| base::Process process = base::LaunchProcess(python_command, {}); |
| EXPECT_TRUE(process.IsValid()); |
| EXPECT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_timeout(), |
| &exit_code)); |
| return exit_code; |
| } |
| |
| } // namespace updater::test |