| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome_elf/chrome_elf_util.h" |
| |
| #include <assert.h> |
| #include <windows.h> |
| |
| #include "base/macros.h" |
| #include "base/strings/string16.h" |
| |
| ProcessType g_process_type = ProcessType::UNINITIALIZED; |
| |
| namespace { |
| |
| const wchar_t kRegPathClientState[] = L"Software\\Google\\Update\\ClientState"; |
| const wchar_t kRegPathClientStateMedium[] = |
| L"Software\\Google\\Update\\ClientStateMedium"; |
| #if defined(GOOGLE_CHROME_BUILD) |
| const wchar_t kRegPathChromePolicy[] = L"SOFTWARE\\Policies\\Google\\Chrome"; |
| #else |
| const wchar_t kRegPathChromePolicy[] = L"SOFTWARE\\Policies\\Chromium"; |
| #endif // defined(GOOGLE_CHROME_BUILD) |
| |
| const wchar_t kRegValueUsageStats[] = L"usagestats"; |
| const wchar_t kUninstallArgumentsField[] = L"UninstallArguments"; |
| const wchar_t kMetricsReportingEnabled[] =L"MetricsReportingEnabled"; |
| |
| const wchar_t kAppGuidCanary[] = |
| L"{4ea16ac7-fd5a-47c3-875b-dbf4a2008c20}"; |
| const wchar_t kAppGuidGoogleChrome[] = |
| L"{8A69D345-D564-463c-AFF1-A69D9E530F96}"; |
| const wchar_t kAppGuidGoogleBinaries[] = |
| L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}"; |
| |
| bool ReadKeyValueString(bool system_install, const wchar_t* key_path, |
| const wchar_t* guid, const wchar_t* value_to_read, |
| base::string16* value_out) { |
| HKEY key = NULL; |
| value_out->clear(); |
| |
| base::string16 full_key_path(key_path); |
| full_key_path.append(1, L'\\'); |
| full_key_path.append(guid); |
| |
| if (::RegOpenKeyEx(system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, |
| full_key_path.c_str(), 0, |
| KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key) != |
| ERROR_SUCCESS) { |
| return false; |
| } |
| |
| const size_t kMaxStringLength = 1024; |
| wchar_t raw_value[kMaxStringLength] = {}; |
| DWORD size = sizeof(raw_value); |
| DWORD type = REG_SZ; |
| LONG result = ::RegQueryValueEx(key, value_to_read, 0, &type, |
| reinterpret_cast<LPBYTE>(raw_value), &size); |
| |
| if (result == ERROR_SUCCESS) { |
| if (type != REG_SZ || (size & 1) != 0) { |
| result = ERROR_NOT_SUPPORTED; |
| } else if (size == 0) { |
| *raw_value = L'\0'; |
| } else if (raw_value[size / sizeof(wchar_t) - 1] != L'\0') { |
| if ((size / sizeof(wchar_t)) < kMaxStringLength) |
| raw_value[size / sizeof(wchar_t)] = L'\0'; |
| else |
| result = ERROR_MORE_DATA; |
| } |
| } |
| |
| if (result == ERROR_SUCCESS) |
| *value_out = raw_value; |
| |
| ::RegCloseKey(key); |
| |
| return result == ERROR_SUCCESS; |
| } |
| |
| bool ReadKeyValueDW(bool system_install, const wchar_t* key_path, |
| base::string16 guid, const wchar_t* value_to_read, |
| DWORD* value_out) { |
| HKEY key = NULL; |
| *value_out = 0; |
| |
| base::string16 full_key_path(key_path); |
| full_key_path.append(1, L'\\'); |
| full_key_path.append(guid); |
| |
| if (::RegOpenKeyEx(system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, |
| full_key_path.c_str(), 0, |
| KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key) != |
| ERROR_SUCCESS) { |
| return false; |
| } |
| |
| DWORD size = sizeof(*value_out); |
| DWORD type = REG_DWORD; |
| LONG result = ::RegQueryValueEx(key, value_to_read, 0, &type, |
| reinterpret_cast<BYTE*>(value_out), &size); |
| |
| ::RegCloseKey(key); |
| |
| return result == ERROR_SUCCESS && size == sizeof(*value_out); |
| } |
| |
| } // namespace |
| |
| bool IsCanary(const wchar_t* exe_path) { |
| return wcsstr(exe_path, L"Chrome SxS\\Application") != NULL; |
| } |
| |
| bool IsSystemInstall(const wchar_t* exe_path) { |
| wchar_t program_dir[MAX_PATH] = {}; |
| DWORD ret = ::GetEnvironmentVariable(L"PROGRAMFILES", program_dir, |
| arraysize(program_dir)); |
| if (ret && ret < MAX_PATH && !wcsncmp(exe_path, program_dir, ret)) |
| return true; |
| |
| ret = ::GetEnvironmentVariable(L"PROGRAMFILES(X86)", program_dir, |
| arraysize(program_dir)); |
| if (ret && ret < MAX_PATH && !wcsncmp(exe_path, program_dir, ret)) |
| return true; |
| |
| return false; |
| } |
| |
| bool IsMultiInstall(bool is_system_install) { |
| base::string16 args; |
| if (!ReadKeyValueString(is_system_install, kRegPathClientState, |
| kAppGuidGoogleChrome, kUninstallArgumentsField, |
| &args)) { |
| return false; |
| } |
| return args.find(L"--multi-install") != base::string16::npos; |
| } |
| |
| bool AreUsageStatsEnabled(const wchar_t* exe_path) { |
| bool enabled = true; |
| bool controlled_by_policy = ReportingIsEnforcedByPolicy(&enabled); |
| |
| if (controlled_by_policy && !enabled) |
| return false; |
| |
| bool system_install = IsSystemInstall(exe_path); |
| base::string16 app_guid; |
| |
| if (IsCanary(exe_path)) { |
| app_guid = kAppGuidCanary; |
| } else { |
| app_guid = IsMultiInstall(system_install) ? kAppGuidGoogleBinaries : |
| kAppGuidGoogleChrome; |
| } |
| |
| DWORD out_value = 0; |
| if (system_install && |
| ReadKeyValueDW(system_install, kRegPathClientStateMedium, app_guid, |
| kRegValueUsageStats, &out_value)) { |
| return out_value == 1; |
| } |
| |
| return ReadKeyValueDW(system_install, kRegPathClientState, app_guid, |
| kRegValueUsageStats, &out_value) && out_value == 1; |
| } |
| |
| bool ReportingIsEnforcedByPolicy(bool* breakpad_enabled) { |
| HKEY key = NULL; |
| DWORD value = 0; |
| BYTE* value_bytes = reinterpret_cast<BYTE*>(&value); |
| DWORD size = sizeof(value); |
| DWORD type = REG_DWORD; |
| |
| if (::RegOpenKeyEx(HKEY_LOCAL_MACHINE, kRegPathChromePolicy, 0, |
| KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) { |
| if (::RegQueryValueEx(key, kMetricsReportingEnabled, 0, &type, |
| value_bytes, &size) == ERROR_SUCCESS) { |
| *breakpad_enabled = value != 0; |
| } |
| ::RegCloseKey(key); |
| return size == sizeof(value); |
| } |
| |
| if (::RegOpenKeyEx(HKEY_CURRENT_USER, kRegPathChromePolicy, 0, |
| KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) { |
| if (::RegQueryValueEx(key, kMetricsReportingEnabled, 0, &type, |
| value_bytes, &size) == ERROR_SUCCESS) { |
| *breakpad_enabled = value != 0; |
| } |
| ::RegCloseKey(key); |
| return size == sizeof(value); |
| } |
| |
| return false; |
| } |
| |
| void InitializeProcessType() { |
| assert(g_process_type == ProcessType::UNINITIALIZED); |
| typedef bool (*IsSandboxedProcessFunc)(); |
| IsSandboxedProcessFunc is_sandboxed_process_func = |
| reinterpret_cast<IsSandboxedProcessFunc>( |
| GetProcAddress(GetModuleHandle(NULL), "IsSandboxedProcess")); |
| if (is_sandboxed_process_func && is_sandboxed_process_func()) { |
| g_process_type = ProcessType::NON_BROWSER_PROCESS; |
| return; |
| } |
| |
| // TODO(robertshield): Drop the command line check when we drop support for |
| // enabling chrome_elf in unsandboxed processes. |
| const wchar_t* command_line = GetCommandLine(); |
| if (command_line && wcsstr(command_line, L"--type")) { |
| g_process_type = ProcessType::NON_BROWSER_PROCESS; |
| return; |
| } |
| |
| g_process_type = ProcessType::BROWSER_PROCESS; |
| } |
| |
| bool IsNonBrowserProcess() { |
| assert(g_process_type != ProcessType::UNINITIALIZED); |
| return g_process_type == ProcessType::NON_BROWSER_PROCESS; |
| } |