| OLD | NEW |
| (Empty) |
| 1 // Copyright 2007-2010 Google Inc. | |
| 2 // | |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
| 4 // you may not use this file except in compliance with the License. | |
| 5 // You may obtain a copy of the License at | |
| 6 // | |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | |
| 8 // | |
| 9 // Unless required by applicable law or agreed to in writing, software | |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 12 // See the License for the specific language governing permissions and | |
| 13 // limitations under the License. | |
| 14 // ======================================================================== | |
| 15 | |
| 16 #include "omaha/common/config_manager.h" | |
| 17 #include <lm.h> | |
| 18 #include <shlobj.h> | |
| 19 #include <shlwapi.h> | |
| 20 #include <wininet.h> | |
| 21 #include <atlstr.h> | |
| 22 #include <atlsecurity.h> | |
| 23 #include <math.h> | |
| 24 #include "omaha/base/app_util.h" | |
| 25 #include "omaha/base/constants.h" | |
| 26 #include "omaha/base/const_addresses.h" | |
| 27 #include "omaha/base/debug.h" | |
| 28 #include "omaha/base/error.h" | |
| 29 #include "omaha/base/logging.h" | |
| 30 #include "omaha/base/scope_guard.h" | |
| 31 #include "omaha/base/string.h" | |
| 32 #include "omaha/base/time.h" | |
| 33 #include "omaha/base/utils.h" | |
| 34 #include "omaha/base/vistautil.h" | |
| 35 #include "omaha/common/app_registry_utils.h" | |
| 36 #include "omaha/common/const_group_policy.h" | |
| 37 #include "omaha/common/const_goopdate.h" | |
| 38 #include "omaha/common/oem_install_utils.h" | |
| 39 | |
| 40 namespace omaha { | |
| 41 | |
| 42 namespace { | |
| 43 | |
| 44 HRESULT GetDir(int csidl, | |
| 45 const CString& path_tail, | |
| 46 bool create_dir, | |
| 47 CString* dir) { | |
| 48 ASSERT1(dir); | |
| 49 | |
| 50 CString path; | |
| 51 HRESULT hr = GetFolderPath(csidl | CSIDL_FLAG_DONT_VERIFY, &path); | |
| 52 if (FAILED(hr)) { | |
| 53 CORE_LOG(LW, (_T("GetDir failed to find path][%d][0x%08x]"), csidl, hr)); | |
| 54 return hr; | |
| 55 } | |
| 56 if (!::PathAppend(CStrBuf(path, MAX_PATH), path_tail)) { | |
| 57 CORE_LOG(LW, (_T("GetDir failed to append path][%s][%s]"), path, path_tail))
; | |
| 58 return GOOPDATE_E_PATH_APPEND_FAILED; | |
| 59 } | |
| 60 dir->SetString(path); | |
| 61 | |
| 62 // Try to create the directory. Continue if the directory can't be created. | |
| 63 if (create_dir) { | |
| 64 hr = CreateDir(path, NULL); | |
| 65 if (FAILED(hr)) { | |
| 66 CORE_LOG(LW, (_T("[GetDir failed to create dir][%s][0x%08x]"), path, hr)); | |
| 67 } | |
| 68 } | |
| 69 return S_OK; | |
| 70 } | |
| 71 | |
| 72 // The app-specific value overrides the disable all value so read the former | |
| 73 // first. If it doesn't exist, read the "disable all" value. | |
| 74 bool GetEffectivePolicyForApp(const TCHAR* apps_default_value_name, | |
| 75 const TCHAR* app_prefix_name, | |
| 76 const GUID& app_guid, | |
| 77 DWORD* effective_policy) { | |
| 78 ASSERT1(apps_default_value_name); | |
| 79 ASSERT1(app_prefix_name); | |
| 80 ASSERT1(effective_policy); | |
| 81 | |
| 82 CString app_value_name(app_prefix_name); | |
| 83 app_value_name.Append(GuidToString(app_guid)); | |
| 84 | |
| 85 HRESULT hr = RegKey::GetValue(kRegKeyGoopdateGroupPolicy, | |
| 86 app_value_name, | |
| 87 effective_policy); | |
| 88 if (SUCCEEDED(hr)) { | |
| 89 return true; | |
| 90 } else { | |
| 91 CORE_LOG(L4, (_T("[Failed to read Group Policy value][%s]"), | |
| 92 app_value_name)); | |
| 93 } | |
| 94 | |
| 95 hr = RegKey::GetValue(kRegKeyGoopdateGroupPolicy, | |
| 96 apps_default_value_name, | |
| 97 effective_policy); | |
| 98 if (SUCCEEDED(hr)) { | |
| 99 return true; | |
| 100 } else { | |
| 101 CORE_LOG(L4, (_T("[Failed to read Group Policy value][%s]"), | |
| 102 apps_default_value_name)); | |
| 103 } | |
| 104 | |
| 105 return false; | |
| 106 } | |
| 107 | |
| 108 // Gets the raw update check period override value in seconds from the registry. | |
| 109 // The value must be processed for limits and overflow before using. | |
| 110 // Checks UpdateDev and Group Policy. | |
| 111 // Returns true if either override was successefully read. | |
| 112 bool GetLastCheckPeriodSecFromRegistry(DWORD* period_sec) { | |
| 113 ASSERT1(period_sec); | |
| 114 | |
| 115 DWORD update_dev_sec = 0; | |
| 116 if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV, | |
| 117 kRegValueLastCheckPeriodSec, | |
| 118 &update_dev_sec))) { | |
| 119 CORE_LOG(L5, (_T("['LastCheckPeriodSec' override %d]"), update_dev_sec)); | |
| 120 *period_sec = update_dev_sec; | |
| 121 return true; | |
| 122 } | |
| 123 | |
| 124 DWORD group_policy_minutes = 0; | |
| 125 if (SUCCEEDED(RegKey::GetValue(kRegKeyGoopdateGroupPolicy, | |
| 126 kRegValueAutoUpdateCheckPeriodOverrideMinutes, | |
| 127 &group_policy_minutes))) { | |
| 128 CORE_LOG(L5, (_T("[Group Policy check period override %d]"), | |
| 129 group_policy_minutes)); | |
| 130 | |
| 131 | |
| 132 *period_sec = (group_policy_minutes > UINT_MAX / 60) ? | |
| 133 UINT_MAX : | |
| 134 group_policy_minutes * 60; | |
| 135 | |
| 136 return true; | |
| 137 } | |
| 138 | |
| 139 return false; | |
| 140 } | |
| 141 | |
| 142 } // namespace | |
| 143 | |
| 144 LLock ConfigManager::lock_; | |
| 145 ConfigManager* ConfigManager::config_manager_ = NULL; | |
| 146 | |
| 147 ConfigManager* ConfigManager::Instance() { | |
| 148 __mutexScope(lock_); | |
| 149 if (!config_manager_) { | |
| 150 config_manager_ = new ConfigManager(); | |
| 151 } | |
| 152 return config_manager_; | |
| 153 } | |
| 154 | |
| 155 void ConfigManager::DeleteInstance() { | |
| 156 delete config_manager_; | |
| 157 } | |
| 158 | |
| 159 ConfigManager::ConfigManager() { | |
| 160 CString current_module_directory(app_util::GetCurrentModuleDirectory()); | |
| 161 | |
| 162 CString path; | |
| 163 HRESULT hr = GetDir(CSIDL_LOCAL_APPDATA, | |
| 164 CString(OMAHA_REL_GOOPDATE_INSTALL_DIR), | |
| 165 false, | |
| 166 &path); | |
| 167 | |
| 168 is_running_from_official_user_dir_ = | |
| 169 SUCCEEDED(hr) ? (String_StrNCmp(path, | |
| 170 current_module_directory, | |
| 171 path.GetLength(), | |
| 172 true) == 0) : | |
| 173 false; | |
| 174 | |
| 175 hr = GetDir(CSIDL_PROGRAM_FILES, | |
| 176 CString(OMAHA_REL_GOOPDATE_INSTALL_DIR), | |
| 177 false, | |
| 178 &path); | |
| 179 | |
| 180 is_running_from_official_machine_dir_ = | |
| 181 SUCCEEDED(hr) ? (String_StrNCmp(path, | |
| 182 current_module_directory, | |
| 183 path.GetLength(), | |
| 184 true) == 0) : | |
| 185 false; | |
| 186 } | |
| 187 | |
| 188 CString ConfigManager::GetUserDownloadStorageDir() const { | |
| 189 CString path; | |
| 190 VERIFY1(SUCCEEDED(GetDir(CSIDL_LOCAL_APPDATA, | |
| 191 CString(OMAHA_REL_DOWNLOAD_STORAGE_DIR), | |
| 192 true, | |
| 193 &path))); | |
| 194 return path; | |
| 195 } | |
| 196 | |
| 197 CString ConfigManager::GetUserInstallWorkingDir() const { | |
| 198 CString path; | |
| 199 VERIFY1(SUCCEEDED(GetDir(CSIDL_LOCAL_APPDATA, | |
| 200 CString(OMAHA_REL_INSTALL_WORKING_DIR), | |
| 201 true, | |
| 202 &path))); | |
| 203 return path; | |
| 204 } | |
| 205 | |
| 206 CString ConfigManager::GetUserOfflineStorageDir() const { | |
| 207 CString path; | |
| 208 VERIFY1(SUCCEEDED(GetDir(CSIDL_LOCAL_APPDATA, | |
| 209 CString(OMAHA_REL_OFFLINE_STORAGE_DIR), | |
| 210 true, | |
| 211 &path))); | |
| 212 return path; | |
| 213 } | |
| 214 | |
| 215 CString ConfigManager::GetUserGoopdateInstallDirNoCreate() const { | |
| 216 CString path; | |
| 217 VERIFY1(SUCCEEDED(GetDir(CSIDL_LOCAL_APPDATA, | |
| 218 CString(OMAHA_REL_GOOPDATE_INSTALL_DIR), | |
| 219 false, | |
| 220 &path))); | |
| 221 return path; | |
| 222 } | |
| 223 | |
| 224 CString ConfigManager::GetUserGoopdateInstallDir() const { | |
| 225 CString path; | |
| 226 VERIFY1(SUCCEEDED(GetDir(CSIDL_LOCAL_APPDATA, | |
| 227 CString(OMAHA_REL_GOOPDATE_INSTALL_DIR), | |
| 228 true, | |
| 229 &path))); | |
| 230 return path; | |
| 231 } | |
| 232 | |
| 233 bool ConfigManager::IsRunningFromUserGoopdateInstallDir() const { | |
| 234 return is_running_from_official_user_dir_; | |
| 235 } | |
| 236 | |
| 237 CString ConfigManager::GetUserCrashReportsDir() const { | |
| 238 CString path; | |
| 239 VERIFY1(SUCCEEDED(GetDir(CSIDL_LOCAL_APPDATA, | |
| 240 CString(OMAHA_REL_CRASH_DIR), | |
| 241 true, | |
| 242 &path))); | |
| 243 return path; | |
| 244 } | |
| 245 | |
| 246 CString ConfigManager::GetMachineCrashReportsDir() const { | |
| 247 CString path; | |
| 248 VERIFY1(SUCCEEDED(GetDir(CSIDL_PROGRAM_FILES, | |
| 249 CString(OMAHA_REL_CRASH_DIR), | |
| 250 true, | |
| 251 &path))); | |
| 252 return path; | |
| 253 } | |
| 254 | |
| 255 CString ConfigManager::GetMachineSecureDownloadStorageDir() const { | |
| 256 CString path; | |
| 257 VERIFY1(SUCCEEDED(GetDir(CSIDL_PROGRAM_FILES, | |
| 258 CString(OMAHA_REL_DOWNLOAD_STORAGE_DIR), | |
| 259 true, | |
| 260 &path))); | |
| 261 return path; | |
| 262 } | |
| 263 | |
| 264 CString ConfigManager::GetMachineInstallWorkingDir() const { | |
| 265 CString path; | |
| 266 VERIFY1(SUCCEEDED(GetDir(CSIDL_PROGRAM_FILES, | |
| 267 CString(OMAHA_REL_INSTALL_WORKING_DIR), | |
| 268 true, | |
| 269 &path))); | |
| 270 return path; | |
| 271 } | |
| 272 | |
| 273 CString ConfigManager::GetMachineSecureOfflineStorageDir() const { | |
| 274 CString path; | |
| 275 VERIFY1(SUCCEEDED(GetDir(CSIDL_PROGRAM_FILES, | |
| 276 CString(OMAHA_REL_OFFLINE_STORAGE_DIR), | |
| 277 true, | |
| 278 &path))); | |
| 279 return path; | |
| 280 } | |
| 281 | |
| 282 CString ConfigManager::GetTempDownloadDir() const { | |
| 283 CString temp_download_dir(app_util::GetTempDirForImpersonatedOrCurrentUser()); | |
| 284 ASSERT1(temp_download_dir); | |
| 285 HRESULT hr = CreateDir(temp_download_dir, NULL); | |
| 286 if (FAILED(hr)) { | |
| 287 CORE_LOG(LW, (_T("[GetDir failed to create dir][%s][0x%08x]"), | |
| 288 temp_download_dir, hr)); | |
| 289 } | |
| 290 return temp_download_dir; | |
| 291 } | |
| 292 | |
| 293 int ConfigManager::GetPackageCacheSizeLimitMBytes() const { | |
| 294 DWORD kDefaultCacheStorageLimit = 500; // 500 MB | |
| 295 DWORD kMaxCacheStorageLimit = 5000; // 5 GB | |
| 296 | |
| 297 DWORD cache_size_limit = 0; | |
| 298 if (FAILED(RegKey::GetValue(kRegKeyGoopdateGroupPolicy, | |
| 299 kRegValueCacheSizeLimitMBytes, | |
| 300 &cache_size_limit)) || | |
| 301 cache_size_limit > kMaxCacheStorageLimit || | |
| 302 cache_size_limit == 0) { | |
| 303 cache_size_limit = kDefaultCacheStorageLimit; | |
| 304 } | |
| 305 | |
| 306 return static_cast<int>(cache_size_limit); | |
| 307 } | |
| 308 | |
| 309 int ConfigManager::GetPackageCacheExpirationTimeDays() const { | |
| 310 DWORD kDefaultCacheLifeTimeInDays = 180; // 180 days. | |
| 311 DWORD kMaxCacheLifeTimeInDays = 1800; // Roughly 5 years. | |
| 312 | |
| 313 DWORD cache_life_limit = 0; | |
| 314 if (FAILED(RegKey::GetValue(kRegKeyGoopdateGroupPolicy, | |
| 315 kRegValueCacheLifeLimitDays, | |
| 316 &cache_life_limit)) || | |
| 317 cache_life_limit > kMaxCacheLifeTimeInDays || | |
| 318 cache_life_limit == 0) { | |
| 319 cache_life_limit = kDefaultCacheLifeTimeInDays; | |
| 320 } | |
| 321 | |
| 322 return static_cast<int>(cache_life_limit); | |
| 323 } | |
| 324 | |
| 325 CString ConfigManager::GetMachineGoopdateInstallDirNoCreate() const { | |
| 326 CString path; | |
| 327 VERIFY1(SUCCEEDED(GetDir(CSIDL_PROGRAM_FILES, | |
| 328 CString(OMAHA_REL_GOOPDATE_INSTALL_DIR), | |
| 329 false, | |
| 330 &path))); | |
| 331 return path; | |
| 332 } | |
| 333 | |
| 334 CString ConfigManager::GetMachineGoopdateInstallDir() const { | |
| 335 CString path; | |
| 336 VERIFY1(SUCCEEDED(GetDir(CSIDL_PROGRAM_FILES, | |
| 337 CString(OMAHA_REL_GOOPDATE_INSTALL_DIR), | |
| 338 true, | |
| 339 &path))); | |
| 340 return path; | |
| 341 } | |
| 342 | |
| 343 bool ConfigManager::IsRunningFromMachineGoopdateInstallDir() const { | |
| 344 return is_running_from_official_machine_dir_; | |
| 345 } | |
| 346 | |
| 347 HRESULT ConfigManager::GetPingUrl(CString* url) const { | |
| 348 ASSERT1(url); | |
| 349 | |
| 350 if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV, | |
| 351 kRegValueNamePingUrl, | |
| 352 url))) { | |
| 353 CORE_LOG(L5, (_T("['ping url' override %s]"), *url)); | |
| 354 return S_OK; | |
| 355 } | |
| 356 | |
| 357 *url = kUrlPing; | |
| 358 return S_OK; | |
| 359 } | |
| 360 | |
| 361 HRESULT ConfigManager::GetUpdateCheckUrl(CString* url) const { | |
| 362 ASSERT1(url); | |
| 363 | |
| 364 if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV, | |
| 365 kRegValueNameUrl, | |
| 366 url))) { | |
| 367 CORE_LOG(L5, (_T("['update check url' override %s]"), *url)); | |
| 368 return S_OK; | |
| 369 } | |
| 370 | |
| 371 *url = kUrlUpdateCheck; | |
| 372 return S_OK; | |
| 373 } | |
| 374 | |
| 375 HRESULT ConfigManager::GetCrashReportUrl(CString* url) const { | |
| 376 ASSERT1(url); | |
| 377 | |
| 378 if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV, | |
| 379 kRegValueNameCrashReportUrl, | |
| 380 url))) { | |
| 381 CORE_LOG(L5, (_T("['crash report url' override %s]"), *url)); | |
| 382 return S_OK; | |
| 383 } | |
| 384 | |
| 385 *url = kUrlCrashReport; | |
| 386 return S_OK; | |
| 387 } | |
| 388 | |
| 389 HRESULT ConfigManager::GetMoreInfoUrl(CString* url) const { | |
| 390 ASSERT1(url); | |
| 391 | |
| 392 if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV, | |
| 393 kRegValueNameGetMoreInfoUrl, | |
| 394 url))) { | |
| 395 CORE_LOG(L5, (_T("['more info url' override %s]"), *url)); | |
| 396 return S_OK; | |
| 397 } | |
| 398 | |
| 399 *url = kUrlMoreInfo; | |
| 400 return S_OK; | |
| 401 } | |
| 402 | |
| 403 HRESULT ConfigManager::GetUsageStatsReportUrl(CString* url) const { | |
| 404 ASSERT1(url); | |
| 405 | |
| 406 if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV, | |
| 407 kRegValueNameUsageStatsReportUrl, | |
| 408 url))) { | |
| 409 CORE_LOG(L5, (_T("['usage stats report url' override %s]"), *url)); | |
| 410 return S_OK; | |
| 411 } | |
| 412 | |
| 413 *url = kUrlUsageStatsReport; | |
| 414 return S_OK; | |
| 415 } | |
| 416 | |
| 417 // Returns the override from the registry locations if present. Otherwise, | |
| 418 // returns the default value. | |
| 419 // Default value is different value for internal users to make update checks | |
| 420 // more aggresive. | |
| 421 // Ensures returned value is between kMinLastCheckPeriodSec and INT_MAX except | |
| 422 // when the override is 0, which indicates updates are disabled. | |
| 423 int ConfigManager::GetLastCheckPeriodSec(bool* is_overridden) const { | |
| 424 ASSERT1(is_overridden); | |
| 425 DWORD registry_period_sec = 0; | |
| 426 *is_overridden = GetLastCheckPeriodSecFromRegistry(®istry_period_sec); | |
| 427 if (*is_overridden) { | |
| 428 if (0 == registry_period_sec) { | |
| 429 return 0; | |
| 430 } | |
| 431 const int period_sec = registry_period_sec > INT_MAX ? | |
| 432 INT_MAX : | |
| 433 static_cast<int>(registry_period_sec); | |
| 434 | |
| 435 if (period_sec < kMinLastCheckPeriodSec) { | |
| 436 return kMinLastCheckPeriodSec; | |
| 437 } | |
| 438 return period_sec; | |
| 439 } | |
| 440 | |
| 441 // Returns a lower value for internal users. | |
| 442 if (IsInternalUser()) { | |
| 443 return kLastCheckPeriodInternalUserSec; | |
| 444 } | |
| 445 | |
| 446 return kLastCheckPeriodSec; | |
| 447 } | |
| 448 | |
| 449 // All time values are in seconds. | |
| 450 int ConfigManager::GetTimeSinceLastCheckedSec(bool is_machine) const { | |
| 451 const uint32 now = Time64ToInt32(GetCurrent100NSTime()); | |
| 452 const uint32 last_checked = GetLastCheckedTime(is_machine); | |
| 453 if (now < last_checked) { | |
| 454 CORE_LOG(LW, (_T("[possible time warp detected]") | |
| 455 _T("[now %u][last checked %u]"), now, last_checked)); | |
| 456 } | |
| 457 const int time_difference = abs(static_cast<int>(now - last_checked)); | |
| 458 bool is_period_overridden = false; | |
| 459 CORE_LOG(L3, (_T("[now %u][last checked %u][update interval %u]") | |
| 460 _T("[time difference %u]"), | |
| 461 now, last_checked, GetLastCheckPeriodSec(&is_period_overridden), | |
| 462 time_difference)); | |
| 463 return time_difference; | |
| 464 } | |
| 465 | |
| 466 DWORD ConfigManager::GetLastCheckedTime(bool is_machine) const { | |
| 467 const TCHAR* reg_update_key = is_machine ? MACHINE_REG_UPDATE: | |
| 468 USER_REG_UPDATE; | |
| 469 DWORD last_checked_time = 0; | |
| 470 if (SUCCEEDED(RegKey::GetValue(reg_update_key, | |
| 471 kRegValueLastChecked, | |
| 472 &last_checked_time))) { | |
| 473 return last_checked_time; | |
| 474 } | |
| 475 return 0; | |
| 476 } | |
| 477 | |
| 478 HRESULT ConfigManager::SetLastCheckedTime(bool is_machine, DWORD time) const { | |
| 479 const TCHAR* reg_update_key = is_machine ? MACHINE_REG_UPDATE: | |
| 480 USER_REG_UPDATE; | |
| 481 return RegKey::SetValue(reg_update_key, kRegValueLastChecked, time); | |
| 482 } | |
| 483 | |
| 484 DWORD ConfigManager::GetInstallTime(bool is_machine) { | |
| 485 const CString client_state_key_name = | |
| 486 ConfigManager::Instance()->registry_client_state_goopdate(is_machine); | |
| 487 DWORD update_time(0); | |
| 488 if (SUCCEEDED(RegKey::GetValue(client_state_key_name, | |
| 489 kRegValueLastUpdateTimeSec, | |
| 490 &update_time))) { | |
| 491 return update_time; | |
| 492 } | |
| 493 | |
| 494 DWORD install_time(0); | |
| 495 if (SUCCEEDED(RegKey::GetValue(client_state_key_name, | |
| 496 kRegValueInstallTimeSec, | |
| 497 &install_time))) { | |
| 498 return install_time; | |
| 499 } | |
| 500 | |
| 501 return 0; | |
| 502 } | |
| 503 | |
| 504 bool ConfigManager::Is24HoursSinceInstall(bool is_machine) { | |
| 505 const int kDaySec = 24 * 60 * 60; | |
| 506 const uint32 now = Time64ToInt32(GetCurrent100NSTime()); | |
| 507 | |
| 508 const uint32 install_time = GetInstallTime(is_machine); | |
| 509 if (now < install_time) { | |
| 510 CORE_LOG(LW, (_T("[Incorrect clock time detected]") | |
| 511 _T("[now %u][install_time %u]"), now, install_time)); | |
| 512 } | |
| 513 const int time_difference = abs(static_cast<int>(now - install_time)); | |
| 514 return time_difference >= kDaySec; | |
| 515 } | |
| 516 | |
| 517 // Uses app_registry_utils because this needs to be called in the server and | |
| 518 // client and it is a best effort so locking isn't necessary. | |
| 519 bool ConfigManager::CanCollectStats(bool is_machine) const { | |
| 520 if (RegKey::HasValue(MACHINE_REG_UPDATE_DEV, kRegValueForceUsageStats)) { | |
| 521 return true; | |
| 522 } | |
| 523 | |
| 524 // TODO(omaha): This should actually be iterating over registered products | |
| 525 // rather than present ClientState keys. These are identical in most cases. | |
| 526 const TCHAR* state_key_name = registry_client_state(is_machine); | |
| 527 | |
| 528 RegKey state_key; | |
| 529 HRESULT hr = state_key.Open(state_key_name, KEY_READ); | |
| 530 if (FAILED(hr)) { | |
| 531 return false; | |
| 532 } | |
| 533 | |
| 534 int num_sub_keys = state_key.GetSubkeyCount(); | |
| 535 for (int i = 0; i < num_sub_keys; ++i) { | |
| 536 CString sub_key_name; | |
| 537 if (FAILED(state_key.GetSubkeyNameAt(i, &sub_key_name))) { | |
| 538 continue; | |
| 539 } | |
| 540 | |
| 541 if (app_registry_utils::AreAppUsageStatsEnabled(is_machine, sub_key_name)) { | |
| 542 return true; | |
| 543 } | |
| 544 } | |
| 545 | |
| 546 return false; | |
| 547 } | |
| 548 | |
| 549 // Overrides OverInstall in debug builds. | |
| 550 bool ConfigManager::CanOverInstall() const { | |
| 551 #ifdef DEBUG | |
| 552 DWORD value = 0; | |
| 553 if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV, | |
| 554 kRegValueNameOverInstall, | |
| 555 &value))) { | |
| 556 CORE_LOG(L5, (_T("['OverInstall' override %d]"), value)); | |
| 557 return value != 0; | |
| 558 } | |
| 559 #endif | |
| 560 return !OFFICIAL_BUILD; | |
| 561 } | |
| 562 | |
| 563 // Overrides AuCheckPeriodMs. Implements a lower bound value. Returns INT_MAX | |
| 564 // if the registry value exceeds INT_MAX. | |
| 565 int ConfigManager::GetAutoUpdateTimerIntervalMs() const { | |
| 566 DWORD interval(0); | |
| 567 if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV, | |
| 568 kRegValueAuCheckPeriodMs, | |
| 569 &interval))) { | |
| 570 int ret_val = 0; | |
| 571 if (interval > INT_MAX) { | |
| 572 ret_val = INT_MAX; | |
| 573 } else if (interval < kMinAUCheckPeriodMs) { | |
| 574 ret_val = kMinAUCheckPeriodMs; | |
| 575 } else { | |
| 576 ret_val = interval; | |
| 577 } | |
| 578 ASSERT1(ret_val >= kMinAUCheckPeriodMs); | |
| 579 CORE_LOG(L5, (_T("['AuCheckPeriodMs' override %d]"), interval)); | |
| 580 return ret_val; | |
| 581 } | |
| 582 | |
| 583 // Returns a lower value for internal users. | |
| 584 if (IsInternalUser()) { | |
| 585 return kAUCheckPeriodInternalUserMs; | |
| 586 } | |
| 587 | |
| 588 return kAUCheckPeriodMs; | |
| 589 } | |
| 590 | |
| 591 int ConfigManager::GetUpdateWorkerStartUpDelayMs() const { | |
| 592 int au_timer_interval_ms = GetAutoUpdateTimerIntervalMs(); | |
| 593 | |
| 594 // If the AuCheckPeriod is overriden then use that as the delay. | |
| 595 if (RegKey::HasValue(MACHINE_REG_UPDATE_DEV, kRegValueAuCheckPeriodMs)) { | |
| 596 return au_timer_interval_ms; | |
| 597 } | |
| 598 | |
| 599 int random_delay = 0; | |
| 600 if (!GenRandom(&random_delay, sizeof(random_delay))) { | |
| 601 return au_timer_interval_ms; | |
| 602 } | |
| 603 | |
| 604 // Scale the au_check_period number to be between | |
| 605 // kUpdateTimerStartupDelayMinMs and kUpdateTimerStartupDelayMaxMs. | |
| 606 int scale = kUpdateTimerStartupDelayMaxMs - kUpdateTimerStartupDelayMinMs; | |
| 607 ASSERT1(scale >= 0); | |
| 608 | |
| 609 int random_addition = abs(random_delay) % scale; | |
| 610 ASSERT1(random_addition < scale); | |
| 611 | |
| 612 au_timer_interval_ms = kUpdateTimerStartupDelayMinMs + random_addition; | |
| 613 ASSERT1(au_timer_interval_ms >= kUpdateTimerStartupDelayMinMs && | |
| 614 au_timer_interval_ms <= kUpdateTimerStartupDelayMaxMs); | |
| 615 | |
| 616 return au_timer_interval_ms; | |
| 617 } | |
| 618 | |
| 619 // Overrides CodeRedCheckPeriodMs. Implements a lower bound value. Returns | |
| 620 // INT_MAX if the registry value exceeds INT_MAX. | |
| 621 int ConfigManager::GetCodeRedTimerIntervalMs() const { | |
| 622 DWORD interval(0); | |
| 623 if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV, | |
| 624 kRegValueCrCheckPeriodMs, | |
| 625 &interval))) { | |
| 626 int ret_val = 0; | |
| 627 if (interval > INT_MAX) { | |
| 628 ret_val = INT_MAX; | |
| 629 } else if (interval < kMinCodeRedCheckPeriodMs) { | |
| 630 ret_val = kMinCodeRedCheckPeriodMs; | |
| 631 } else { | |
| 632 ret_val = interval; | |
| 633 } | |
| 634 ASSERT1(ret_val >= kMinCodeRedCheckPeriodMs); | |
| 635 CORE_LOG(L5, (_T("['CrCheckPeriodMs' override %d]"), interval)); | |
| 636 return ret_val; | |
| 637 } | |
| 638 return kCodeRedCheckPeriodMs; | |
| 639 } | |
| 640 | |
| 641 // Returns true if logging is enabled for the event type. | |
| 642 // Logging of errors and warnings is enabled by default. | |
| 643 bool ConfigManager::CanLogEvents(WORD event_type) const { | |
| 644 const TCHAR* reg_update_key = MACHINE_REG_UPDATE_DEV; | |
| 645 DWORD log_events_level = LOG_EVENT_LEVEL_NONE; | |
| 646 if (SUCCEEDED(RegKey::GetValue(reg_update_key, | |
| 647 kRegValueEventLogLevel, | |
| 648 &log_events_level))) { | |
| 649 switch (log_events_level) { | |
| 650 case LOG_EVENT_LEVEL_ALL: | |
| 651 return true; | |
| 652 case LOG_EVENT_LEVEL_WARN_AND_ERROR: | |
| 653 return event_type == EVENTLOG_ERROR_TYPE || | |
| 654 event_type == EVENTLOG_WARNING_TYPE; | |
| 655 case LOG_EVENT_LEVEL_NONE: | |
| 656 default: | |
| 657 return false; | |
| 658 } | |
| 659 } | |
| 660 | |
| 661 return event_type == EVENTLOG_ERROR_TYPE || | |
| 662 event_type == EVENTLOG_WARNING_TYPE; | |
| 663 } | |
| 664 | |
| 665 CString ConfigManager::GetTestSource() const { | |
| 666 CString test_source; | |
| 667 HRESULT hr = RegKey::GetValue(MACHINE_REG_UPDATE_DEV, | |
| 668 kRegValueTestSource, | |
| 669 &test_source); | |
| 670 if (SUCCEEDED(hr)) { | |
| 671 if (test_source.IsEmpty()) { | |
| 672 test_source = kRegValueTestSourceAuto; | |
| 673 } | |
| 674 return test_source; | |
| 675 } | |
| 676 | |
| 677 DWORD interval = 0; | |
| 678 hr = RegKey::GetValue(MACHINE_REG_UPDATE_DEV, | |
| 679 kRegValueAuCheckPeriodMs, | |
| 680 &interval); | |
| 681 if (SUCCEEDED(hr)) { | |
| 682 return kRegValueTestSourceAuto; | |
| 683 } | |
| 684 | |
| 685 #if defined(DEBUG) || !OFFICIAL_BUILD | |
| 686 test_source = kRegValueTestSourceAuto; | |
| 687 #endif | |
| 688 | |
| 689 return test_source; | |
| 690 } | |
| 691 | |
| 692 HRESULT ConfigManager::GetNetConfig(CString* net_config) { | |
| 693 ASSERT1(net_config); | |
| 694 CString val; | |
| 695 HRESULT hr = RegKey::GetValue(MACHINE_REG_UPDATE_DEV, | |
| 696 kRegValueNetConfig, | |
| 697 &val); | |
| 698 if (SUCCEEDED(hr)) { | |
| 699 *net_config = val; | |
| 700 } | |
| 701 return hr; | |
| 702 } | |
| 703 | |
| 704 // Returns false if running in the context of an OEM install or waiting for a | |
| 705 // EULA to be accepted. | |
| 706 bool ConfigManager::CanUseNetwork(bool is_machine) const { | |
| 707 DWORD eula_accepted(0); | |
| 708 HRESULT hr = RegKey::GetValue(registry_update(is_machine), | |
| 709 kRegValueOmahaEulaAccepted, | |
| 710 &eula_accepted); | |
| 711 if (SUCCEEDED(hr) && 0 == eula_accepted) { | |
| 712 CORE_LOG(L3, (_T("[CanUseNetwork][eulaaccepted=0][false]"))); | |
| 713 return false; | |
| 714 } | |
| 715 | |
| 716 if (oem_install_utils::IsOemInstalling(is_machine)) { | |
| 717 CORE_LOG(L3, (_T("[CanUseNetwork][OEM installing][false]"))); | |
| 718 return false; | |
| 719 } | |
| 720 | |
| 721 return true; | |
| 722 } | |
| 723 | |
| 724 // USE oem_install_utils::IsOemInstalling() INSTEAD in most cases. | |
| 725 bool ConfigManager::IsWindowsInstalling() const { | |
| 726 #if !OFFICIAL_BUILD | |
| 727 DWORD value = 0; | |
| 728 if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV, | |
| 729 kRegValueNameWindowsInstalling, | |
| 730 &value))) { | |
| 731 CORE_LOG(L3, (_T("['WindowsInstalling' override %d]"), value)); | |
| 732 return value != 0; | |
| 733 } | |
| 734 #endif | |
| 735 | |
| 736 return omaha::IsWindowsInstalling(); | |
| 737 } | |
| 738 | |
| 739 // Checks if the computer name ends with ".google.com" or the NetBIOS domain is | |
| 740 // "google". | |
| 741 bool ConfigManager::IsInternalUser() const { | |
| 742 CORE_LOG(L4, (_T("[ConfigManager::IsInternalUser]"))); | |
| 743 TCHAR dns_name[INTERNET_MAX_HOST_NAME_LENGTH] = {0}; | |
| 744 DWORD dns_name_size(arraysize(dns_name)); | |
| 745 if (::GetComputerNameEx(ComputerNameDnsFullyQualified, | |
| 746 dns_name, &dns_name_size)) { | |
| 747 CORE_LOG(L4, (_T("[dns name %s]"), dns_name)); | |
| 748 if (String_EndsWith(dns_name, kCompanyInternalDnsName, true)) { | |
| 749 return true; | |
| 750 } | |
| 751 } | |
| 752 | |
| 753 WKSTA_INFO_100* info = NULL; | |
| 754 int kInformationLevel = 100; | |
| 755 NET_API_STATUS status = ::NetWkstaGetInfo(NULL, | |
| 756 kInformationLevel, | |
| 757 reinterpret_cast<BYTE**>(&info)); | |
| 758 ON_SCOPE_EXIT(::NetApiBufferFree, info); | |
| 759 if (status == NERR_Success) { | |
| 760 CORE_LOG(L4, (_T("[netbios name %s]"), info->wki100_langroup)); | |
| 761 if (info->wki100_langroup && | |
| 762 _tcsicmp(info->wki100_langroup, kCompanyInternalLanGroupName) == 0) { | |
| 763 return true; | |
| 764 } | |
| 765 } | |
| 766 return false; | |
| 767 } | |
| 768 | |
| 769 bool ConfigManager::CanInstallApp(const GUID& app_guid) const { | |
| 770 // Google Update should never be checking whether it can install itself. | |
| 771 ASSERT1(!::IsEqualGUID(kGoopdateGuid, app_guid)); | |
| 772 | |
| 773 DWORD effective_policy = 0; | |
| 774 if (!GetEffectivePolicyForApp(kRegValueInstallAppsDefault, | |
| 775 kRegValueInstallAppPrefix, | |
| 776 app_guid, | |
| 777 &effective_policy)) { | |
| 778 return kInstallPolicyDefault; | |
| 779 } | |
| 780 | |
| 781 return kPolicyDisabled != effective_policy; | |
| 782 } | |
| 783 | |
| 784 // Self-updates cannot be disabled. | |
| 785 bool ConfigManager::CanUpdateApp(const GUID& app_guid, | |
| 786 bool is_manual) const { | |
| 787 if (::IsEqualGUID(kGoopdateGuid, app_guid)) { | |
| 788 return true; | |
| 789 } | |
| 790 | |
| 791 DWORD effective_policy = 0; | |
| 792 if (!GetEffectivePolicyForApp(kRegValueUpdateAppsDefault, | |
| 793 kRegValueUpdateAppPrefix, | |
| 794 app_guid, | |
| 795 &effective_policy)) { | |
| 796 return kUpdatePolicyDefault; | |
| 797 } | |
| 798 | |
| 799 if (kPolicyDisabled == effective_policy) { | |
| 800 return false; | |
| 801 } | |
| 802 if ((kPolicyManualUpdatesOnly == effective_policy) && !is_manual) { | |
| 803 return false; | |
| 804 } | |
| 805 | |
| 806 return kUpdatePolicyDefault; | |
| 807 } | |
| 808 | |
| 809 bool ConfigManager::AlwaysAllowCrashUploads() const { | |
| 810 DWORD always_allow_crash_uploads = 0; | |
| 811 RegKey::GetValue(MACHINE_REG_UPDATE_DEV, | |
| 812 kRegValueAlwaysAllowCrashUploads, | |
| 813 &always_allow_crash_uploads); | |
| 814 return always_allow_crash_uploads != 0; | |
| 815 } | |
| 816 | |
| 817 } // namespace omaha | |
| OLD | NEW |