|  | // 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 <stddef.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; | 
|  | } |