| 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"
; | 24 const wchar_t kNoChromeOfferUntil[] = L"SOFTWARE\\Google\\No Chrome Offer Until"
; |
| 25 | 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. | 26 // Return the company name specified in the file version info resource. |
| 80 bool GetCompanyName(const wchar_t* filename, wchar_t* buffer, DWORD out_len) { | 27 bool GetCompanyName(const wchar_t* filename, wchar_t* buffer, DWORD out_len) { |
| 81 wchar_t file_version_info[8192]; | 28 wchar_t file_version_info[8192]; |
| 82 DWORD handle = 0; | 29 DWORD handle = 0; |
| 83 DWORD buffer_size = 0; | 30 DWORD buffer_size = 0; |
| 84 | 31 |
| 85 buffer_size = ::GetFileVersionInfoSize(filename, &handle); | 32 buffer_size = ::GetFileVersionInfoSize(filename, &handle); |
| 86 // Cannot stats the file or our buffer size is too small (very unlikely). | 33 // Cannot stats the file or our buffer size is too small (very unlikely). |
| 87 if (buffer_size == 0 || buffer_size > _countof(file_version_info)) | 34 if (buffer_size == 0 || buffer_size > _countof(file_version_info)) |
| 88 return false; | 35 return false; |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 137 return true; | 84 return true; |
| 138 if (!GetCompanyName(filename, company, sizeof(company))) | 85 if (!GetCompanyName(filename, company, sizeof(company))) |
| 139 return true; | 86 return true; |
| 140 | 87 |
| 141 bool can_re_offer = true; | 88 bool can_re_offer = true; |
| 142 DWORD disposition = 0; | 89 DWORD disposition = 0; |
| 143 HKEY key = NULL; | 90 HKEY key = NULL; |
| 144 if (::RegCreateKeyEx(HKEY_LOCAL_MACHINE, kNoChromeOfferUntil, | 91 if (::RegCreateKeyEx(HKEY_LOCAL_MACHINE, kNoChromeOfferUntil, |
| 145 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, | 92 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, |
| 146 NULL, &key, &disposition) == ERROR_SUCCESS) { | 93 NULL, &key, &disposition) == ERROR_SUCCESS) { |
| 94 // Get today's date, and format it as YYYYMMDD numeric value. |
| 95 SYSTEMTIME now; |
| 96 GetLocalTime(&now); |
| 97 DWORD today = now.wYear * 10000 + now.wMonth * 100 + now.wDay; |
| 98 |
| 147 // Cannot re-offer, if the timer already exists and is not expired yet. | 99 // Cannot re-offer, if the timer already exists and is not expired yet. |
| 148 if (::RegQueryValueEx(key, company, 0, 0, 0, 0) == ERROR_SUCCESS) { | 100 DWORD value_type = REG_DWORD; |
| 149 // The expired timers were already removed in CleanUpRegistryValues. | 101 DWORD value_data = 0; |
| 150 // So if the key is not found, we can offer the Chrome. | 102 DWORD value_length = sizeof(DWORD); |
| 103 if (::RegQueryValueEx(key, company, 0, &value_type, |
| 104 reinterpret_cast<LPBYTE>(&value_data), |
| 105 &value_length) == ERROR_SUCCESS && |
| 106 REG_DWORD == value_type && |
| 107 value_data > today) { |
| 108 // The time has not expired, we cannot offer Chrome. |
| 151 can_re_offer = false; | 109 can_re_offer = false; |
| 152 } else if (set_flag) { | 110 } else { |
| 153 // Set expiration date for offer as six months from today, | 111 // Delete the old or invalid value. |
| 154 // represented as a YYYYMMDD numeric value. | 112 ::RegDeleteValue(key, company); |
| 155 SYSTEMTIME timer; | 113 if (set_flag) { |
| 156 ::GetLocalTime(&timer); | 114 // Set expiration date for offer as six months from today, |
| 157 timer.wMonth = timer.wMonth + 6; | 115 // represented as a YYYYMMDD numeric value. |
| 158 if (timer.wMonth > 12) { | 116 SYSTEMTIME timer = now; |
| 159 timer.wMonth = timer.wMonth - 12; | 117 timer.wMonth = timer.wMonth + 6; |
| 160 timer.wYear = timer.wYear + 1; | 118 if (timer.wMonth > 12) { |
| 119 timer.wMonth = timer.wMonth - 12; |
| 120 timer.wYear = timer.wYear + 1; |
| 121 } |
| 122 DWORD value = timer.wYear * 10000 + timer.wMonth * 100 + timer.wDay; |
| 123 ::RegSetValueEx(key, company, 0, REG_DWORD, (LPBYTE)&value, |
| 124 sizeof(DWORD)); |
| 161 } | 125 } |
| 162 DWORD value = timer.wYear * 10000 + timer.wMonth * 100 + timer.wDay; | |
| 163 ::RegSetValueEx(key, company, 0, REG_DWORD, (LPBYTE)&value, sizeof(DWORD))
; | |
| 164 } | 126 } |
| 165 | 127 |
| 166 ::RegCloseKey(key); | 128 ::RegCloseKey(key); |
| 167 } | 129 } |
| 168 | 130 |
| 169 return can_re_offer; | 131 return can_re_offer; |
| 170 } | 132 } |
| 171 | 133 |
| 172 // Helper function to read a value from registry. Returns true if value | 134 // Helper function to read a value from registry. Returns true if value |
| 173 // is read successfully and stored in parameter value. Returns false otherwise. | 135 // is read successfully and stored in parameter value. Returns false otherwise. |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 331 local_reasons |= GCCC_ERROR_USERLEVELALREADYPRESENT; | 293 local_reasons |= GCCC_ERROR_USERLEVELALREADYPRESENT; |
| 332 | 294 |
| 333 if (!VerifyHKLMAccess(kChromeRegClientsKey)) { | 295 if (!VerifyHKLMAccess(kChromeRegClientsKey)) { |
| 334 local_reasons |= GCCC_ERROR_ACCESSDENIED; | 296 local_reasons |= GCCC_ERROR_ACCESSDENIED; |
| 335 } else if (is_vista_or_later && !VerifyAdminGroup()) { | 297 } else if (is_vista_or_later && !VerifyAdminGroup()) { |
| 336 // For Vista or later check for elevation since even for admin user we could | 298 // For Vista or later check for elevation since even for admin user we could |
| 337 // be running in non-elevated mode. We require integrity level High. | 299 // be running in non-elevated mode. We require integrity level High. |
| 338 local_reasons |= GCCC_ERROR_INTEGRITYLEVEL; | 300 local_reasons |= GCCC_ERROR_INTEGRITYLEVEL; |
| 339 } | 301 } |
| 340 | 302 |
| 341 // First clean up the registry keys left over previously. | 303 // Then only check whether we can re-offer, if everything else is OK. |
| 342 // Then only check whether we can re-offer, if everything else is OK. | 304 if (local_reasons == 0 && !CanReOfferChrome(set_flag)) |
| 343 CleanUpRegistryValues(); | 305 local_reasons |= GCCC_ERROR_ALREADYOFFERED; |
| 344 if (local_reasons == 0 && !CanReOfferChrome(set_flag)) | |
| 345 local_reasons |= GCCC_ERROR_ALREADYOFFERED; | |
| 346 | 306 |
| 347 // Done. Copy/return results. | 307 // Done. Copy/return results. |
| 348 if (reasons != NULL) | 308 if (reasons != NULL) |
| 349 *reasons = local_reasons; | 309 *reasons = local_reasons; |
| 350 | 310 |
| 351 return (*reasons == 0); | 311 return (*reasons == 0); |
| 352 } | 312 } |
| 353 | 313 |
| 354 #pragma comment(linker, "/EXPORT:LaunchGoogleChrome=_LaunchGoogleChrome@0,PRIVAT
E") | 314 #pragma comment(linker, "/EXPORT:LaunchGoogleChrome=_LaunchGoogleChrome@0,PRIVAT
E") |
| 355 DLLEXPORT BOOL __stdcall LaunchGoogleChrome() { | 315 DLLEXPORT BOOL __stdcall LaunchGoogleChrome() { |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 435 if (!FAILED(ipl->LaunchCmdLine(launch_cmd))) | 395 if (!FAILED(ipl->LaunchCmdLine(launch_cmd))) |
| 436 ret = true; | 396 ret = true; |
| 437 ipl.Release(); | 397 ipl.Release(); |
| 438 } | 398 } |
| 439 | 399 |
| 440 if (impersonation_success) | 400 if (impersonation_success) |
| 441 ::RevertToSelf(); | 401 ::RevertToSelf(); |
| 442 ::CoUninitialize(); | 402 ::CoUninitialize(); |
| 443 return ret; | 403 return ret; |
| 444 } | 404 } |
| OLD | NEW |