1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome_elf/chrome_elf_util.h"
6
7 #include <windows.h>
8
9 #include "base/macros.h"
10 #include "base/strings/string16.h"
11
12 namespace {
13
14 const wchar_t kRegPathClientState[] = L"Software\\Google\\Update\\ClientState";
15 const wchar_t kRegPathClientStateMedium[] =
16 L"Software\\Google\\Update\\ClientStateMedium";
17 #if defined(GOOGLE_CHROME_BUILD)
18 const wchar_t kRegPathChromePolicy[] = L"SOFTWARE\\Policies\\Google\\Chrome";
19 #else
20 const wchar_t kRegPathChromePolicy[] = L"SOFTWARE\\Policies\\Chromium";
21 #endif // defined(GOOGLE_CHROME_BUILD)
22
23 const wchar_t kRegValueUsageStats[] = L"usagestats";
24 const wchar_t kUninstallArgumentsField[] = L"UninstallArguments";
25 const wchar_t kMetricsReportingEnabled[] =L"MetricsReportingEnabled";
26
27 const wchar_t kAppGuidCanary[] =
28 L"{4ea16ac7-fd5a-47c3-875b-dbf4a2008c20}";
29 const wchar_t kAppGuidGoogleChrome[] =
30 L"{8A69D345-D564-463c-AFF1-A69D9E530F96}";
31 const wchar_t kAppGuidGoogleBinaries[] =
32 L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}";
33
ReadKeyValueString(bool system_install,const wchar_t * key_path,const wchar_t * guid,const wchar_t * value_to_read,base::string16 * value_out)34 bool ReadKeyValueString(bool system_install, const wchar_t* key_path,
35 const wchar_t* guid, const wchar_t* value_to_read,
36 base::string16* value_out) {
37 HKEY key = NULL;
38 value_out->clear();
39
40 base::string16 full_key_path(key_path);
41 full_key_path.append(1, L'\\');
42 full_key_path.append(guid);
43
44 if (::RegOpenKeyEx(system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
45 full_key_path.c_str(), 0,
46 KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key) !=
47 ERROR_SUCCESS) {
48 return false;
49 }
50
51 const size_t kMaxStringLength = 1024;
52 wchar_t raw_value[kMaxStringLength] = {};
53 DWORD size = sizeof(raw_value);
54 DWORD type = REG_SZ;
55 LONG result = ::RegQueryValueEx(key, value_to_read, 0, &type,
56 reinterpret_cast<LPBYTE>(raw_value), &size);
57
58 if (result == ERROR_SUCCESS) {
59 if (type != REG_SZ || (size & 1) != 0) {
60 result = ERROR_NOT_SUPPORTED;
61 } else if (size == 0) {
62 *raw_value = L'\0';
63 } else if (raw_value[size / sizeof(wchar_t) - 1] != L'\0') {
64 if ((size / sizeof(wchar_t)) < kMaxStringLength)
65 raw_value[size / sizeof(wchar_t)] = L'\0';
66 else
67 result = ERROR_MORE_DATA;
68 }
69 }
70
71 if (result == ERROR_SUCCESS)
72 *value_out = raw_value;
73
74 ::RegCloseKey(key);
75
76 return result == ERROR_SUCCESS;
77 }
78
ReadKeyValueDW(bool system_install,const wchar_t * key_path,base::string16 guid,const wchar_t * value_to_read,DWORD * value_out)79 bool ReadKeyValueDW(bool system_install, const wchar_t* key_path,
80 base::string16 guid, const wchar_t* value_to_read,
81 DWORD* value_out) {
82 HKEY key = NULL;
83 *value_out = 0;
84
85 base::string16 full_key_path(key_path);
86 full_key_path.append(1, L'\\');
87 full_key_path.append(guid);
88
89 if (::RegOpenKeyEx(system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
90 full_key_path.c_str(), 0,
91 KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key) !=
92 ERROR_SUCCESS) {
93 return false;
94 }
95
96 DWORD size = sizeof(*value_out);
97 DWORD type = REG_DWORD;
98 LONG result = ::RegQueryValueEx(key, value_to_read, 0, &type,
99 reinterpret_cast<BYTE*>(value_out), &size);
100
101 ::RegCloseKey(key);
102
103 return result == ERROR_SUCCESS && size == sizeof(*value_out);
104 }
105
106 } // namespace
107
IsCanary(const wchar_t * exe_path)108 bool IsCanary(const wchar_t* exe_path) {
109 return wcsstr(exe_path, L"Chrome SxS\\Application") != NULL;
110 }
111
IsSystemInstall(const wchar_t * exe_path)112 bool IsSystemInstall(const wchar_t* exe_path) {
113 wchar_t program_dir[MAX_PATH] = {};
114 DWORD ret = ::GetEnvironmentVariable(L"PROGRAMFILES", program_dir,
115 arraysize(program_dir));
116 if (ret && ret < MAX_PATH && !wcsncmp(exe_path, program_dir, ret))
117 return true;
118
119 ret = ::GetEnvironmentVariable(L"PROGRAMFILES(X86)", program_dir,
120 arraysize(program_dir));
121 if (ret && ret < MAX_PATH && !wcsncmp(exe_path, program_dir, ret))
122 return true;
123
124 return false;
125 }
126
IsMultiInstall(bool is_system_install)127 bool IsMultiInstall(bool is_system_install) {
128 base::string16 args;
129 if (!ReadKeyValueString(is_system_install, kRegPathClientState,
130 kAppGuidGoogleChrome, kUninstallArgumentsField,
131 &args)) {
132 return false;
133 }
134 return args.find(L"--multi-install") != base::string16::npos;
135 }
136
AreUsageStatsEnabled(const wchar_t * exe_path)137 bool AreUsageStatsEnabled(const wchar_t* exe_path) {
138 bool enabled = true;
139 bool controlled_by_policy = ReportingIsEnforcedByPolicy(&enabled);
140
141 if (controlled_by_policy && !enabled)
142 return false;
143
144 bool system_install = IsSystemInstall(exe_path);
145 base::string16 app_guid;
146
147 if (IsCanary(exe_path)) {
148 app_guid = kAppGuidCanary;
149 } else {
150 app_guid = IsMultiInstall(system_install) ? kAppGuidGoogleBinaries :
151 kAppGuidGoogleChrome;
152 }
153
154 DWORD out_value = 0;
155 if (system_install &&
156 ReadKeyValueDW(system_install, kRegPathClientStateMedium, app_guid,
157 kRegValueUsageStats, &out_value)) {
158 return out_value == 1;
159 }
160
161 return ReadKeyValueDW(system_install, kRegPathClientState, app_guid,
162 kRegValueUsageStats, &out_value) && out_value == 1;
163 }
164
ReportingIsEnforcedByPolicy(bool * breakpad_enabled)165 bool ReportingIsEnforcedByPolicy(bool* breakpad_enabled) {
166 HKEY key = NULL;
167 DWORD value = 0;
168 BYTE* value_bytes = reinterpret_cast<BYTE*>(&value);
169 DWORD size = sizeof(value);
170 DWORD type = REG_DWORD;
171
172 if (::RegOpenKeyEx(HKEY_LOCAL_MACHINE, kRegPathChromePolicy, 0,
173 KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) {
174 if (::RegQueryValueEx(key, kMetricsReportingEnabled, 0, &type,
175 value_bytes, &size) == ERROR_SUCCESS) {
176 *breakpad_enabled = value != 0;
177 }
178 ::RegCloseKey(key);
179 return size == sizeof(value);
180 }
181
182 if (::RegOpenKeyEx(HKEY_CURRENT_USER, kRegPathChromePolicy, 0,
183 KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) {
184 if (::RegQueryValueEx(key, kMetricsReportingEnabled, 0, &type,
185 value_bytes, &size) == ERROR_SUCCESS) {
186 *breakpad_enabled = value != 0;
187 }
188 ::RegCloseKey(key);
189 return size == sizeof(value);
190 }
191
192 return false;
193 }
194
IsNonBrowserProcess()195 bool IsNonBrowserProcess() {
196 typedef bool (*IsSandboxedProcessFunc)();
197 IsSandboxedProcessFunc is_sandboxed_process_func =
198 reinterpret_cast<IsSandboxedProcessFunc>(
199 GetProcAddress(GetModuleHandle(NULL), "IsSandboxedProcess"));
200 bool is_sandboxed_process =
201 is_sandboxed_process_func && is_sandboxed_process_func();
202
203 // TODO(robertshield): Drop the command line check when we drop support for
204 // enabling chrome_elf in unsandboxed processes.
205 wchar_t* command_line = GetCommandLine();
206 bool has_process_type_flag = command_line && wcsstr(command_line, L"--type");
207
208 return (has_process_type_flag || is_sandboxed_process);
209 }
210