| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/installer/gcapi/gcapi.h" | 5 #include "chrome/installer/gcapi/gcapi.h" |
| 6 | 6 |
| 7 #include <atlbase.h> | 7 #include <atlbase.h> |
| 8 #include <atlcom.h> | 8 #include <atlcom.h> |
| 9 #include <windows.h> | 9 #include <windows.h> |
| 10 #include <sddl.h> | 10 #include <sddl.h> |
| 11 #include <stdlib.h> | 11 #include <stdlib.h> |
| 12 #include <strsafe.h> | 12 #include <strsafe.h> |
| 13 #include <tlhelp32.h> | 13 #include <tlhelp32.h> |
| 14 | 14 |
| 15 #include "google_update_idl.h" | 15 #include "google_update_idl.h" |
| 16 | 16 |
| 17 namespace { | 17 namespace { |
| 18 | 18 |
| 19 const wchar_t kChromeRegClientsKey[] = L"Software\\Google\\Update\\Clients\\{8A6
9D345-D564-463c-AFF1-A69D9E530F96}"; | 19 const wchar_t kChromeRegClientsKey[] = L"Software\\Google\\Update\\Clients\\{8A6
9D345-D564-463c-AFF1-A69D9E530F96}"; |
| 20 const wchar_t kChromeRegClientStateKey[] = L"Software\\Google\\Update\\ClientSta
te\\{8A69D345-D564-463c-AFF1-A69D9E530F96}"; | 20 const wchar_t kChromeRegClientStateKey[] = L"Software\\Google\\Update\\ClientSta
te\\{8A69D345-D564-463c-AFF1-A69D9E530F96}"; |
| 21 const wchar_t kChromeRegLaunchCmd[] = L"InstallerSuccessLaunchCmdLine"; | 21 const wchar_t kChromeRegLaunchCmd[] = L"InstallerSuccessLaunchCmdLine"; |
| 22 const wchar_t kChromeRegLastLaunchCmd[] = L"LastInstallerSuccessLaunchCmdLine"; | 22 const wchar_t kChromeRegLastLaunchCmd[] = L"LastInstallerSuccessLaunchCmdLine"; |
| 23 const wchar_t kChromeRegVersion[] = L"pv"; | 23 const wchar_t kChromeRegVersion[] = L"pv"; |
| 24 const wchar_t kNoChromeOfferUntil[] = L"SOFTWARE\\Google\\No Chrome Offer Until"
; |
| 25 |
| 26 // Remove any registry key with non-numeric value or with the numeric value |
| 27 // equal or less than today's date represented in YYYYMMDD form. |
| 28 void CleanUpRegistryValues() { |
| 29 HKEY key = NULL; |
| 30 if (::RegOpenKeyEx(HKEY_LOCAL_MACHINE, kNoChromeOfferUntil, |
| 31 0, KEY_ALL_ACCESS, &key) != ERROR_SUCCESS) |
| 32 return; |
| 33 |
| 34 DWORD index = 0; |
| 35 wchar_t value_name[260]; |
| 36 DWORD value_name_len = _countof(value_name); |
| 37 DWORD value_type = REG_DWORD; |
| 38 DWORD value_data = 0; |
| 39 DWORD value_len = sizeof(DWORD); |
| 40 |
| 41 // First, remove any value whose type is not DWORD. |
| 42 while (::RegEnumValue(key, index, value_name, &value_name_len, NULL, |
| 43 &value_type, NULL, &value_len) == ERROR_SUCCESS) { |
| 44 if (value_type == REG_DWORD) |
| 45 index++; |
| 46 else |
| 47 ::RegDeleteValue(key, value_name); |
| 48 |
| 49 value_name_len = _countof(value_name); |
| 50 value_type = REG_DWORD; |
| 51 value_len = sizeof(DWORD); |
| 52 } |
| 53 |
| 54 // Get today's date, and format it as YYYYMMDD numeric value. |
| 55 SYSTEMTIME now; |
| 56 ::GetLocalTime(&now); |
| 57 DWORD expiration_date = now.wYear * 10000 + now.wMonth * 100 + now.wDay; |
| 58 |
| 59 // Remove any DWORD value smaller than the number represent the |
| 60 // expiration date (YYYYMMDD). |
| 61 index = 0; |
| 62 while (::RegEnumValue(key, index, value_name, &value_name_len, NULL, |
| 63 &value_type, (LPBYTE) &value_data, |
| 64 &value_len) == ERROR_SUCCESS) { |
| 65 if (value_type == REG_DWORD && value_data > expiration_date) |
| 66 index++; // move on to next value. |
| 67 else |
| 68 ::RegDeleteValue(key, value_name); // delete this value. |
| 69 |
| 70 value_name_len = _countof(value_name); |
| 71 value_type = REG_DWORD; |
| 72 value_data = 0; |
| 73 value_len = sizeof(DWORD); |
| 74 } |
| 75 |
| 76 ::RegCloseKey(key); |
| 77 } |
| 78 |
| 79 // Return the company name specified in the file version info resource. |
| 80 bool GetCompanyName(const wchar_t* filename, wchar_t* buffer, DWORD out_len) { |
| 81 wchar_t file_version_info[8192]; |
| 82 DWORD handle = 0; |
| 83 DWORD buffer_size = 0; |
| 84 |
| 85 buffer_size = ::GetFileVersionInfoSize(filename, &handle); |
| 86 // Cannot stats the file or our buffer size is too small (very unlikely). |
| 87 if (buffer_size == 0 || buffer_size > _countof(file_version_info)) |
| 88 return false; |
| 89 |
| 90 buffer_size = _countof(file_version_info); |
| 91 memset(file_version_info, 0, buffer_size); |
| 92 if (!::GetFileVersionInfo(filename, handle, buffer_size, file_version_info)) |
| 93 return false; |
| 94 |
| 95 DWORD data_len = 0; |
| 96 LPVOID data = NULL; |
| 97 // Retrieve the language and codepage code if exists. |
| 98 buffer_size = 0; |
| 99 if (!::VerQueryValue(file_version_info, TEXT("\\VarFileInfo\\Translation"), |
| 100 reinterpret_cast<LPVOID *>(&data), reinterpret_cast<UINT *>(&data_len))) |
| 101 return false; |
| 102 if (data_len != 4) |
| 103 return false; |
| 104 |
| 105 wchar_t info_name[256]; |
| 106 DWORD lang = 0; |
| 107 // Formulate the string to retrieve the company name of the specific |
| 108 // language codepage. |
| 109 memcpy(&lang, data, 4); |
| 110 ::StringCchPrintf(info_name, _countof(info_name), |
| 111 L"\\StringFileInfo\\%02X%02X%02X%02X\\CompanyName", |
| 112 (lang & 0xff00)>>8, (lang & 0xff), (lang & 0xff000000)>>24, |
| 113 (lang & 0xff0000)>>16); |
| 114 |
| 115 data_len = 0; |
| 116 if (!::VerQueryValue(file_version_info, info_name, |
| 117 reinterpret_cast<LPVOID *>(&data), reinterpret_cast<UINT *>(&data_len))) |
| 118 return false; |
| 119 if (data_len <= 0 || data_len >= out_len) |
| 120 return false; |
| 121 |
| 122 memset(buffer, 0, out_len); |
| 123 ::StringCchCopyN(buffer, out_len, (const wchar_t*)data, data_len); |
| 124 return true; |
| 125 } |
| 126 |
| 127 // Return true if we can re-offer Chrome; false, otherwise. |
| 128 // Each partner can only offer Chrome once every six months. |
| 129 bool CanReOfferChrome(BOOL set_flag) { |
| 130 wchar_t filename[MAX_PATH+1]; |
| 131 wchar_t company[MAX_PATH]; |
| 132 |
| 133 // If we cannot retrieve the version info of the executable or company |
| 134 // name, we allow the Chrome to be offered because there is no past |
| 135 // history to be found. |
| 136 if (::GetModuleFileName(NULL, filename, MAX_PATH) == 0) |
| 137 return true; |
| 138 if (!GetCompanyName(filename, company, sizeof(company))) |
| 139 return true; |
| 140 |
| 141 bool can_re_offer = true; |
| 142 DWORD disposition = 0; |
| 143 HKEY key = NULL; |
| 144 if (::RegCreateKeyEx(HKEY_LOCAL_MACHINE, kNoChromeOfferUntil, |
| 145 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, |
| 146 NULL, &key, &disposition) == ERROR_SUCCESS) { |
| 147 // Cannot re-offer, if the timer already exists and is not expired yet. |
| 148 if (::RegQueryValueEx(key, company, 0, 0, 0, 0) == ERROR_SUCCESS) { |
| 149 // The expired timers were already removed in CleanUpRegistryValues. |
| 150 // So if the key is not found, we can offer the Chrome. |
| 151 can_re_offer = false; |
| 152 } else if (set_flag) { |
| 153 // Set expiration date for offer as six months from today, |
| 154 // represented as a YYYYMMDD numeric value. |
| 155 SYSTEMTIME timer; |
| 156 ::GetLocalTime(&timer); |
| 157 timer.wMonth = timer.wMonth + 6; |
| 158 if (timer.wMonth > 12) { |
| 159 timer.wMonth = timer.wMonth - 12; |
| 160 timer.wYear = timer.wYear + 1; |
| 161 } |
| 162 DWORD value = timer.wYear * 10000 + timer.wMonth * 100 + timer.wDay; |
| 163 ::RegSetValueEx(key, company, 0, REG_DWORD, (LPBYTE)&value, sizeof(DWORD))
; |
| 164 } |
| 165 |
| 166 ::RegCloseKey(key); |
| 167 } |
| 168 |
| 169 return can_re_offer; |
| 170 } |
| 24 | 171 |
| 25 // Helper function to read a value from registry. Returns true if value | 172 // Helper function to read a value from registry. Returns true if value |
| 26 // is read successfully and stored in parameter value. Returns false otherwise. | 173 // is read successfully and stored in parameter value. Returns false otherwise. |
| 27 bool ReadValueFromRegistry(HKEY root_key, const wchar_t *sub_key, | 174 bool ReadValueFromRegistry(HKEY root_key, const wchar_t *sub_key, |
| 28 const wchar_t *value_name, wchar_t *value, | 175 const wchar_t *value_name, wchar_t *value, |
| 29 size_t *size) { | 176 size_t *size) { |
| 30 HKEY key; | 177 HKEY key; |
| 31 if ((::RegOpenKeyEx(root_key, sub_key, NULL, | 178 if ((::RegOpenKeyEx(root_key, sub_key, NULL, |
| 32 KEY_READ, &key) == ERROR_SUCCESS) && | 179 KEY_READ, &key) == ERROR_SUCCESS) && |
| 33 (::RegQueryValueEx(key, value_name, NULL, NULL, | 180 (::RegQueryValueEx(key, value_name, NULL, NULL, |
| (...skipping 10 matching lines...) Expand all Loading... |
| 44 size_t size = _countof(version); | 191 size_t size = _countof(version); |
| 45 if (ReadValueFromRegistry(root_key, kChromeRegClientsKey, kChromeRegVersion, | 192 if (ReadValueFromRegistry(root_key, kChromeRegClientsKey, kChromeRegVersion, |
| 46 version, &size)) | 193 version, &size)) |
| 47 return true; | 194 return true; |
| 48 return false; | 195 return false; |
| 49 } | 196 } |
| 50 | 197 |
| 51 bool IsWinXPSp1OrLater(bool* is_vista_or_later) { | 198 bool IsWinXPSp1OrLater(bool* is_vista_or_later) { |
| 52 OSVERSIONINFOEX osviex = { sizeof(OSVERSIONINFOEX) }; | 199 OSVERSIONINFOEX osviex = { sizeof(OSVERSIONINFOEX) }; |
| 53 int r = ::GetVersionEx((LPOSVERSIONINFO)&osviex); | 200 int r = ::GetVersionEx((LPOSVERSIONINFO)&osviex); |
| 54 // If this failed we're on Win9X or a pre NT4SP6 OS | 201 // If this failed we're on Win9X or a pre NT4SP6 OS. |
| 55 if (!r) | 202 if (!r) |
| 56 return false; | 203 return false; |
| 57 | 204 |
| 58 if (osviex.dwMajorVersion < 5) | 205 if (osviex.dwMajorVersion < 5) |
| 59 return false; | 206 return false; |
| 60 | 207 |
| 61 if (osviex.dwMajorVersion > 5) { | 208 if (osviex.dwMajorVersion > 5) { |
| 62 *is_vista_or_later = true; | 209 *is_vista_or_later = true; |
| 63 return true; // way beyond Windows XP; | 210 return true; // way beyond Windows XP; |
| 64 } | 211 } |
| 65 | 212 |
| 66 if (osviex.dwMinorVersion >= 1 && osviex.wServicePackMajor >= 1) | 213 if (osviex.dwMinorVersion >= 1 && osviex.wServicePackMajor >= 1) |
| 67 return true; // Windows XP SP1 or better | 214 return true; // Windows XP SP1 or better. |
| 68 | 215 |
| 69 return false; // Windows 2000, WinXP no Service Pack | 216 return false; // Windows 2000, WinXP no Service Pack. |
| 70 } | 217 } |
| 71 | 218 |
| 72 // Note this function should not be called on old Windows versions where these | 219 // Note this function should not be called on old Windows versions where these |
| 73 // Windows API are not available. We always invoke this function after checking | 220 // Windows API are not available. We always invoke this function after checking |
| 74 // that current OS is Vista or later. | 221 // that current OS is Vista or later. |
| 75 bool VerifyAdminGroup() { | 222 bool VerifyAdminGroup() { |
| 76 SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; | 223 SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; |
| 77 PSID Group; | 224 PSID Group; |
| 78 BOOL check = ::AllocateAndInitializeSid(&NtAuthority, 2, | 225 BOOL check = ::AllocateAndInitializeSid(&NtAuthority, 2, |
| 79 SECURITY_BUILTIN_DOMAIN_RID, | 226 SECURITY_BUILTIN_DOMAIN_RID, |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 161 } | 308 } |
| 162 delete[] token_user; | 309 delete[] token_user; |
| 163 } | 310 } |
| 164 ::CloseHandle(process_token); | 311 ::CloseHandle(process_token); |
| 165 } | 312 } |
| 166 ::CloseHandle(process_handle); | 313 ::CloseHandle(process_handle); |
| 167 return result; | 314 return result; |
| 168 } | 315 } |
| 169 } // namespace | 316 } // namespace |
| 170 | 317 |
| 171 #pragma comment(linker, "/EXPORT:GoogleChromeCompatibilityCheck=_GoogleChromeCom
patibilityCheck@4,PRIVATE") | 318 #pragma comment(linker, "/EXPORT:GoogleChromeCompatibilityCheck=_GoogleChromeCom
patibilityCheck@8,PRIVATE") |
| 172 DLLEXPORT BOOL __stdcall GoogleChromeCompatibilityCheck(DWORD *reasons) { | 319 DLLEXPORT BOOL __stdcall GoogleChromeCompatibilityCheck(BOOL set_flag, DWORD *re
asons) { |
| 173 DWORD local_reasons = 0; | 320 DWORD local_reasons = 0; |
| 174 | 321 |
| 175 bool is_vista_or_later = false; | 322 bool is_vista_or_later = false; |
| 176 // System requirements? | 323 // System requirements? |
| 177 if (!IsWinXPSp1OrLater(&is_vista_or_later)) | 324 if (!IsWinXPSp1OrLater(&is_vista_or_later)) |
| 178 local_reasons |= GCCC_ERROR_OSNOTSUPPORTED; | 325 local_reasons |= GCCC_ERROR_OSNOTSUPPORTED; |
| 179 | 326 |
| 180 if (IsChromeInstalled(HKEY_LOCAL_MACHINE)) | 327 if (IsChromeInstalled(HKEY_LOCAL_MACHINE)) |
| 181 local_reasons |= GCCC_ERROR_SYSTEMLEVELALREADYPRESENT; | 328 local_reasons |= GCCC_ERROR_SYSTEMLEVELALREADYPRESENT; |
| 182 | 329 |
| 183 if (IsChromeInstalled(HKEY_CURRENT_USER)) | 330 if (IsChromeInstalled(HKEY_CURRENT_USER)) |
| 184 local_reasons |= GCCC_ERROR_USERLEVELALREADYPRESENT; | 331 local_reasons |= GCCC_ERROR_USERLEVELALREADYPRESENT; |
| 185 | 332 |
| 186 if (!VerifyHKLMAccess(kChromeRegClientsKey)) { | 333 if (!VerifyHKLMAccess(kChromeRegClientsKey)) { |
| 187 local_reasons |= GCCC_ERROR_ACCESSDENIED; | 334 local_reasons |= GCCC_ERROR_ACCESSDENIED; |
| 188 } else if (is_vista_or_later && !VerifyAdminGroup()) { | 335 } else if (is_vista_or_later && !VerifyAdminGroup()) { |
| 189 // For Vista or later check for elevation since even for admin user we could | 336 // For Vista or later check for elevation since even for admin user we could |
| 190 // be running in non-elevated mode. We require integrity level High. | 337 // be running in non-elevated mode. We require integrity level High. |
| 191 local_reasons |= GCCC_ERROR_INTEGRITYLEVEL; | 338 local_reasons |= GCCC_ERROR_INTEGRITYLEVEL; |
| 192 } | 339 } |
| 193 | 340 |
| 341 // First clean up the registry keys left over previously. |
| 342 // Then only check whether we can re-offer, if everything else is OK. |
| 343 CleanUpRegistryValues(); |
| 344 if (local_reasons == 0 && !CanReOfferChrome(set_flag)) |
| 345 local_reasons |= GCCC_ERROR_ALREADYOFFERED; |
| 346 |
| 194 // Done. Copy/return results. | 347 // Done. Copy/return results. |
| 195 if (reasons != NULL) | 348 if (reasons != NULL) |
| 196 *reasons = local_reasons; | 349 *reasons = local_reasons; |
| 197 | 350 |
| 198 return (*reasons == 0); | 351 return (*reasons == 0); |
| 199 } | 352 } |
| 200 | 353 |
| 201 #pragma comment(linker, "/EXPORT:LaunchGoogleChrome=_LaunchGoogleChrome@0,PRIVAT
E") | 354 #pragma comment(linker, "/EXPORT:LaunchGoogleChrome=_LaunchGoogleChrome@0,PRIVAT
E") |
| 202 DLLEXPORT BOOL __stdcall LaunchGoogleChrome() { | 355 DLLEXPORT BOOL __stdcall LaunchGoogleChrome() { |
| 203 wchar_t launch_cmd[MAX_PATH]; | 356 wchar_t launch_cmd[MAX_PATH]; |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 282 if (!FAILED(ipl->LaunchCmdLine(launch_cmd))) | 435 if (!FAILED(ipl->LaunchCmdLine(launch_cmd))) |
| 283 ret = true; | 436 ret = true; |
| 284 ipl.Release(); | 437 ipl.Release(); |
| 285 } | 438 } |
| 286 | 439 |
| 287 if (impersonation_success) | 440 if (impersonation_success) |
| 288 ::RevertToSelf(); | 441 ::RevertToSelf(); |
| 289 ::CoUninitialize(); | 442 ::CoUninitialize(); |
| 290 return ret; | 443 return ret; |
| 291 } | 444 } |
| OLD | NEW |