| // Copyright 2020 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <string> |
| |
| #include "base/functional/function_ref.h" |
| #include "base/logging.h" |
| #include "base/strings/strcat.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/win/registry.h" |
| #include "base/win/windows_types.h" |
| #include "chrome/updater/activity.h" |
| #include "chrome/updater/updater_scope.h" |
| #include "chrome/updater/util/win_util.h" |
| #include "chrome/updater/win/user_info.h" |
| #include "chrome/updater/win/win_constants.h" |
| |
| namespace updater { |
| namespace { |
| |
| using ProcessActiveBitUnderKeyCallback = |
| base::FunctionRef<bool(HKEY, const std::wstring&)>; |
| |
| constexpr wchar_t kDidRun[] = L"dr"; |
| |
| bool GetActiveBitUnderKey(HKEY rootkey, const std::wstring& key_name) { |
| base::win::RegKey key; |
| if (key.Open(rootkey, key_name.c_str(), Wow6432(KEY_QUERY_VALUE)) == |
| ERROR_SUCCESS) { |
| // We support both string and DWORD formats for backward compatibility. |
| std::wstring value; |
| if ((key.ReadValue(kDidRun, &value) == ERROR_SUCCESS) && (value == L"1")) { |
| return true; |
| } |
| |
| DWORD value_dw = 0; |
| if ((key.ReadValueDW(kDidRun, &value_dw) == ERROR_SUCCESS) && |
| (value_dw == 1)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| // Always returns false to avoid the short circuit in ProcessActiveBit and |
| // the early return in ProcessSystemActiveBit. |
| bool ClearActiveBitUnderKey(HKEY rootkey, const std::wstring& key_name) { |
| base::win::RegKey key; |
| if (key.Open(rootkey, key_name.c_str(), |
| Wow6432(KEY_QUERY_VALUE | KEY_SET_VALUE)) != ERROR_SUCCESS) { |
| VLOG(3) << "Failed to open activity key with write for " << key_name; |
| return false; |
| } |
| |
| if (!key.HasValue(kDidRun)) { |
| return false; |
| } |
| |
| // We always clear the value as a string "0". |
| const LONG result = key.WriteValue(kDidRun, L"0"); |
| VLOG_IF(2, result) << "Failed to clear activity key for " << key_name << ": " |
| << result; |
| return false; |
| } |
| |
| bool ProcessActiveBit(ProcessActiveBitUnderKeyCallback callback, |
| HKEY rootkey, |
| const std::wstring& sid, |
| const std::string& id) { |
| const std::wstring rootkey_suffix = |
| (rootkey == HKEY_USERS) ? base::StrCat({sid, L"\\"}) : L""; |
| const bool process_success = callback( |
| rootkey, base::StrCat({rootkey_suffix, GetAppClientStateKey(id)})); |
| |
| // For Google Toolbar and similar apps that run at low integrity, we need to |
| // also look at the low integrity IE key. Note that we cannot use the |
| // IEGetWriteableHKCU function since this function assumes that we are |
| // running with the user's credentials. The path is as follows: |
| // USER_REG_VISTA_LOW_INTEGRITY_HKCU\\SID |
| // \\GOOPDATE_REG_RELATIVE_CLIENT_STATE\\app_guid |
| const std::wstring low_integrity_key_name = |
| base::StrCat({rootkey_suffix, USER_REG_VISTA_LOW_INTEGRITY_HKCU, L"\\", |
| sid, L"\\", GetAppClientStateKey(id)}); |
| |
| return callback(rootkey, low_integrity_key_name) || process_success; |
| } |
| |
| bool ProcessUserActiveBit(ProcessActiveBitUnderKeyCallback callback, |
| const std::string& id) { |
| // Clear the active bit under HKCU. |
| std::wstring sid; |
| const HRESULT hr = GetProcessUser(nullptr, nullptr, &sid); |
| if (FAILED(hr)) { |
| VLOG(2) << "Failed to GetProcessUser " << hr; |
| return false; |
| } |
| |
| return ProcessActiveBit(callback, HKEY_CURRENT_USER, sid, id); |
| } |
| |
| bool ProcessSystemActiveBit(ProcessActiveBitUnderKeyCallback callback, |
| const std::string& id) { |
| // Clear the active bit under each user in HKU\<sid>. |
| for (base::win::RegistryKeyIterator it(HKEY_USERS, L"", KEY_WOW64_32KEY); |
| it.Valid(); ++it) { |
| const std::wstring sid = it.Name(); |
| if (ProcessActiveBit(callback, HKEY_USERS, sid, id)) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| bool GetUserActiveBit(const std::string& id) { |
| // Read the active bit under HKCU. |
| return ProcessUserActiveBit(&GetActiveBitUnderKey, id); |
| } |
| |
| void ClearUserActiveBit(const std::string& id) { |
| // Clear the active bit under HKCU. |
| ProcessUserActiveBit(&ClearActiveBitUnderKey, id); |
| } |
| |
| bool GetSystemActiveBit(const std::string& id) { |
| // Read the active bit under each user in HKU\<sid>. |
| return ProcessSystemActiveBit(&GetActiveBitUnderKey, id); |
| } |
| |
| void ClearSystemActiveBit(const std::string& id) { |
| // Clear the active bit under each user in HKU\<sid>. |
| ProcessSystemActiveBit(&ClearActiveBitUnderKey, id); |
| } |
| |
| } // namespace |
| |
| bool GetActiveBit(UpdaterScope scope, const std::string& id) { |
| switch (scope) { |
| case UpdaterScope::kUser: |
| return GetUserActiveBit(id); |
| case UpdaterScope::kSystem: |
| return GetSystemActiveBit(id); |
| } |
| } |
| |
| void ClearActiveBit(UpdaterScope scope, const std::string& id) { |
| switch (scope) { |
| case UpdaterScope::kUser: |
| ClearUserActiveBit(id); |
| break; |
| case UpdaterScope::kSystem: |
| ClearSystemActiveBit(id); |
| break; |
| } |
| } |
| |
| } // namespace updater |