// 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 <windows.h>
#include "base/macros.h"
#include "base/strings/string16.h"
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;
}
bool IsNonBrowserProcess() {
typedef bool (*IsSandboxedProcessFunc)();
IsSandboxedProcessFunc is_sandboxed_process_func =
reinterpret_cast<IsSandboxedProcessFunc>(
GetProcAddress(GetModuleHandle(NULL), "IsSandboxedProcess"));
bool is_sandboxed_process =
is_sandboxed_process_func && is_sandboxed_process_func();
// TODO(robertshield): Drop the command line check when we drop support for
// enabling chrome_elf in unsandboxed processes.
wchar_t* command_line = GetCommandLine();
bool has_process_type_flag = command_line && wcsstr(command_line, L"--type");
return (has_process_type_flag || is_sandboxed_process);
}