| 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 // For interactive instances, do not access the network before displaying the | |
| 17 // UI. This provides a better user experience - quick UI - when the network is | |
| 18 // slow. It is also required to ensure that UI displayed event is signaled | |
| 19 // before potentially waiting on a firewall prompt. | |
| 20 // | |
| 21 // Debugging notes: | |
| 22 // * Omaha initial install: | |
| 23 // /install "appguid={8A69D345-D564-463C-AFF1-A69D9E530F96}&appname=Google%
20Chrome&needsadmin=False&lang=en" // NOLINT | |
| 24 // /install "appguid={283EAF47-8817-4c2b-A801-AD1FADFB7BAA}&appname=Gears&n
eedsadmin=True&lang=en" // NOLINT | |
| 25 // * App install: | |
| 26 // /handoff "appguid={8A69D345-D564-463C-AFF1-A69D9E530F96}&appname=Google%
20Chrome&needsadmin=False&lang=en" // NOLINT | |
| 27 // /handoff "appguid={283EAF47-8817-4c2b-A801-AD1FADFB7BAA}&appname=Gears&n
eedsadmin=True&lang=en" // NOLINT | |
| 28 // * Silent install: | |
| 29 // * Add "/silent" to any of the above command lines (not to the tag). | |
| 30 // * Google Update self-update: | |
| 31 // /update | |
| 32 // * Update check for apps that need it: | |
| 33 // /ua | |
| 34 // * Core: | |
| 35 // /c | |
| 36 // * Cod Red check: | |
| 37 // /cr | |
| 38 // * Cod Red repair: | |
| 39 // /recover [/machine] | |
| 40 // * OneClick: | |
| 41 // /pi "http://www.google.com/" "/install%20%22appguid=%7B8A69D345-D564-463
C-AFF1-A69D9E530F96%7D%26lang=en%26appname=Google%2520Chrome%26needsadmin=false"
/installsource oneclick // NOLINT | |
| 42 // * COM server: | |
| 43 // -Embedding | |
| 44 | |
| 45 #include "omaha/goopdate/goopdate.h" | |
| 46 | |
| 47 #include <atlstr.h> | |
| 48 #include <new> | |
| 49 #include "base/scoped_ptr.h" | |
| 50 #include "omaha/base/app_util.h" | |
| 51 #include "omaha/base/const_object_names.h" | |
| 52 #include "omaha/base/crash_if_specific_error.h" | |
| 53 #include "omaha/base/debug.h" | |
| 54 #include "omaha/base/error.h" | |
| 55 #include "omaha/base/file.h" | |
| 56 #include "omaha/base/logging.h" | |
| 57 #include "omaha/base/module_utils.h" | |
| 58 #include "omaha/base/omaha_version.h" | |
| 59 #include "omaha/base/proc_utils.h" | |
| 60 #include "omaha/base/reg_key.h" | |
| 61 #include "omaha/base/safe_format.h" | |
| 62 #include "omaha/base/scoped_any.h" | |
| 63 #include "omaha/base/scoped_ptr_address.h" | |
| 64 #include "omaha/base/system_info.h" | |
| 65 #include "omaha/base/utils.h" | |
| 66 #include "omaha/base/vistautil.h" | |
| 67 #include "omaha/client/client_utils.h" | |
| 68 #include "omaha/client/install.h" | |
| 69 #include "omaha/client/install_apps.h" | |
| 70 #include "omaha/client/install_self.h" | |
| 71 #include "omaha/client/resource.h" // IDS_* are used in client modes only. | |
| 72 #include "omaha/client/ua.h" | |
| 73 #include "omaha/common/app_registry_utils.h" | |
| 74 #include "omaha/common/command_line.h" | |
| 75 #include "omaha/common/config_manager.h" | |
| 76 #include "omaha/common/const_cmd_line.h" | |
| 77 #include "omaha/common/const_goopdate.h" | |
| 78 #include "omaha/common/goopdate_utils.h" | |
| 79 #include "omaha/common/ping.h" | |
| 80 #include "omaha/common/lang.h" | |
| 81 #include "omaha/common/oem_install_utils.h" | |
| 82 #include "omaha/common/stats_uploader.h" | |
| 83 #include "omaha/common/webplugin_utils.h" | |
| 84 #include "omaha/core/core.h" | |
| 85 #include "omaha/core/crash_handler.h" | |
| 86 #include "omaha/goopdate/code_red_check.h" | |
| 87 #include "omaha/goopdate/crash.h" | |
| 88 #include "omaha/goopdate/google_update.h" | |
| 89 #include "omaha/goopdate/goopdate_internal.h" | |
| 90 #include "omaha/goopdate/goopdate_metrics.h" | |
| 91 #include "omaha/goopdate/resource_manager.h" | |
| 92 #include "omaha/net/net_diags.h" | |
| 93 #include "omaha/service/service_main.h" | |
| 94 #include "omaha/setup/setup_service.h" | |
| 95 #include "third_party/breakpad/src/client/windows/sender/crash_report_sender.h" | |
| 96 #include "third_party/breakpad/src/client/windows/handler/exception_handler.h" | |
| 97 | |
| 98 // TODO(omaha3): Where should we put this? In Omaha 2, it was in worker.cc. | |
| 99 // TODO(omaha): fix this clunkiness and require explicit registration of the | |
| 100 // http creators with the factory. Not ideal but better then linker options. | |
| 101 #pragma comment(linker, "/INCLUDE:_kRegisterWinHttp") | |
| 102 | |
| 103 namespace omaha { | |
| 104 | |
| 105 namespace { | |
| 106 | |
| 107 #if DEBUG | |
| 108 const TCHAR* const kBuildType = _T("dbg"); | |
| 109 #else | |
| 110 const TCHAR* const kBuildType = _T("opt"); | |
| 111 #endif | |
| 112 | |
| 113 #if OFFICIAL_BUILD | |
| 114 const TCHAR* const kOfficialBuild = _T("official"); | |
| 115 #else | |
| 116 const TCHAR* const kOfficialBuild = _T("dev"); | |
| 117 #endif | |
| 118 | |
| 119 #if DEBUG | |
| 120 // Returns true if the binary's version matches the installed version or this | |
| 121 // mode does not require the versions to match. | |
| 122 bool CheckRegisteredVersion(const CString& version, | |
| 123 bool is_machine, | |
| 124 CommandLineMode mode) { | |
| 125 switch (mode) { | |
| 126 // Modes that may run before or during installation or otherwise do not | |
| 127 // need to match the installed version. | |
| 128 case COMMANDLINE_MODE_UNKNOWN: | |
| 129 case COMMANDLINE_MODE_NOARGS: | |
| 130 case COMMANDLINE_MODE_REGSERVER: | |
| 131 case COMMANDLINE_MODE_UNREGSERVER: | |
| 132 case COMMANDLINE_MODE_NETDIAGS: | |
| 133 case COMMANDLINE_MODE_CRASH: | |
| 134 case COMMANDLINE_MODE_REPORTCRASH: | |
| 135 case COMMANDLINE_MODE_INSTALL: | |
| 136 case COMMANDLINE_MODE_UPDATE: | |
| 137 case COMMANDLINE_MODE_RECOVER: | |
| 138 case COMMANDLINE_MODE_WEBPLUGIN: | |
| 139 case COMMANDLINE_MODE_REGISTER_PRODUCT: | |
| 140 case COMMANDLINE_MODE_UNREGISTER_PRODUCT: | |
| 141 case COMMANDLINE_MODE_SERVICE_REGISTER: | |
| 142 case COMMANDLINE_MODE_SERVICE_UNREGISTER: | |
| 143 case COMMANDLINE_MODE_PING: | |
| 144 return true; | |
| 145 | |
| 146 // COM servers and services that should only run after installation. | |
| 147 case COMMANDLINE_MODE_CORE: | |
| 148 case COMMANDLINE_MODE_SERVICE: | |
| 149 case COMMANDLINE_MODE_CODE_RED_CHECK: | |
| 150 case COMMANDLINE_MODE_COMSERVER: | |
| 151 case COMMANDLINE_MODE_CRASH_HANDLER: | |
| 152 case COMMANDLINE_MODE_COMBROKER: | |
| 153 case COMMANDLINE_MODE_ONDEMAND: | |
| 154 case COMMANDLINE_MODE_MEDIUM_SERVICE: | |
| 155 | |
| 156 // Clients that should only run after installation and should match the | |
| 157 // installed version. | |
| 158 case COMMANDLINE_MODE_HANDOFF_INSTALL: | |
| 159 case COMMANDLINE_MODE_UA: | |
| 160 case COMMANDLINE_MODE_UNINSTALL: | |
| 161 | |
| 162 default: | |
| 163 // This binary's version should be the installed version. | |
| 164 CString installed_version; | |
| 165 VERIFY1(SUCCEEDED(RegKey::GetValue( | |
| 166 ConfigManager::Instance()->registry_update(is_machine), | |
| 167 kRegValueInstalledVersion, | |
| 168 &installed_version))); | |
| 169 return version == installed_version; | |
| 170 } | |
| 171 } | |
| 172 #endif | |
| 173 | |
| 174 } // namespace | |
| 175 | |
| 176 namespace detail { | |
| 177 | |
| 178 class GoopdateImpl { | |
| 179 public: | |
| 180 GoopdateImpl(Goopdate* goopdate, bool is_local_system); | |
| 181 ~GoopdateImpl(); | |
| 182 | |
| 183 HRESULT Main(HINSTANCE instance, const TCHAR* cmd_line, int cmd_show); | |
| 184 | |
| 185 HRESULT QueueUserWorkItem(UserWorkItem* work_item, uint32 flags); | |
| 186 | |
| 187 void Stop(); | |
| 188 | |
| 189 bool is_local_system() const { return is_local_system_; } | |
| 190 | |
| 191 private: | |
| 192 HRESULT DoMain(HINSTANCE instance, const TCHAR* cmd_line, int cmd_show); | |
| 193 | |
| 194 // Performs initialization that must be done as soon as the command line has | |
| 195 // been parsed and loads the resources. If this method succeeds, we can use | |
| 196 // the resources - for example, to display error messagse. | |
| 197 HRESULT InitializeGoopdateAndLoadResources(); | |
| 198 | |
| 199 // Executes the mode determined by DoMain(). | |
| 200 HRESULT ExecuteMode(bool* has_ui_been_displayed); | |
| 201 | |
| 202 // Returns whether a process is a machine process. | |
| 203 // Does not determine whether the process has the appropriate privileges. | |
| 204 bool IsMachineProcess(); | |
| 205 | |
| 206 bool ShouldCheckShutdownEvent(CommandLineMode mode); | |
| 207 bool IsShutdownEventSet(); | |
| 208 | |
| 209 HRESULT LoadResourceDllIfNecessary(CommandLineMode mode, | |
| 210 const CString& resource_dir); | |
| 211 | |
| 212 HRESULT SetUsageStatsEnable(); | |
| 213 | |
| 214 // Handles error conditions by showing UI if appropriate. | |
| 215 void HandleError(HRESULT hr, bool has_ui_been_displayed); | |
| 216 | |
| 217 // Handles response to /pi command. | |
| 218 HRESULT HandleWebPlugin(); | |
| 219 | |
| 220 // Handles responses to /cr command. | |
| 221 HRESULT HandleCodeRedCheck(); | |
| 222 | |
| 223 // Handles /report command. | |
| 224 HRESULT HandleReportCrash(); | |
| 225 | |
| 226 // Installs apps for the /handoff instance. | |
| 227 HRESULT DoHandoff(bool* has_ui_been_displayed); | |
| 228 | |
| 229 // Updates all registered apps for the /ua instance. | |
| 230 HRESULT DoUpdateAllApps(bool* has_ui_been_displayed); | |
| 231 | |
| 232 // Generates a divide by zero to trigger breakpad dump. | |
| 233 // Is only enabled in debug builds. | |
| 234 HRESULT DoCrash(); | |
| 235 | |
| 236 // Install Omaha. | |
| 237 HRESULT DoInstall(bool* has_ui_been_displayed); | |
| 238 | |
| 239 // Silently update Omaha. | |
| 240 HRESULT DoSelfUpdate(); | |
| 241 | |
| 242 // Handles the recover command in Google Update. | |
| 243 HRESULT DoRecover(); | |
| 244 | |
| 245 // Uninstalls Omaha if appropriate. | |
| 246 HRESULT HandleUninstall(); | |
| 247 | |
| 248 // Pings the Omaha server with a string. | |
| 249 HRESULT HandlePing(); | |
| 250 | |
| 251 // TODO(omaha): Reconcile the two uninstall functions and paths. | |
| 252 void MaybeUninstallGoogleUpdate(); | |
| 253 | |
| 254 // Uninstalls Google Update if a /install process failed to install itself | |
| 255 // or the app and there are no other apps registered. | |
| 256 HRESULT UninstallIfNecessary(); | |
| 257 | |
| 258 // Called by operator new or operator new[] when they cannot satisfy | |
| 259 // a request for additional storage. | |
| 260 static void OutOfMemoryHandler(); | |
| 261 | |
| 262 static HRESULT CaptureOSMetrics(); | |
| 263 | |
| 264 HINSTANCE module_instance_; // Current module instance. | |
| 265 CString cmd_line_; // Command line, as provided by the OS. | |
| 266 int cmd_show_; | |
| 267 | |
| 268 CommandLineArgs args_; // Command line options and flags. | |
| 269 | |
| 270 // True if the process belongs to a machine Omaha "session". | |
| 271 bool is_machine_; | |
| 272 bool is_local_system_; // True if running as LOCAL_SYSTEM. | |
| 273 CString this_version_; // Version of this Goopdate DLL. | |
| 274 | |
| 275 // True if Omaha has been uninstalled by the Worker. | |
| 276 bool has_uninstalled_; | |
| 277 | |
| 278 // Language identifier for the current user locale. | |
| 279 CString user_default_language_id_; | |
| 280 | |
| 281 scoped_ptr<ThreadPool> thread_pool_; | |
| 282 | |
| 283 Goopdate* goopdate_; | |
| 284 | |
| 285 DISALLOW_EVIL_CONSTRUCTORS(GoopdateImpl); | |
| 286 }; | |
| 287 | |
| 288 GoopdateImpl::GoopdateImpl(Goopdate* goopdate, bool is_local_system) | |
| 289 : module_instance_(NULL), | |
| 290 cmd_show_(0), | |
| 291 is_local_system_(is_local_system), | |
| 292 has_uninstalled_(false), | |
| 293 goopdate_(goopdate) { | |
| 294 ASSERT1(goopdate); | |
| 295 | |
| 296 ++metric_goopdate_constructor; | |
| 297 | |
| 298 // The command line needs to be parsed to accurately determine if the current | |
| 299 // process is a machine process or not. Take an upfront guess before that. | |
| 300 is_machine_ = vista_util::IsUserAdmin() && | |
| 301 goopdate_utils::IsRunningFromOfficialGoopdateDir(true); | |
| 302 | |
| 303 // Install an error-handling mechanism which gets called when new operator | |
| 304 // fails to allocate memory. | |
| 305 VERIFY1(set_new_handler(&GoopdateImpl::OutOfMemoryHandler) == 0); | |
| 306 | |
| 307 // Install the exception handler. | |
| 308 VERIFY1(SUCCEEDED(Crash::InstallCrashHandler(is_machine_))); | |
| 309 | |
| 310 // Hints network configure manager how to create its singleton. | |
| 311 NetworkConfigManager::set_is_machine(is_machine_); | |
| 312 | |
| 313 // Initialize the global metrics collection. | |
| 314 stats_report::g_global_metrics.Initialize(); | |
| 315 | |
| 316 // TODO(omaha): Support multiple HRESULT codes to crash on. | |
| 317 // TODO(omaha): Support passing in HRESULT codes via the command line, | |
| 318 // especially for "/update". | |
| 319 DWORD crash_specific_error = 0; | |
| 320 if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV, | |
| 321 kRegValueNameCrashIfSpecificError, | |
| 322 &crash_specific_error))) { | |
| 323 omaha::g_crash_specific_error = static_cast<HRESULT>(crash_specific_error); | |
| 324 } | |
| 325 | |
| 326 static const int kThreadPoolShutdownDelayMs = 60000; | |
| 327 thread_pool_.reset(new ThreadPool); | |
| 328 HRESULT hr = thread_pool_->Initialize(kThreadPoolShutdownDelayMs); | |
| 329 if (FAILED(hr)) { | |
| 330 CORE_LOG(LE, (_T("[thread_pool_->Initialize failed][0x%08x]"), hr)); | |
| 331 } | |
| 332 } | |
| 333 | |
| 334 GoopdateImpl::~GoopdateImpl() { | |
| 335 CORE_LOG(L2, (_T("[GoopdateImpl::~GoopdateImpl]"))); | |
| 336 | |
| 337 ++metric_goopdate_destructor; | |
| 338 | |
| 339 Stop(); | |
| 340 | |
| 341 // Bug 994348 does not repro anymore. | |
| 342 // If the assert fires, clean up the key, and fix the code if we have unit | |
| 343 // tests or application code that create the key. | |
| 344 ASSERT(!RegKey::HasKey(_T("HKEY_USERS\\.DEFAULT\\Software\\Google\\Update")), | |
| 345 (_T("This assert has fired because it has found the registry key at ") | |
| 346 _T("'HKEY_USERS\\.DEFAULT\\Software\\Google\\Update'. ") | |
| 347 _T("Please delete the key and report to omaha-core team if ") | |
| 348 _T("the assert fires again."))); | |
| 349 | |
| 350 // The global metrics collection must be uninitialized before the metrics | |
| 351 // destructors are called. | |
| 352 stats_report::g_global_metrics.Uninitialize(); | |
| 353 | |
| 354 // Uninstall the exception handler. Program crashes are handled by Windows | |
| 355 // Error Reporting (WER) beyond this point. | |
| 356 Crash::UninstallCrashHandler(); | |
| 357 | |
| 358 // Reset the new handler. | |
| 359 set_new_handler(NULL); | |
| 360 } | |
| 361 | |
| 362 HRESULT GoopdateImpl::QueueUserWorkItem(UserWorkItem* work_item, uint32 flags) { | |
| 363 CORE_LOG(L3, (_T("[GoopdateImpl::QueueUserWorkItem]"))); | |
| 364 ASSERT1(work_item); | |
| 365 | |
| 366 ASSERT1(thread_pool_.get()); | |
| 367 | |
| 368 return thread_pool_->QueueUserWorkItem(work_item, flags); | |
| 369 } | |
| 370 | |
| 371 void GoopdateImpl::Stop() { | |
| 372 // The thread pool destructor waits for any remaining jobs to complete. | |
| 373 thread_pool_.reset(); | |
| 374 } | |
| 375 | |
| 376 // Assumes the resources are loaded and members are initialized. | |
| 377 void GoopdateImpl::HandleError(HRESULT hr, bool has_ui_been_displayed) { | |
| 378 CORE_LOG(L3, (_T("[GoopdateImpl::HandleError][0x%x][%u]"), | |
| 379 hr, has_ui_been_displayed)); | |
| 380 | |
| 381 if (has_ui_been_displayed || | |
| 382 !internal::CanDisplayUi(args_.mode, args_.is_silent_set)) { | |
| 383 return; | |
| 384 } | |
| 385 | |
| 386 const CString& bundle_name = args_.extra.bundle_name; | |
| 387 CString primary_app_guid; | |
| 388 if (!args_.extra.apps.empty()) { | |
| 389 primary_app_guid = GuidToString(args_.extra.apps[0].app_guid); | |
| 390 } | |
| 391 | |
| 392 CString error_text; | |
| 393 switch (hr) { | |
| 394 case GOOPDATE_E_UA_ALREADY_RUNNING: | |
| 395 error_text.FormatMessage(IDS_APPLICATION_ALREADY_INSTALLING, | |
| 396 client_utils::GetUpdateAllAppsBundleName()); | |
| 397 break; | |
| 398 case OMAHA_NET_E_WINHTTP_NOT_AVAILABLE: | |
| 399 ASSERT1(!bundle_name.IsEmpty()); | |
| 400 error_text.FormatMessage(IDS_WINDOWS_IS_NOT_UP_TO_DATE, | |
| 401 bundle_name); | |
| 402 break; | |
| 403 default: | |
| 404 // TODO(omaha3): This currently assumes that any error returned here is | |
| 405 // related to Setup. | |
| 406 CString product_name; | |
| 407 VERIFY1(product_name.LoadString(IDS_PRODUCT_DISPLAY_NAME)); | |
| 408 error_text.FormatMessage(IDS_SETUP_FAILED, product_name, hr); | |
| 409 break; | |
| 410 } | |
| 411 | |
| 412 VERIFY1(client_utils::DisplayError(is_machine_, | |
| 413 bundle_name, | |
| 414 hr, | |
| 415 0, | |
| 416 error_text, | |
| 417 primary_app_guid, | |
| 418 args_.extra.language, | |
| 419 args_.extra.installation_id, | |
| 420 args_.extra.brand_code)); | |
| 421 } | |
| 422 | |
| 423 HRESULT GoopdateImpl::Main(HINSTANCE instance, | |
| 424 const TCHAR* cmd_line, | |
| 425 int cmd_show) { | |
| 426 ++metric_goopdate_main; | |
| 427 | |
| 428 HRESULT hr = DoMain(instance, cmd_line, cmd_show); | |
| 429 | |
| 430 CORE_LOG(L2, (_T("[has_uninstalled_ is %d]"), has_uninstalled_)); | |
| 431 | |
| 432 // For install processes, verify the Google Update EULA has been accepted and | |
| 433 // we can use the network unless a) the command line specifies EULA is | |
| 434 // required or b) in OEM installing mode, which also prevents network use. | |
| 435 if ((COMMANDLINE_MODE_INSTALL == args_.mode || | |
| 436 COMMANDLINE_MODE_HANDOFF_INSTALL == args_.mode) && | |
| 437 SUCCEEDED(hr)) { | |
| 438 ASSERT1(args_.is_eula_required_set || | |
| 439 ConfigManager::Instance()->CanUseNetwork(is_machine_) || | |
| 440 oem_install_utils::IsOemInstalling(is_machine_)); | |
| 441 } | |
| 442 | |
| 443 // In the /install case, clean up if Google Update and/or app install did not | |
| 444 // complete successfully. | |
| 445 // Only aggregate the metrics if there is no chance that Google Update has | |
| 446 // or may be uninstalled and the process has the appropriate permissions. | |
| 447 // Uninstall will aggregate and report the metrics as appropriate. | |
| 448 bool did_install_uninstall_fail = false; | |
| 449 if (COMMANDLINE_MODE_INSTALL == args_.mode) { | |
| 450 did_install_uninstall_fail = FAILED(UninstallIfNecessary()); | |
| 451 } else if (!has_uninstalled_) { | |
| 452 if (args_.mode == COMMANDLINE_MODE_UA) { | |
| 453 VERIFY1(SUCCEEDED(AggregateAndReportMetrics(is_machine_, false))); | |
| 454 } else if (!is_machine_ || vista_util::IsUserAdmin()) { | |
| 455 VERIFY1(SUCCEEDED(AggregateMetrics(is_machine_))); | |
| 456 } | |
| 457 } | |
| 458 | |
| 459 Worker::DeleteInstance(); | |
| 460 | |
| 461 // Uninitializing the network configuration must happen after reporting the | |
| 462 // metrics. The call succeeds even if the network has not been initialized | |
| 463 // due to errors up the execution path. | |
| 464 NetworkConfigManager::DeleteInstance(); | |
| 465 | |
| 466 if (COMMANDLINE_MODE_INSTALL == args_.mode && | |
| 467 args_.is_oem_set && | |
| 468 SUCCEEDED(hr) && | |
| 469 !oem_install_utils::IsOemInstalling(is_machine_)) { | |
| 470 ASSERT1(false); | |
| 471 hr = GOOPDATE_E_OEM_INSTALL_SUCCEEDED_BUT_NOT_IN_OEM_INSTALLING_MODE; | |
| 472 } | |
| 473 | |
| 474 // Verify that Google Update is either completely installed or uninstalled. | |
| 475 // Do not check in the following cases: | |
| 476 // * Modes that may exit during Setup, during uninstall, or while Omaha | |
| 477 // is partially installed. | |
| 478 // * The mode is unknown, which means the args were not be parsed. | |
| 479 // * /cr instance, which may exit after Omaha is uninstalled. | |
| 480 // * /install instance that would not have called Setup.Uninstall(). | |
| 481 // * /install instance when Uninstall failed for some reason since the | |
| 482 // the consistency check may expect the wrong state. | |
| 483 // * /update instance that failed due to an install/uninstall in progress. | |
| 484 if (COMMANDLINE_MODE_REGSERVER != args_.mode && | |
| 485 COMMANDLINE_MODE_UNREGSERVER != args_.mode && | |
| 486 COMMANDLINE_MODE_COMSERVER != args_.mode && | |
| 487 COMMANDLINE_MODE_CODE_RED_CHECK != args_.mode && | |
| 488 COMMANDLINE_MODE_SERVICE_REGISTER != args_.mode && | |
| 489 COMMANDLINE_MODE_SERVICE_UNREGISTER != args_.mode && | |
| 490 COMMANDLINE_MODE_UNKNOWN != args_.mode && | |
| 491 !(COMMANDLINE_MODE_INSTALL == args_.mode && | |
| 492 is_machine_ && | |
| 493 !vista_util::IsUserAdmin()) && | |
| 494 !(COMMANDLINE_MODE_UPDATE == args_.mode && | |
| 495 GOOPDATE_E_FAILED_TO_GET_LOCK == hr) && | |
| 496 !did_install_uninstall_fail) { | |
| 497 install_self::CheckInstallStateConsistency(is_machine_); | |
| 498 } | |
| 499 | |
| 500 ResourceManager::Delete(); | |
| 501 | |
| 502 return hr; | |
| 503 } | |
| 504 | |
| 505 HRESULT GoopdateImpl::DoMain(HINSTANCE instance, | |
| 506 const TCHAR* cmd_line, | |
| 507 int cmd_show) { | |
| 508 module_instance_ = instance; | |
| 509 cmd_line_ = cmd_line; | |
| 510 cmd_show_ = cmd_show; | |
| 511 | |
| 512 // The system terminates the process without displaying a retry dialog box | |
| 513 // for the user. GoogleUpdate has no user state to be saved, therefore | |
| 514 // prompting the user for input is meaningless. | |
| 515 VERIFY1(SUCCEEDED(SetProcessSilentShutdown())); | |
| 516 | |
| 517 VERIFY1(SUCCEEDED(CaptureOSMetrics())); | |
| 518 | |
| 519 InitializeVersionFromModule(module_instance_); | |
| 520 this_version_ = GetVersionString(); | |
| 521 | |
| 522 TCHAR path[MAX_PATH] = {0}; | |
| 523 VERIFY1(::GetModuleFileName(module_instance_, path, MAX_PATH)); | |
| 524 OPT_LOG(L1, (_T("[%s][version %s][%s][%s]"), | |
| 525 path, this_version_, kBuildType, kOfficialBuild)); | |
| 526 | |
| 527 CORE_LOG(L2, (_T("[is system %d]") | |
| 528 _T("[elevated admin %d]") | |
| 529 _T("[non-elevated admin %d]") | |
| 530 _T("[testsource %s]"), | |
| 531 is_local_system_, | |
| 532 vista_util::IsUserAdmin(), | |
| 533 vista_util::IsUserNonElevatedAdmin(), | |
| 534 ConfigManager::Instance()->GetTestSource())); | |
| 535 | |
| 536 HRESULT parse_hr = omaha::ParseCommandLine(cmd_line_, &args_); | |
| 537 if (FAILED(parse_hr)) { | |
| 538 CORE_LOG(LE, (_T("[Parse cmd line failed][0x%08x]"), parse_hr)); | |
| 539 args_.mode = COMMANDLINE_MODE_UNKNOWN; | |
| 540 // Continue because we want to load the resources and display an error. | |
| 541 } | |
| 542 | |
| 543 // TODO(omaha3): Interactive updates might be useful for debugging or even | |
| 544 // on-demand updates of all apps. Figure out how to expose this. For now, no | |
| 545 // install source, which should not happen normally, is used as the trigger. | |
| 546 // The simplest way to make this work is to set args_.is_silent_set | |
| 547 // accordingly. However, we also need a way for this to work for per-machine | |
| 548 // instances since IsMachineProcess() relies on being Local System. When we | |
| 549 // settle on a mechanism, we should update the parser and remove this. | |
| 550 if (args_.mode == COMMANDLINE_MODE_UA) { | |
| 551 args_.is_silent_set = !args_.install_source.IsEmpty(); | |
| 552 } | |
| 553 | |
| 554 HRESULT hr = InitializeGoopdateAndLoadResources(); | |
| 555 if (FAILED(hr)) { | |
| 556 CORE_LOG(LE, | |
| 557 (_T("[InitializeGoopdateAndLoadResources failed][0x%08x]"), hr)); | |
| 558 if (internal::CanDisplayUi(args_.mode, args_.is_silent_set)) { | |
| 559 // The resources are unavaliable, so we must use hard-coded text. | |
| 560 const TCHAR* const kMsgBoxTitle = _T("Google Installer"); | |
| 561 CString message; | |
| 562 message.Format(_T("Installation failed with error 0x%08x."), hr); | |
| 563 VERIFY1(IDOK == ::MessageBox(NULL, message, kMsgBoxTitle, MB_OK)); | |
| 564 } | |
| 565 return hr; | |
| 566 } | |
| 567 // The resources are now loaded and available if applicable for this instance. | |
| 568 // If there was no bundle name specified on the command line, we take the | |
| 569 // bundle name from the first app's name; if that has no name (or if there is | |
| 570 // no apps, as in a runtime-only install) it will be an empty string. | |
| 571 // Replace it with the localized installer name. | |
| 572 if (args_.extra.bundle_name.IsEmpty()) { | |
| 573 args_.extra.bundle_name.LoadString(IDS_PRODUCT_DISPLAY_NAME); | |
| 574 } | |
| 575 | |
| 576 CORE_LOG(L2, (_T("[can use network %d]") | |
| 577 _T("[can collect stats %d]"), | |
| 578 ConfigManager::Instance()->CanUseNetwork(is_machine_), | |
| 579 ConfigManager::Instance()->CanCollectStats(is_machine_))); | |
| 580 | |
| 581 bool has_ui_been_displayed = false; | |
| 582 | |
| 583 if (!is_machine_ && vista_util::IsElevatedWithUACMaybeOn()) { | |
| 584 CORE_LOG(LW, (_T("User GoogleUpdate is possibly running in an unsupported ") | |
| 585 _T("way, at High integrity with UAC possibly enabled."))); | |
| 586 } | |
| 587 | |
| 588 if (FAILED(parse_hr)) { | |
| 589 ASSERT1(args_.mode == COMMANDLINE_MODE_UNKNOWN); | |
| 590 hr = parse_hr; | |
| 591 } else { | |
| 592 ASSERT1(args_.mode != COMMANDLINE_MODE_UNKNOWN); | |
| 593 // TODO(omaha): I would like to pass the mode as an argument, but there | |
| 594 // are so many uses for args_.mode and they could easily creep in. Consider | |
| 595 // eliminating the args_ member. | |
| 596 hr = ExecuteMode(&has_ui_been_displayed); | |
| 597 if (FAILED(hr)) { | |
| 598 CORE_LOG(LE, (_T("[ExecuteMode failed][0x%08x]"), hr)); | |
| 599 // Continue and display error. | |
| 600 } | |
| 601 } | |
| 602 | |
| 603 if (FAILED(hr)) { | |
| 604 HandleError(hr, has_ui_been_displayed); | |
| 605 return hr; | |
| 606 } | |
| 607 | |
| 608 return S_OK; | |
| 609 } | |
| 610 | |
| 611 // Assumes the command line has been parsed. | |
| 612 HRESULT GoopdateImpl::InitializeGoopdateAndLoadResources() { | |
| 613 // IsMachineProcess requires the command line be parsed first. | |
| 614 is_machine_ = IsMachineProcess(); | |
| 615 OPT_LOG(L1, (_T("[is machine: %d]"), is_machine_)); | |
| 616 | |
| 617 if (!::SetEnvironmentVariable(kEnvVariableIsMachine, | |
| 618 is_machine_ ? _T("1") : _T("0"))) { | |
| 619 HRESULT hr = HRESULTFromLastError(); | |
| 620 CORE_LOG(LW, (_T("[::SetEnvironmentVariable failed][%s][0x%x]"), | |
| 621 kEnvVariableIsMachine, hr)); | |
| 622 } | |
| 623 | |
| 624 // After parsing the command line, reinstall the crash handler to match the | |
| 625 // state of the process. | |
| 626 if (is_machine_ != Crash::is_machine()) { | |
| 627 VERIFY1(SUCCEEDED(Crash::InstallCrashHandler(is_machine_))); | |
| 628 } | |
| 629 | |
| 630 // We have parsed the command line, and we are now resetting is_machine. | |
| 631 NetworkConfigManager::set_is_machine( | |
| 632 is_machine_ && vista_util::IsUserAdmin()); | |
| 633 | |
| 634 // Set the current directory to be the one that the DLL was launched from. | |
| 635 TCHAR module_directory[MAX_PATH] = {0}; | |
| 636 if (!GetModuleDirectory(module_instance_, module_directory)) { | |
| 637 return HRESULTFromLastError(); | |
| 638 } | |
| 639 if (!::SetCurrentDirectory(module_directory)) { | |
| 640 return HRESULTFromLastError(); | |
| 641 } | |
| 642 OPT_LOG(L3, (_T("[Current dir][%s]"), module_directory)); | |
| 643 | |
| 644 // Set the usage stats as soon as possible, which is after the command line | |
| 645 // has been parsed, so that we can report crashes and other stats. | |
| 646 VERIFY1(SUCCEEDED(SetUsageStatsEnable())); | |
| 647 | |
| 648 VERIFY1(SUCCEEDED(internal::PromoteAppEulaAccepted(is_machine_))); | |
| 649 | |
| 650 if (ShouldCheckShutdownEvent(args_.mode) && IsShutdownEventSet()) { | |
| 651 return GOOPDATE_E_SHUTDOWN_SIGNALED; | |
| 652 } | |
| 653 | |
| 654 HRESULT hr = LoadResourceDllIfNecessary(args_.mode, module_directory); | |
| 655 if (FAILED(hr)) { | |
| 656 CORE_LOG(LE, (_T("[LoadResourceDllIfNecessary failed][0x%08x]"), hr)); | |
| 657 return hr; | |
| 658 } | |
| 659 | |
| 660 return S_OK; | |
| 661 } | |
| 662 | |
| 663 // Assumes Goopdate is initialized and resources are loaded. | |
| 664 HRESULT GoopdateImpl::ExecuteMode(bool* has_ui_been_displayed) { | |
| 665 ASSERT1(has_ui_been_displayed); | |
| 666 | |
| 667 // Save the mode on the stack for post-mortem debugging purposes. | |
| 668 volatile CommandLineMode mode = args_.mode; | |
| 669 | |
| 670 user_default_language_id_ = lang::GetDefaultLanguage(is_local_system_); | |
| 671 | |
| 672 ASSERT1(CheckRegisteredVersion(GetVersionString(), is_machine_, mode)); | |
| 673 | |
| 674 #pragma warning(push) | |
| 675 // C4061: enumerator 'xxx' in switch of enum 'yyy' is not explicitly handled by | |
| 676 // a case label. | |
| 677 #pragma warning(disable : 4061) | |
| 678 switch (mode) { | |
| 679 // Delegate to the service or the core. Both have reliability requirements | |
| 680 // and resource constraints. Generally speaking, they do not use COM nor | |
| 681 // networking code. | |
| 682 case COMMANDLINE_MODE_SERVICE: | |
| 683 return omaha::Update3ServiceModule().Main(SW_HIDE); | |
| 684 | |
| 685 case COMMANDLINE_MODE_MEDIUM_SERVICE: | |
| 686 return omaha::UpdateMediumServiceModule().Main(SW_HIDE); | |
| 687 | |
| 688 case COMMANDLINE_MODE_SERVICE_REGISTER: { | |
| 689 HRESULT hr = SetupUpdate3Service::InstallService( | |
| 690 app_util::GetModulePath(NULL)); | |
| 691 if (FAILED(hr)) { | |
| 692 return hr; | |
| 693 } | |
| 694 return SetupUpdateMediumService::InstallService( | |
| 695 app_util::GetModulePath(NULL)); | |
| 696 } | |
| 697 | |
| 698 case COMMANDLINE_MODE_SERVICE_UNREGISTER: { | |
| 699 HRESULT hr = SetupUpdate3Service::UninstallService(); | |
| 700 if (FAILED(hr)) { | |
| 701 return hr; | |
| 702 } | |
| 703 return SetupUpdateMediumService::UninstallService(); | |
| 704 } | |
| 705 | |
| 706 default: { | |
| 707 scoped_co_init init_com_apt(COINIT_MULTITHREADED); | |
| 708 HRESULT hr = init_com_apt.hresult(); | |
| 709 if (FAILED(hr)) { | |
| 710 return hr; | |
| 711 } | |
| 712 | |
| 713 switch (mode) { | |
| 714 case COMMANDLINE_MODE_CORE: | |
| 715 return omaha::Core().Main(is_local_system_, | |
| 716 !args_.is_crash_handler_disabled); | |
| 717 | |
| 718 case COMMANDLINE_MODE_CRASH_HANDLER: | |
| 719 return omaha::CrashHandler().Main(is_local_system_); | |
| 720 | |
| 721 case COMMANDLINE_MODE_NOARGS: | |
| 722 return GOOPDATE_E_NO_ARGS; | |
| 723 | |
| 724 case COMMANDLINE_MODE_UNREGISTER_PRODUCT: | |
| 725 // TODO(omaha3): Eliminate the need for this mode. | |
| 726 return E_FAIL; | |
| 727 | |
| 728 case COMMANDLINE_MODE_COMBROKER: | |
| 729 return omaha::GoogleUpdate(is_machine_, | |
| 730 omaha::GoogleUpdate::kBrokerMode).Main(); | |
| 731 | |
| 732 case COMMANDLINE_MODE_ONDEMAND: | |
| 733 return omaha::GoogleUpdate( | |
| 734 is_machine_, | |
| 735 omaha::GoogleUpdate::kOnDemandMode).Main(); | |
| 736 | |
| 737 default: { | |
| 738 // Reference the network instance here so the singleton can be | |
| 739 // created before possible impersonation. | |
| 740 NetworkConfigManager::Instance(); | |
| 741 | |
| 742 switch (mode) { | |
| 743 case COMMANDLINE_MODE_WEBPLUGIN: | |
| 744 return HandleWebPlugin(); | |
| 745 | |
| 746 case COMMANDLINE_MODE_CODE_RED_CHECK: | |
| 747 return HandleCodeRedCheck(); | |
| 748 | |
| 749 case COMMANDLINE_MODE_NETDIAGS: | |
| 750 return NetDiags().Main(); | |
| 751 | |
| 752 case COMMANDLINE_MODE_REGISTER_PRODUCT: | |
| 753 // TODO(omaha3): Eliminate the need for this mode. | |
| 754 return E_FAIL; | |
| 755 | |
| 756 case COMMANDLINE_MODE_INSTALL: | |
| 757 return DoInstall(has_ui_been_displayed); | |
| 758 | |
| 759 case COMMANDLINE_MODE_UPDATE: | |
| 760 return DoSelfUpdate(); | |
| 761 | |
| 762 case COMMANDLINE_MODE_RECOVER: | |
| 763 return DoRecover(); | |
| 764 | |
| 765 case COMMANDLINE_MODE_HANDOFF_INSTALL: | |
| 766 return DoHandoff(has_ui_been_displayed); | |
| 767 | |
| 768 case COMMANDLINE_MODE_UA: | |
| 769 return DoUpdateAllApps(has_ui_been_displayed); | |
| 770 | |
| 771 case COMMANDLINE_MODE_CRASH: | |
| 772 return DoCrash(); | |
| 773 | |
| 774 case COMMANDLINE_MODE_REPORTCRASH: | |
| 775 return HandleReportCrash(); | |
| 776 | |
| 777 case COMMANDLINE_MODE_REGSERVER: | |
| 778 case COMMANDLINE_MODE_UNREGSERVER: { | |
| 779 hr = omaha::GoogleUpdate( | |
| 780 is_machine_, omaha::GoogleUpdate::kUpdate3Mode).Main(); | |
| 781 if (FAILED(hr)) { | |
| 782 return hr; | |
| 783 } | |
| 784 hr = omaha::GoogleUpdate( | |
| 785 is_machine_, omaha::GoogleUpdate::kBrokerMode).Main(); | |
| 786 if (FAILED(hr)) { | |
| 787 return hr; | |
| 788 } | |
| 789 return omaha::GoogleUpdate( | |
| 790 is_machine_, omaha::GoogleUpdate::kOnDemandMode).Main(); | |
| 791 } | |
| 792 | |
| 793 case COMMANDLINE_MODE_COMSERVER: | |
| 794 return omaha::GoogleUpdate( | |
| 795 is_machine_, omaha::GoogleUpdate::kUpdate3Mode).Main(); | |
| 796 | |
| 797 case COMMANDLINE_MODE_UNINSTALL: | |
| 798 return HandleUninstall(); | |
| 799 | |
| 800 case COMMANDLINE_MODE_PING: | |
| 801 return HandlePing(); | |
| 802 | |
| 803 default: | |
| 804 // We have a COMMANDLINE_MODE_ that isn't being handled. | |
| 805 ASSERT1(false); | |
| 806 OPT_LOG(LE, (_T("[Command line has unhandled mode]"))); | |
| 807 return E_UNEXPECTED; | |
| 808 } | |
| 809 } | |
| 810 } | |
| 811 } | |
| 812 } | |
| 813 #pragma warning(pop) | |
| 814 } | |
| 815 | |
| 816 bool GoopdateImpl::IsMachineProcess() { | |
| 817 Tristate needs_admin(TRISTATE_NONE); | |
| 818 if (!args_.extra.apps.empty()) { | |
| 819 needs_admin = args_.extra.apps[0].needs_admin != NEEDS_ADMIN_NO ? | |
| 820 TRISTATE_TRUE : TRISTATE_FALSE; | |
| 821 } | |
| 822 | |
| 823 return internal::IsMachineProcess( | |
| 824 args_.mode, | |
| 825 goopdate_utils::IsRunningFromOfficialGoopdateDir(true), | |
| 826 is_local_system_, | |
| 827 args_.is_machine_set, | |
| 828 needs_admin); | |
| 829 } | |
| 830 | |
| 831 | |
| 832 HRESULT GoopdateImpl::HandleReportCrash() { | |
| 833 ++metric_goopdate_handle_report_crash; | |
| 834 VERIFY1(SUCCEEDED(AggregateMetrics(is_machine_))); | |
| 835 | |
| 836 // Catch exceptions to avoid reporting crashes when handling a crash. | |
| 837 // TODO(omaha): maybe let Windows handle the crashes when reporting crashes | |
| 838 // in certain interactive modes. | |
| 839 HRESULT hr = S_OK; | |
| 840 __try { | |
| 841 // Crashes are uploaded always in the out-of-process case. | |
| 842 // | |
| 843 // Google Update internal crashes are handled in-process. They are uploaded | |
| 844 // only for the users that have opted in sending usage stats and when | |
| 845 // network use is allowed, and from systems that are not development | |
| 846 // nor test. | |
| 847 // This default behavior can be overriden by an UpdatedDev parameter that | |
| 848 // allows crashes to be uploaded always. | |
| 849 // | |
| 850 // All GoogleUpdate crashes are logged in the Windows event log for | |
| 851 // applications, unless the logging is disabled by the administrator. | |
| 852 ConfigManager* cm = ConfigManager::Instance(); | |
| 853 const bool can_upload_in_process = cm->AlwaysAllowCrashUploads() || | |
| 854 (cm->CanCollectStats(is_machine_) && | |
| 855 cm->CanUseNetwork(is_machine_) && | |
| 856 !goopdate_utils::IsTestSource()); | |
| 857 hr = Crash::Report(can_upload_in_process, | |
| 858 args_.crash_filename, | |
| 859 args_.custom_info_filename, | |
| 860 user_default_language_id_); | |
| 861 } | |
| 862 __except(EXCEPTION_EXECUTE_HANDLER) { | |
| 863 hr = E_FAIL; | |
| 864 } | |
| 865 return hr; | |
| 866 } | |
| 867 | |
| 868 bool GoopdateImpl::ShouldCheckShutdownEvent(CommandLineMode mode) { | |
| 869 switch (mode) { | |
| 870 // Modes that may run before or during installation or otherwise do not | |
| 871 // need to listen to shutdown. | |
| 872 case COMMANDLINE_MODE_UNKNOWN: | |
| 873 case COMMANDLINE_MODE_NOARGS: | |
| 874 case COMMANDLINE_MODE_REGSERVER: | |
| 875 case COMMANDLINE_MODE_UNREGSERVER: | |
| 876 case COMMANDLINE_MODE_NETDIAGS: | |
| 877 case COMMANDLINE_MODE_CRASH: | |
| 878 case COMMANDLINE_MODE_REPORTCRASH: | |
| 879 case COMMANDLINE_MODE_RECOVER: | |
| 880 case COMMANDLINE_MODE_SERVICE_REGISTER: | |
| 881 case COMMANDLINE_MODE_SERVICE_UNREGISTER: | |
| 882 | |
| 883 case COMMANDLINE_MODE_INSTALL: | |
| 884 case COMMANDLINE_MODE_UPDATE: | |
| 885 case COMMANDLINE_MODE_WEBPLUGIN: | |
| 886 case COMMANDLINE_MODE_CODE_RED_CHECK: | |
| 887 case COMMANDLINE_MODE_REGISTER_PRODUCT: | |
| 888 case COMMANDLINE_MODE_UNREGISTER_PRODUCT: | |
| 889 case COMMANDLINE_MODE_PING: | |
| 890 return false; | |
| 891 | |
| 892 // Modes that should honor shutdown. | |
| 893 case COMMANDLINE_MODE_CORE: | |
| 894 case COMMANDLINE_MODE_SERVICE: | |
| 895 case COMMANDLINE_MODE_COMSERVER: | |
| 896 case COMMANDLINE_MODE_CRASH_HANDLER: | |
| 897 case COMMANDLINE_MODE_COMBROKER: | |
| 898 case COMMANDLINE_MODE_ONDEMAND: | |
| 899 case COMMANDLINE_MODE_MEDIUM_SERVICE: | |
| 900 | |
| 901 case COMMANDLINE_MODE_HANDOFF_INSTALL: | |
| 902 case COMMANDLINE_MODE_UA: | |
| 903 case COMMANDLINE_MODE_UNINSTALL: | |
| 904 return true; | |
| 905 | |
| 906 default: | |
| 907 ASSERT1(false); | |
| 908 return true; | |
| 909 } | |
| 910 } | |
| 911 | |
| 912 bool GoopdateImpl::IsShutdownEventSet() { | |
| 913 NamedObjectAttributes attr; | |
| 914 GetNamedObjectAttributes(kShutdownEvent, is_machine_, &attr); | |
| 915 scoped_event shutdown_event(::OpenEvent(SYNCHRONIZE, false, attr.name)); | |
| 916 if (!shutdown_event) { | |
| 917 return false; | |
| 918 } | |
| 919 | |
| 920 return WAIT_OBJECT_0 == ::WaitForSingleObject(get(shutdown_event), 0); | |
| 921 } | |
| 922 | |
| 923 // The resource dll is loaded only in the following cases: | |
| 924 // 1. Initial setup: /install | |
| 925 // 2. Handoff install: /handoff | |
| 926 // 3. App update worker: /ua | |
| 927 // 4. Various registrations. | |
| 928 // 5. Modes where an error message needs to be displayed. | |
| 929 HRESULT GoopdateImpl::LoadResourceDllIfNecessary(CommandLineMode mode, | |
| 930 const CString& resource_dir) { | |
| 931 switch (mode) { | |
| 932 case COMMANDLINE_MODE_UNKNOWN: // Displays an error using UI. | |
| 933 case COMMANDLINE_MODE_NOARGS: // Displays an error using UI. | |
| 934 case COMMANDLINE_MODE_INSTALL: // Has UI on errors. | |
| 935 case COMMANDLINE_MODE_UPDATE: // Task and Service descriptions. | |
| 936 case COMMANDLINE_MODE_RECOVER: // Writes strings to registry. | |
| 937 case COMMANDLINE_MODE_HANDOFF_INSTALL: // Has optional UI. | |
| 938 case COMMANDLINE_MODE_UA: // Has optional UI. | |
| 939 case COMMANDLINE_MODE_COMSERVER: // Returns strings to caller. | |
| 940 case COMMANDLINE_MODE_SERVICE: // Returns strings to caller. | |
| 941 case COMMANDLINE_MODE_MEDIUM_SERVICE: // TODO(omaha): Check & explain. | |
| 942 case COMMANDLINE_MODE_SERVICE_REGISTER: // Requires the RGS resources. | |
| 943 case COMMANDLINE_MODE_SERVICE_UNREGISTER: // Requires the RGS resources. | |
| 944 case COMMANDLINE_MODE_ONDEMAND: // Worker, etc. load strings. | |
| 945 // Load the resource DLL for these modes. | |
| 946 break; | |
| 947 | |
| 948 // For the Core, the resource DLL needs to be loaded when the Core is | |
| 949 // servicing IGoogleUpdate3. The Core loads the resource DLL after the Code | |
| 950 // Red kickoff, from within core.cc. | |
| 951 case COMMANDLINE_MODE_CORE: | |
| 952 case COMMANDLINE_MODE_REGSERVER: | |
| 953 case COMMANDLINE_MODE_UNREGSERVER: | |
| 954 case COMMANDLINE_MODE_NETDIAGS: | |
| 955 case COMMANDLINE_MODE_CRASH: | |
| 956 case COMMANDLINE_MODE_REPORTCRASH: | |
| 957 case COMMANDLINE_MODE_WEBPLUGIN: | |
| 958 case COMMANDLINE_MODE_CODE_RED_CHECK: | |
| 959 case COMMANDLINE_MODE_REGISTER_PRODUCT: | |
| 960 case COMMANDLINE_MODE_UNREGISTER_PRODUCT: | |
| 961 case COMMANDLINE_MODE_CRASH_HANDLER: | |
| 962 case COMMANDLINE_MODE_COMBROKER: | |
| 963 case COMMANDLINE_MODE_UNINSTALL: | |
| 964 case COMMANDLINE_MODE_PING: | |
| 965 default: | |
| 966 // These modes do not need the resource DLL. | |
| 967 ASSERT1(!internal::CanDisplayUi(mode, false)); | |
| 968 return S_OK; | |
| 969 } | |
| 970 | |
| 971 // TODO(omaha3): Consider not using ResourceManager in this file. | |
| 972 HRESULT hr = ResourceManager::Create( | |
| 973 is_machine_, | |
| 974 resource_dir, | |
| 975 lang::GetLanguageForProcess(args_.extra.language)); | |
| 976 if (FAILED(hr)) { | |
| 977 ASSERT(false, (_T("ResourceManager::Create failed with 0x%08x"), hr)); | |
| 978 return hr; | |
| 979 } | |
| 980 | |
| 981 return S_OK; | |
| 982 } | |
| 983 | |
| 984 // Writes the information for the primary app to enable Omaha to send usage | |
| 985 // stats now. It will be set for each app in the args when they are installed. | |
| 986 HRESULT GoopdateImpl::SetUsageStatsEnable() { | |
| 987 if (args_.extra.apps.empty()) { | |
| 988 return S_OK; | |
| 989 } | |
| 990 | |
| 991 HRESULT hr = app_registry_utils::SetUsageStatsEnable( | |
| 992 args_.extra.apps[0].needs_admin != NEEDS_ADMIN_NO, | |
| 993 GuidToString(args_.extra.apps[0].app_guid), | |
| 994 args_.extra.usage_stats_enable); | |
| 995 if (FAILED(hr)) { | |
| 996 CORE_LOG(LW, (_T("[SetUsageStatsEnable failed][0x%08x]"), hr)); | |
| 997 | |
| 998 if ((HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) == hr) && | |
| 999 args_.extra.apps[0].needs_admin && | |
| 1000 !vista_util::IsUserAdmin()) { | |
| 1001 CORE_LOG(L3, (_T("[Process does not have permission to HKLM]"))); | |
| 1002 return S_OK; | |
| 1003 } | |
| 1004 return hr; | |
| 1005 } | |
| 1006 | |
| 1007 return S_OK; | |
| 1008 } | |
| 1009 | |
| 1010 HRESULT GoopdateImpl::HandleCodeRedCheck() { | |
| 1011 CORE_LOG(L2, (_T("[GoopdateImpl::HandleCodeRedCheck]"))); | |
| 1012 ++metric_cr_process_total; | |
| 1013 | |
| 1014 // Call the utils method instead of member method because we want to execute | |
| 1015 // as little code as possible. | |
| 1016 bool is_machine = internal::IsMachineProcess(args_.mode, | |
| 1017 false, // machine dir | |
| 1018 is_local_system_, | |
| 1019 args_.is_machine_set, | |
| 1020 TRISTATE_NONE); | |
| 1021 ASSERT1(IsMachineProcess() == is_machine); | |
| 1022 | |
| 1023 if (!ConfigManager::Instance()->CanUseNetwork(is_machine)) { | |
| 1024 CORE_LOG(L1, | |
| 1025 (_T("[Code Red check not sent because network use prohibited]"))); | |
| 1026 return GOOPDATE_E_CANNOT_USE_NETWORK; | |
| 1027 } | |
| 1028 | |
| 1029 CheckForCodeRed(is_machine, this_version_); | |
| 1030 return S_OK; | |
| 1031 } | |
| 1032 | |
| 1033 // Even though http://b/1135173 is fixed, there is still a possibility that only | |
| 1034 // some of the files will be copied if Setup is currently running. | |
| 1035 // TODO(omaha3): If we save and use the metainstaller for OneClick, that may | |
| 1036 // address this. | |
| 1037 | |
| 1038 // If we're called with the /webplugin command, we need to handle it and exit. | |
| 1039 // This is called from the browser and the command line arguments come from the | |
| 1040 // website so we need to be restrictive of what we let past. If everything from | |
| 1041 // the plugin is valid, we'll relaunch goopdate with the proper commands. | |
| 1042 HRESULT GoopdateImpl::HandleWebPlugin() { | |
| 1043 return webplugin_utils::DoOneClickInstall(args_); | |
| 1044 } | |
| 1045 | |
| 1046 HRESULT GoopdateImpl::DoInstall(bool* has_ui_been_displayed) { | |
| 1047 OPT_LOG(L1, (_T("[GoopdateImpl::DoInstall]"))); | |
| 1048 ASSERT1(has_ui_been_displayed); | |
| 1049 | |
| 1050 // Some /install command lines, such as /silent /install will not necessarily | |
| 1051 // have an install source. To differentiate these from other sources, such as | |
| 1052 // other clients using the COM API, specify a generic source for /install. | |
| 1053 // TODO(omaha3): Updating two types of command line/args is undesirable, and | |
| 1054 // this does not use CommandLineBuilder. This could be addressed in several | |
| 1055 // ways. See the TODO above install.cc::LaunchHandoffProcess(). | |
| 1056 ASSERT1(args_.mode == COMMANDLINE_MODE_INSTALL); | |
| 1057 CString install_command_line = cmd_line_; | |
| 1058 CommandLineArgs install_args = args_; | |
| 1059 if (args_.install_source.IsEmpty()) { | |
| 1060 ASSERT1(-1 == cmd_line_.Find(kCmdLineInstallSource)); | |
| 1061 SafeCStringAppendFormat(&install_command_line, _T(" /%s %s"), | |
| 1062 kCmdLineInstallSource, | |
| 1063 kCmdLineInstallSource_InstallDefault); | |
| 1064 install_args.install_source = kCmdLineInstallSource_InstallDefault; | |
| 1065 } | |
| 1066 | |
| 1067 HRESULT hr = S_OK; | |
| 1068 if (args_.is_oem_set) { | |
| 1069 hr = OemInstall(!args_.is_silent_set, // is_interactive | |
| 1070 !args_.extra.runtime_only, // is_app_install | |
| 1071 args_.is_eula_required_set, | |
| 1072 args_.is_install_elevated, | |
| 1073 install_command_line, | |
| 1074 install_args, | |
| 1075 &is_machine_, | |
| 1076 has_ui_been_displayed); | |
| 1077 } else { | |
| 1078 hr = Install(!args_.is_silent_set, // is_interactive | |
| 1079 !args_.extra.runtime_only, // is_app_install | |
| 1080 args_.is_eula_required_set, | |
| 1081 false, | |
| 1082 args_.is_install_elevated, | |
| 1083 install_command_line, | |
| 1084 install_args, | |
| 1085 &is_machine_, | |
| 1086 has_ui_been_displayed); | |
| 1087 } | |
| 1088 | |
| 1089 if (FAILED(hr)) { | |
| 1090 CORE_LOG(LE, (_T("[Install failed][0x%08x]"), hr)); | |
| 1091 return hr; | |
| 1092 } | |
| 1093 | |
| 1094 return S_OK; | |
| 1095 } | |
| 1096 | |
| 1097 HRESULT GoopdateImpl::DoSelfUpdate() { | |
| 1098 OPT_LOG(L1, (_T("[GoopdateImpl::DoSelfUpdate]"))); | |
| 1099 | |
| 1100 HRESULT hr = install_self::UpdateSelf(is_machine_, args_.session_id); | |
| 1101 if (FAILED(hr)) { | |
| 1102 CORE_LOG(LE, (_T("[UpdateSelf failed][0x%08x]"), hr)); | |
| 1103 return hr; | |
| 1104 } | |
| 1105 | |
| 1106 return S_OK; | |
| 1107 } | |
| 1108 | |
| 1109 // Attempts to launch the repair file elevated using the MSP. If elevation is | |
| 1110 // not needed or fails, attempts to install without elevating. | |
| 1111 // The code_red_metainstaller_path arg is the repair file. | |
| 1112 HRESULT GoopdateImpl::DoRecover() { | |
| 1113 OPT_LOG(L1, (_T("[GoopdateImpl::DoRecover()]"))); | |
| 1114 | |
| 1115 // TODO(omaha3): Enable. Maybe build without the builder. | |
| 1116 #if 0 | |
| 1117 CommandLineBuilder builder(COMMANDLINE_MODE_UPDATE); | |
| 1118 | |
| 1119 HRESULT hr = S_OK; | |
| 1120 if (LaunchRepairFileElevated(is_machine_, | |
| 1121 args_.code_red_metainstaller_path, | |
| 1122 builder.GetCommandLineArgs(), | |
| 1123 &hr)) { | |
| 1124 ASSERT1(SUCCEEDED(hr)); | |
| 1125 return S_OK; | |
| 1126 } | |
| 1127 #else | |
| 1128 HRESULT hr = S_OK; | |
| 1129 #endif | |
| 1130 | |
| 1131 if (FAILED(hr)) { | |
| 1132 OPT_LOG(LW, (_T("[LaunchRepairFileElevated failed][0x%08x]"), hr)); | |
| 1133 } | |
| 1134 | |
| 1135 hr = install_self::Repair(is_machine_); | |
| 1136 if (FAILED(hr)) { | |
| 1137 OPT_LOG(LE, (_T("[Non-elevated repair failed][0x%08x]"), hr)); | |
| 1138 return hr; | |
| 1139 } | |
| 1140 | |
| 1141 return S_OK; | |
| 1142 } | |
| 1143 | |
| 1144 // Clears the EULA flag in the handoff instance in case an older installer that | |
| 1145 // does not know about the EULA flag is used to launch the install. | |
| 1146 // Failing to clear flag fails installation because this would prevent updates. | |
| 1147 HRESULT GoopdateImpl::DoHandoff(bool* has_ui_been_displayed) { | |
| 1148 OPT_LOG(L1, (_T("[GoopdateImpl::DoHandoff]"))); | |
| 1149 ASSERT1(has_ui_been_displayed); | |
| 1150 | |
| 1151 if (!args_.is_eula_required_set) { | |
| 1152 HRESULT hr = install_self::SetEulaAccepted(is_machine_); | |
| 1153 if (FAILED(hr)) { | |
| 1154 CORE_LOG(LE, (_T("[install_self::SetEulaAccepted failed][0x%08x]"), hr)); | |
| 1155 return hr; | |
| 1156 } | |
| 1157 } | |
| 1158 | |
| 1159 HRESULT hr = InitializeClientSecurity(); | |
| 1160 if (FAILED(hr)) { | |
| 1161 return hr; | |
| 1162 } | |
| 1163 | |
| 1164 // If /sessionid wasn't specified on the command line, generate a random GUID | |
| 1165 // to use for the session ID. (This can happen if a metainstaller from the | |
| 1166 // prior version does a handoff to a newer version.) | |
| 1167 CString session_id = args_.session_id; | |
| 1168 if (session_id.IsEmpty()) { | |
| 1169 VERIFY1(SUCCEEDED(GetGuid(&session_id))); | |
| 1170 } | |
| 1171 | |
| 1172 hr = InstallApps(is_machine_, | |
| 1173 !args_.is_silent_set, // is_interactive. | |
| 1174 !args_.is_eula_required_set, // is_eula_accepted. | |
| 1175 args_.is_oem_set, | |
| 1176 args_.is_offline_set, | |
| 1177 args_.offline_dir, | |
| 1178 args_.extra, | |
| 1179 args_.install_source, | |
| 1180 session_id, | |
| 1181 has_ui_been_displayed); | |
| 1182 if (FAILED(hr)) { | |
| 1183 CORE_LOG(LE, (_T("[Install failed][0x%08x]"), hr)); | |
| 1184 return hr; | |
| 1185 } | |
| 1186 | |
| 1187 return S_OK; | |
| 1188 } | |
| 1189 | |
| 1190 HRESULT GoopdateImpl::DoUpdateAllApps(bool* has_ui_been_displayed ) { | |
| 1191 OPT_LOG(L1, (_T("[GoopdateImpl::DoUpdateAllApps]"))); | |
| 1192 ASSERT1(has_ui_been_displayed); | |
| 1193 | |
| 1194 bool is_interactive_update = !args_.is_silent_set; | |
| 1195 | |
| 1196 // TODO(omaha3): Interactive is used as an indication of an on-demand request. | |
| 1197 // It might also be useful to allow on-demand silent update requests. | |
| 1198 // This was a request when we added the ability to disable updates. | |
| 1199 // TODO(omaha3): These on-demand requests should also allow updates if the | |
| 1200 // app update policy is set to on-demand in addition to silent auto. | |
| 1201 const bool is_on_demand = is_interactive_update; | |
| 1202 | |
| 1203 CString install_source = args_.install_source; | |
| 1204 | |
| 1205 if (is_on_demand && install_source.IsEmpty()) { | |
| 1206 // Set an install source for interactive/on-demand update all apps. | |
| 1207 install_source = kCmdLineInstallSource_OnDemandUA; | |
| 1208 } | |
| 1209 | |
| 1210 // TODO(omaha): Consider moving InitializeClientSecurity calls inside | |
| 1211 // install_apps.cc or maybe to update3_utils::CreateGoogleUpdate3Class(). | |
| 1212 HRESULT hr = InitializeClientSecurity(); | |
| 1213 if (FAILED(hr)) { | |
| 1214 ASSERT1(false); | |
| 1215 return is_interactive_update ? hr : S_OK; | |
| 1216 } | |
| 1217 | |
| 1218 hr = UpdateApps(is_machine_, | |
| 1219 is_interactive_update, | |
| 1220 is_on_demand, | |
| 1221 install_source, | |
| 1222 args_.extra.language, | |
| 1223 has_ui_been_displayed); | |
| 1224 OPT_LOG(L2, (_T("[Update all apps process finished][0x%x]"), hr)); | |
| 1225 | |
| 1226 // The UA worker always returns S_OK. UA can be launched by the scheduled task | |
| 1227 // or the core, neither of which wait for a return code. On Vista, returning | |
| 1228 // an error code from the scheduled task reportedly causes issues with the | |
| 1229 // task scheduler in rare cases, so returning S_OK helps with that as well. | |
| 1230 // However, in interactive cases, we should return the actual error so that it | |
| 1231 // can be reported to the user if necessary. | |
| 1232 return is_interactive_update ? hr : S_OK; | |
| 1233 } | |
| 1234 | |
| 1235 HRESULT GoopdateImpl::DoCrash() { | |
| 1236 #if DEBUG | |
| 1237 return static_cast<HRESULT>(Crash::CrashNow()); | |
| 1238 #else | |
| 1239 return S_OK; | |
| 1240 #endif | |
| 1241 } | |
| 1242 | |
| 1243 HRESULT GoopdateImpl::HandleUninstall() { | |
| 1244 // TODO(omaha3): Why don't we always acquire this lock before uninstalling? | |
| 1245 // We don't in the /install case. I guess it's important that we uninstall | |
| 1246 // the first time in that case, but there's a chance that the case in the | |
| 1247 // referenced bug could occur while a user is installing. | |
| 1248 | |
| 1249 // Attempt a conditional uninstall and always return S_OK to avoid | |
| 1250 // executing error handling code in the case of an actual uninstall. | |
| 1251 // Do not attempt to uninstall if MSI is busy to avoid spurious uninstalls. | |
| 1252 // See http://b/1436223. The call to WaitForMSIExecute blocks with a | |
| 1253 // timeout. It is better to block here than block while holding the setup | |
| 1254 // lock. | |
| 1255 HRESULT hr = WaitForMSIExecute(kWaitForMSIExecuteMs); | |
| 1256 CORE_LOG(L2, (_T("[WaitForMSIExecute returned 0x%08x]"), hr)); | |
| 1257 if (SUCCEEDED(hr)) { | |
| 1258 MaybeUninstallGoogleUpdate(); | |
| 1259 } | |
| 1260 return S_OK; | |
| 1261 } | |
| 1262 | |
| 1263 HRESULT GoopdateImpl::HandlePing() { | |
| 1264 return Ping::HandlePing(is_machine_, args_.ping_string); | |
| 1265 } | |
| 1266 | |
| 1267 // TODO(omaha3): In Omaha 2, this was also called when /ig failed. There is a | |
| 1268 // separate call to UninstallSelf for /install in goopdate.cc. Should we call | |
| 1269 // this instead to ensure we ping? Should we try to only call from one location? | |
| 1270 // If we move it, make sure it is called regardless of LastChecked. See | |
| 1271 // http://b/2663423. | |
| 1272 | |
| 1273 // Uninstall is a tricky use case. Uninstall can primarily happen in three cases | |
| 1274 // and there are two mechanisms to uninstall. The cases in which Omaha | |
| 1275 // uninstalls are: | |
| 1276 // 1. The last registered application uninstalls. If Omaha is long-running, | |
| 1277 // Omaha monitors the Client keys and it will trigger an immediate uninstall in | |
| 1278 // this case. | |
| 1279 // 2. The core starts an update worker, if there are no registered | |
| 1280 // applications, the update worker will do the uninstall. | |
| 1281 // 3. An error, including user cancel, happens during Omaha or app installation | |
| 1282 // and there are no registered applications. | |
| 1283 // The uninstall is implemented in terms of the following mechanisms: | |
| 1284 // * An update worker launched with "/ua /uninstalled" by the core, in the | |
| 1285 // first two cases above. | |
| 1286 // * A direct uninstall, in the case of errors or user cancellations, in the | |
| 1287 // last case above. | |
| 1288 // | |
| 1289 // Omaha can uninstall only if there are no install workers running and no | |
| 1290 // registered applications. This check is done under the setup lock protection. | |
| 1291 // In addition, the uninstall worker takes the update worker lock. Acquiring | |
| 1292 // this lock is important since the silent installers can modify the | |
| 1293 // registration of apps and trigger uninstalls workers. Therefore, both | |
| 1294 // setup lock and the update worker locks are needed. | |
| 1295 // | |
| 1296 // In the direct uninstall case there is a small race condition, since there is | |
| 1297 // no other single lock that can be acquired to prevent changes to the | |
| 1298 // application registration. The code looks for install workers but the test is | |
| 1299 // racy if not protected by locks. | |
| 1300 void GoopdateImpl::MaybeUninstallGoogleUpdate() { | |
| 1301 CORE_LOG(L1, (_T("[MaybeUninstallGoogleUpdate]"))); | |
| 1302 has_uninstalled_ = | |
| 1303 !!SUCCEEDED(install_self::UninstallSelf(is_machine_, true)); | |
| 1304 } | |
| 1305 | |
| 1306 // In dbg builds, also checks the post conditions of a /install process to | |
| 1307 // ensure that the registry is correctly populated or has been cleaned up. | |
| 1308 HRESULT GoopdateImpl::UninstallIfNecessary() { | |
| 1309 ASSERT1(COMMANDLINE_MODE_INSTALL == args_.mode); | |
| 1310 ASSERT(!has_uninstalled_, (_T("Worker doesn't uninstall in /install mode"))); | |
| 1311 | |
| 1312 if (is_machine_ && !vista_util::IsUserAdmin()) { | |
| 1313 // The non-elevated instance, so do not try to uninstall. | |
| 1314 return S_OK; | |
| 1315 } else { | |
| 1316 CORE_LOG(L2, (_T("[GoopdateImpl::Main /install][Uninstall if necessary]"))); | |
| 1317 // COM must be initialized in order to uninstall the scheduled task(s). | |
| 1318 scoped_co_init init_com_apt(COINIT_MULTITHREADED); | |
| 1319 return install_self::UninstallSelf(is_machine_, false); | |
| 1320 } | |
| 1321 } | |
| 1322 | |
| 1323 void GoopdateImpl::OutOfMemoryHandler() { | |
| 1324 ::RaiseException(EXCEPTION_ACCESS_VIOLATION, | |
| 1325 EXCEPTION_NONCONTINUABLE, | |
| 1326 0, | |
| 1327 NULL); | |
| 1328 } | |
| 1329 | |
| 1330 HRESULT GoopdateImpl::CaptureOSMetrics() { | |
| 1331 int major_version(0); | |
| 1332 int minor_version(0); | |
| 1333 int service_pack_major(0); | |
| 1334 int service_pack_minor(0); | |
| 1335 TCHAR name[MAX_PATH] = {0}; | |
| 1336 | |
| 1337 HRESULT hr = SystemInfo::GetSystemVersion(&major_version, | |
| 1338 &minor_version, | |
| 1339 &service_pack_major, | |
| 1340 &service_pack_minor, | |
| 1341 name, | |
| 1342 arraysize(name)); | |
| 1343 if (SUCCEEDED(hr)) { | |
| 1344 metric_windows_major_version = major_version; | |
| 1345 metric_windows_minor_version = minor_version; | |
| 1346 metric_windows_sp_major_version = service_pack_major; | |
| 1347 metric_windows_sp_minor_version = service_pack_minor; | |
| 1348 } | |
| 1349 | |
| 1350 return hr; | |
| 1351 } | |
| 1352 | |
| 1353 } // namespace detail | |
| 1354 | |
| 1355 namespace internal { | |
| 1356 | |
| 1357 // TODO(omaha3): Consider moving to app_registry_utils. | |
| 1358 // Returns early if Google Update's EULA is already accepted, as indicated by | |
| 1359 // the lack of eulaaccepted in the Update key. | |
| 1360 // The apps' values are not modified or deleted. | |
| 1361 HRESULT PromoteAppEulaAccepted(bool is_machine) { | |
| 1362 const TCHAR* update_key_name = | |
| 1363 ConfigManager::Instance()->registry_update(is_machine); | |
| 1364 if (!RegKey::HasValue(update_key_name, kRegValueOmahaEulaAccepted)) { | |
| 1365 return S_OK; | |
| 1366 } | |
| 1367 | |
| 1368 const TCHAR* state_key_name = | |
| 1369 ConfigManager::Instance()->registry_client_state(is_machine); | |
| 1370 | |
| 1371 RegKey state_key; | |
| 1372 HRESULT hr = state_key.Open(state_key_name, KEY_READ); | |
| 1373 if (FAILED(hr)) { | |
| 1374 if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) { | |
| 1375 return S_FALSE; | |
| 1376 } | |
| 1377 return hr; | |
| 1378 } | |
| 1379 | |
| 1380 // TODO(omaha): This should actually be iterating over registered products | |
| 1381 // rather than present ClientState keys. These are identical in most cases. | |
| 1382 int num_sub_keys = state_key.GetSubkeyCount(); | |
| 1383 for (int i = 0; i < num_sub_keys; ++i) { | |
| 1384 CString sub_key_name; | |
| 1385 if (FAILED(state_key.GetSubkeyNameAt(i, &sub_key_name))) { | |
| 1386 continue; | |
| 1387 } | |
| 1388 | |
| 1389 if (app_registry_utils::IsAppEulaAccepted(is_machine, sub_key_name, true)) { | |
| 1390 ASSERT1(kGoogleUpdateAppId != sub_key_name); | |
| 1391 return install_self::SetEulaAccepted(is_machine); | |
| 1392 } | |
| 1393 } | |
| 1394 | |
| 1395 return S_OK; | |
| 1396 } | |
| 1397 | |
| 1398 // TODO(omaha): Use a registry override instead. | |
| 1399 #if !OFFICIAL_BUILD | |
| 1400 bool IsOmahaShellRunningFromStaging() { | |
| 1401 return !app_util::GetModuleName(NULL).CompareNoCase(kOmahaShellFileName) && | |
| 1402 app_util::GetModuleDirectory(NULL).Right(_tcslen(_T("staging"))) == | |
| 1403 _T("staging"); | |
| 1404 } | |
| 1405 #endif | |
| 1406 | |
| 1407 // TODO(omaha): needs_admin is only used for one case. Can we avoid it? | |
| 1408 bool IsMachineProcess(CommandLineMode mode, | |
| 1409 bool is_running_from_official_machine_directory, | |
| 1410 bool is_local_system, | |
| 1411 bool is_machine_override, | |
| 1412 Tristate needs_admin) { | |
| 1413 switch (mode) { | |
| 1414 // These "install" operations may not be running from the installed | |
| 1415 // location. | |
| 1416 case COMMANDLINE_MODE_INSTALL: | |
| 1417 case COMMANDLINE_MODE_HANDOFF_INSTALL: | |
| 1418 case COMMANDLINE_MODE_REGISTER_PRODUCT: | |
| 1419 case COMMANDLINE_MODE_UNREGISTER_PRODUCT: | |
| 1420 ASSERT1(TRISTATE_NONE != needs_admin); | |
| 1421 return TRISTATE_TRUE == needs_admin; | |
| 1422 | |
| 1423 // The following is a Code Red repair executable, which runs from temp dir. | |
| 1424 case COMMANDLINE_MODE_RECOVER: | |
| 1425 return is_machine_override; | |
| 1426 | |
| 1427 // The following always runs as the user and may provide UI for on-demand | |
| 1428 // installs and browser launches. | |
| 1429 // The install location determines user vs. machine. | |
| 1430 case COMMANDLINE_MODE_COMSERVER: | |
| 1431 case COMMANDLINE_MODE_ONDEMAND: | |
| 1432 #if !OFFICIAL_BUILD | |
| 1433 // Return machine == true. This is to facilitate unit tests such as | |
| 1434 // GoogleUpdateCoreTest.LaunchCmdElevated_LocalServerRegistered. | |
| 1435 if (IsOmahaShellRunningFromStaging()) { | |
| 1436 return true; | |
| 1437 } | |
| 1438 #endif | |
| 1439 | |
| 1440 ASSERT1(goopdate_utils::IsRunningFromOfficialGoopdateDir(false) || | |
| 1441 goopdate_utils::IsRunningFromOfficialGoopdateDir(true) || | |
| 1442 _T("omaha_unittest.exe") == app_util::GetCurrentModuleName() || | |
| 1443 _T("GoogleUpdate_unsigned.exe") == | |
| 1444 app_util::GetModuleName(NULL)); // Running in debugger. | |
| 1445 return is_running_from_official_machine_directory; | |
| 1446 | |
| 1447 // The broker forwarder is elevatable and always runs as the user it was | |
| 1448 // created as. | |
| 1449 case COMMANDLINE_MODE_COMBROKER: | |
| 1450 return is_running_from_official_machine_directory; | |
| 1451 | |
| 1452 // The following always runs as the user and is user-initiated. | |
| 1453 case COMMANDLINE_MODE_WEBPLUGIN: | |
| 1454 // The install location determines user vs. machine. | |
| 1455 // This may not be the desired value when doing a cross-install or using | |
| 1456 // the opposite plugin (i.e. user plugin is often used before the machine | |
| 1457 // one). | |
| 1458 ASSERT1(goopdate_utils::IsRunningFromOfficialGoopdateDir(false) || | |
| 1459 goopdate_utils::IsRunningFromOfficialGoopdateDir(true) || | |
| 1460 _T("omaha_unittest.exe") == app_util::GetCurrentModuleName()); | |
| 1461 return is_running_from_official_machine_directory; | |
| 1462 | |
| 1463 // The following all run silently as the user for user installs or Local | |
| 1464 // System for machine installs. | |
| 1465 case COMMANDLINE_MODE_UPDATE: | |
| 1466 case COMMANDLINE_MODE_CODE_RED_CHECK: | |
| 1467 return is_local_system; | |
| 1468 | |
| 1469 // The following all run silently as the user for user installs or Local | |
| 1470 // System for machine installs. | |
| 1471 case COMMANDLINE_MODE_UA: | |
| 1472 return is_local_system ? true : is_machine_override; | |
| 1473 | |
| 1474 // /ua runs silently as the user for user installs or Local System for | |
| 1475 // machine installs. Interactive machine /ua may be run as the user if | |
| 1476 // /machine is specified. | |
| 1477 case COMMANDLINE_MODE_CORE: | |
| 1478 case COMMANDLINE_MODE_CRASH_HANDLER: | |
| 1479 return is_local_system; | |
| 1480 | |
| 1481 // The following runs silently as Local System. | |
| 1482 case COMMANDLINE_MODE_SERVICE: | |
| 1483 case COMMANDLINE_MODE_MEDIUM_SERVICE: | |
| 1484 ASSERT1(is_local_system); | |
| 1485 return is_local_system; | |
| 1486 | |
| 1487 // The following run as machine for all installs. | |
| 1488 case COMMANDLINE_MODE_SERVICE_REGISTER: | |
| 1489 case COMMANDLINE_MODE_SERVICE_UNREGISTER: | |
| 1490 return true; | |
| 1491 | |
| 1492 // The crashing process determines whether it was a machine or user omaha | |
| 1493 // and correctly sets the /machine switch. | |
| 1494 case COMMANDLINE_MODE_REPORTCRASH: | |
| 1495 return is_machine_override; | |
| 1496 | |
| 1497 // The following all run silently as the user for all installs. | |
| 1498 case COMMANDLINE_MODE_REGSERVER: | |
| 1499 case COMMANDLINE_MODE_UNREGSERVER: | |
| 1500 #if !OFFICIAL_BUILD | |
| 1501 // Return machine == true. This is to facilitate unit tests such as | |
| 1502 // GoogleUpdateCoreTest.LaunchCmdElevated_LocalServerRegistered. | |
| 1503 if (IsOmahaShellRunningFromStaging()) { | |
| 1504 return true; | |
| 1505 } | |
| 1506 #endif | |
| 1507 | |
| 1508 ASSERT1(goopdate_utils::IsRunningFromOfficialGoopdateDir(false) || | |
| 1509 goopdate_utils::IsRunningFromOfficialGoopdateDir(true) || | |
| 1510 _T("omaha_unittest.exe") == app_util::GetCurrentModuleName()); | |
| 1511 return is_running_from_official_machine_directory; | |
| 1512 | |
| 1513 // The following may run as user or Local System. Thus, use the directory. | |
| 1514 case COMMANDLINE_MODE_UNINSTALL: | |
| 1515 case COMMANDLINE_MODE_PING: | |
| 1516 ASSERT1(goopdate_utils::IsRunningFromOfficialGoopdateDir(false) || | |
| 1517 goopdate_utils::IsRunningFromOfficialGoopdateDir(true) || | |
| 1518 _T("omaha_unittest.exe") == app_util::GetCurrentModuleName()); | |
| 1519 return is_running_from_official_machine_directory; | |
| 1520 | |
| 1521 // The following are miscellaneous modes that we do not expect to be running | |
| 1522 // in the wild. | |
| 1523 case COMMANDLINE_MODE_NOARGS: | |
| 1524 case COMMANDLINE_MODE_UNKNOWN: | |
| 1525 case COMMANDLINE_MODE_NETDIAGS: | |
| 1526 case COMMANDLINE_MODE_CRASH: | |
| 1527 default: | |
| 1528 return is_running_from_official_machine_directory; | |
| 1529 } | |
| 1530 } | |
| 1531 | |
| 1532 bool CanDisplayUi(CommandLineMode mode, bool is_silent) { | |
| 1533 switch (mode) { | |
| 1534 case COMMANDLINE_MODE_UNKNOWN: | |
| 1535 // This mode is not one of our known silent modes. Therefore, we can | |
| 1536 // display an error UI. | |
| 1537 return true; | |
| 1538 | |
| 1539 case COMMANDLINE_MODE_INSTALL: | |
| 1540 case COMMANDLINE_MODE_HANDOFF_INSTALL: | |
| 1541 case COMMANDLINE_MODE_UA: | |
| 1542 // These modes have UI unless they are silent. | |
| 1543 // UA is usually silent, but follows the same logic. | |
| 1544 return !is_silent; | |
| 1545 | |
| 1546 case COMMANDLINE_MODE_NOARGS: | |
| 1547 case COMMANDLINE_MODE_CORE: | |
| 1548 case COMMANDLINE_MODE_SERVICE: | |
| 1549 case COMMANDLINE_MODE_REGSERVER: | |
| 1550 case COMMANDLINE_MODE_UNREGSERVER: | |
| 1551 case COMMANDLINE_MODE_NETDIAGS: | |
| 1552 case COMMANDLINE_MODE_CRASH: | |
| 1553 case COMMANDLINE_MODE_REPORTCRASH: | |
| 1554 case COMMANDLINE_MODE_UPDATE: | |
| 1555 case COMMANDLINE_MODE_RECOVER: | |
| 1556 case COMMANDLINE_MODE_WEBPLUGIN: | |
| 1557 case COMMANDLINE_MODE_CODE_RED_CHECK: | |
| 1558 case COMMANDLINE_MODE_COMSERVER: | |
| 1559 case COMMANDLINE_MODE_REGISTER_PRODUCT: | |
| 1560 case COMMANDLINE_MODE_UNREGISTER_PRODUCT: | |
| 1561 case COMMANDLINE_MODE_SERVICE_REGISTER: | |
| 1562 case COMMANDLINE_MODE_SERVICE_UNREGISTER: | |
| 1563 case COMMANDLINE_MODE_CRASH_HANDLER: | |
| 1564 case COMMANDLINE_MODE_COMBROKER: | |
| 1565 case COMMANDLINE_MODE_ONDEMAND: | |
| 1566 case COMMANDLINE_MODE_MEDIUM_SERVICE: | |
| 1567 case COMMANDLINE_MODE_UNINSTALL: | |
| 1568 case COMMANDLINE_MODE_PING: | |
| 1569 default: | |
| 1570 // These modes are always silent. | |
| 1571 return false; | |
| 1572 } | |
| 1573 } | |
| 1574 | |
| 1575 } // namespace internal | |
| 1576 | |
| 1577 Goopdate* Goopdate::instance_ = NULL; | |
| 1578 | |
| 1579 Goopdate& Goopdate::Instance() { | |
| 1580 ASSERT1(instance_); | |
| 1581 return *instance_; | |
| 1582 } | |
| 1583 | |
| 1584 Goopdate::Goopdate(bool is_local_system) { | |
| 1585 CORE_LOG(L2, (_T("[Goopdate::Goopdate]"))); | |
| 1586 impl_.reset(new detail::GoopdateImpl(this, is_local_system)); | |
| 1587 | |
| 1588 ASSERT1(!instance_); | |
| 1589 instance_ = this; | |
| 1590 } | |
| 1591 | |
| 1592 Goopdate::~Goopdate() { | |
| 1593 CORE_LOG(L2, (_T("[Goopdate::~Goopdate]"))); | |
| 1594 | |
| 1595 Stop(); | |
| 1596 | |
| 1597 instance_ = NULL; | |
| 1598 } | |
| 1599 | |
| 1600 HRESULT Goopdate::Main(HINSTANCE instance, | |
| 1601 const TCHAR* cmd_line, | |
| 1602 int cmd_show) { | |
| 1603 return impl_->Main(instance, cmd_line, cmd_show); | |
| 1604 } | |
| 1605 | |
| 1606 HRESULT Goopdate::QueueUserWorkItem(UserWorkItem* work_item, uint32 flags) { | |
| 1607 return impl_->QueueUserWorkItem(work_item, flags); | |
| 1608 } | |
| 1609 | |
| 1610 void Goopdate::Stop() { | |
| 1611 return impl_->Stop(); | |
| 1612 } | |
| 1613 | |
| 1614 bool Goopdate::is_local_system() const { | |
| 1615 return impl_->is_local_system(); | |
| 1616 } | |
| 1617 | |
| 1618 } // namespace omaha | |
| OLD | NEW |