1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Implementation of the installation validator. 6 7 #include "chrome/installer/util/installation_validator.h" 8 9 #include <algorithm> 10 #include <set> 11 #include <string> 12 13 #include "base/logging.h" 14 #include "base/strings/utf_string_conversions.h" 15 #include "base/version.h" 16 #include "chrome/common/chrome_switches.h" 17 #include "chrome/installer/util/browser_distribution.h" 18 #include "chrome/installer/util/google_update_constants.h" 19 #include "chrome/installer/util/helper.h" 20 #include "chrome/installer/util/installation_state.h" 21 22 namespace installer { 23 24 BrowserDistribution::Type 25 InstallationValidator::ChromeRules::distribution_type() const { 26 return BrowserDistribution::CHROME_BROWSER; 27 } 28 29 void InstallationValidator::ChromeRules::AddUninstallSwitchExpectations( 30 const ProductContext& ctx, 31 SwitchExpectations* expectations) const { 32 const bool is_multi_install = 33 ctx.state.uninstall_command().HasSwitch(switches::kMultiInstall); 34 35 // --chrome should be present for uninstall iff --multi-install. This wasn't 36 // the case in Chrome 10 (between r68996 and r72497), though, so consider it 37 // optional. 38 } 39 40 void InstallationValidator::ChromeRules::AddRenameSwitchExpectations( 41 const ProductContext& ctx, 42 SwitchExpectations* expectations) const { 43 const bool is_multi_install = 44 ctx.state.uninstall_command().HasSwitch(switches::kMultiInstall); 45 46 // --chrome should not be present for rename. It was for a time, so we'll be 47 // lenient so that mini_installer tests pass. 48 49 // --chrome-frame should never be present. 50 expectations->push_back( 51 std::make_pair(std::string(switches::kChromeFrame), false)); 52 } 53 54 bool InstallationValidator::ChromeRules::UsageStatsAllowed( 55 const ProductContext& ctx) const { 56 // Products must not have usagestats consent values when multi-install 57 // (only the multi-install binaries may). 58 return !ctx.state.is_multi_install(); 59 } 60 61 BrowserDistribution::Type 62 InstallationValidator::ChromeFrameRules::distribution_type() const { 63 return BrowserDistribution::CHROME_FRAME; 64 } 65 66 void InstallationValidator::ChromeFrameRules::AddUninstallSwitchExpectations( 67 const ProductContext& ctx, 68 SwitchExpectations* expectations) const { 69 // --chrome-frame must be present. 70 expectations->push_back(std::make_pair(std::string(switches::kChromeFrame), 71 true)); 72 // --chrome must not be present. 73 expectations->push_back(std::make_pair(std::string(switches::kChrome), 74 false)); 75 } 76 77 void InstallationValidator::ChromeFrameRules::AddRenameSwitchExpectations( 78 const ProductContext& ctx, 79 SwitchExpectations* expectations) const { 80 // --chrome-frame must be present for SxS rename. 81 expectations->push_back(std::make_pair(std::string(switches::kChromeFrame), 82 !ctx.state.is_multi_install())); 83 // --chrome must not be present. 84 expectations->push_back(std::make_pair(std::string(switches::kChrome), 85 false)); 86 } 87 88 bool InstallationValidator::ChromeFrameRules::UsageStatsAllowed( 89 const ProductContext& ctx) const { 90 // Products must not have usagestats consent values when multi-install 91 // (only the multi-install binaries may). 92 return !ctx.state.is_multi_install(); 93 } 94 95 BrowserDistribution::Type 96 InstallationValidator::ChromeAppHostRules::distribution_type() const { 97 return BrowserDistribution::CHROME_APP_HOST; 98 } 99 100 void InstallationValidator::ChromeAppHostRules::AddUninstallSwitchExpectations( 101 const ProductContext& ctx, 102 SwitchExpectations* expectations) const { 103 // --app-launcher must be present. 104 expectations->push_back( 105 std::make_pair(std::string(switches::kChromeAppLauncher), true)); 106 107 // --chrome must not be present. 108 expectations->push_back(std::make_pair(std::string(switches::kChrome), 109 false)); 110 // --chrome-frame must not be present. 111 expectations->push_back(std::make_pair(std::string(switches::kChromeFrame), 112 false)); 113 } 114 115 void InstallationValidator::ChromeAppHostRules::AddRenameSwitchExpectations( 116 const ProductContext& ctx, 117 SwitchExpectations* expectations) const { 118 // TODO(erikwright): I guess there will be none? 119 } 120 121 bool InstallationValidator::ChromeAppHostRules::UsageStatsAllowed( 122 const ProductContext& ctx) const { 123 // App Host doesn't manage usage stats. The Chrome Binaries will. 124 return false; 125 } 126 127 BrowserDistribution::Type 128 InstallationValidator::ChromeBinariesRules::distribution_type() const { 129 return BrowserDistribution::CHROME_BINARIES; 130 } 131 132 void InstallationValidator::ChromeBinariesRules::AddUninstallSwitchExpectations( 133 const ProductContext& ctx, 134 SwitchExpectations* expectations) const { 135 NOTREACHED(); 136 } 137 138 void InstallationValidator::ChromeBinariesRules::AddRenameSwitchExpectations( 139 const ProductContext& ctx, 140 SwitchExpectations* expectations) const { 141 NOTREACHED(); 142 } 143 144 bool InstallationValidator::ChromeBinariesRules::UsageStatsAllowed( 145 const ProductContext& ctx) const { 146 // UsageStats consent values are always allowed on the binaries. 147 return true; 148 } 149 150 // static 151 const InstallationValidator::InstallationType 152 InstallationValidator::kInstallationTypes[] = { 153 NO_PRODUCTS, 154 CHROME_SINGLE, 155 CHROME_MULTI, 156 CHROME_FRAME_SINGLE, 157 CHROME_FRAME_SINGLE_CHROME_SINGLE, 158 CHROME_FRAME_SINGLE_CHROME_MULTI, 159 CHROME_FRAME_MULTI, 160 CHROME_FRAME_MULTI_CHROME_MULTI, 161 CHROME_APP_HOST, 162 CHROME_APP_HOST_CHROME_FRAME_SINGLE, 163 CHROME_APP_HOST_CHROME_FRAME_SINGLE_CHROME_MULTI, 164 CHROME_APP_HOST_CHROME_FRAME_MULTI, 165 CHROME_APP_HOST_CHROME_FRAME_MULTI_CHROME_MULTI, 166 CHROME_APP_HOST_CHROME_MULTI, 167 }; 168 169 void InstallationValidator::ValidateAppCommandFlags( 170 const ProductContext& ctx, 171 const AppCommand& app_cmd, 172 const std::set<base::string16>& flags_exp, 173 const base::string16& name, 174 bool* is_valid) { 175 const struct { 176 const base::string16 exp_key; 177 bool val; 178 const char* msg; 179 } check_list[] = { 180 {google_update::kRegSendsPingsField, 181 app_cmd.sends_pings(), 182 "be configured to send pings"}, 183 {google_update::kRegWebAccessibleField, 184 app_cmd.is_web_accessible(), 185 "be web accessible"}, 186 {google_update::kRegAutoRunOnOSUpgradeField, 187 app_cmd.is_auto_run_on_os_upgrade(), 188 "be marked to run on OS upgrade"}, 189 {google_update::kRegRunAsUserField, 190 app_cmd.is_run_as_user(), 191 "be marked to run as user"}, 192 }; 193 for (int i = 0; i < arraysize(check_list); ++i) { 194 bool expected = flags_exp.find(check_list[i].exp_key) != flags_exp.end(); 195 if (check_list[i].val != expected) { 196 *is_valid = false; 197 LOG(ERROR) << ctx.dist->GetDisplayName() << ": " 198 << name << " command should " << (expected ? "" : "not ") 199 << check_list[i].msg << "."; 200 } 201 } 202 } 203 204 // Validates both "install-application" and "install-extension" depending on 205 // what is passed in. 206 void InstallationValidator::ValidateInstallCommand( 207 const ProductContext& ctx, 208 const AppCommand& app_cmd, 209 const wchar_t* expected_command, 210 const wchar_t* expected_app_name, 211 const char* expected_switch, 212 bool* is_valid) { 213 DCHECK(is_valid); 214 215 CommandLine cmd_line(CommandLine::FromString(app_cmd.command_line())); 216 base::string16 name(expected_command); 217 218 base::FilePath expected_path( 219 installer::GetChromeInstallPath(ctx.system_install, ctx.dist) 220 .Append(expected_app_name)); 221 222 if (!base::FilePath::CompareEqualIgnoreCase(expected_path.value(), 223 cmd_line.GetProgram().value())) { 224 *is_valid = false; 225 LOG(ERROR) << name << "'s path is not " 226 << expected_path.value() << ": " 227 << cmd_line.GetProgram().value(); 228 } 229 230 SwitchExpectations expected; 231 expected.push_back(std::make_pair(std::string(expected_switch), true)); 232 233 ValidateCommandExpectations(ctx, cmd_line, expected, name, is_valid); 234 235 std::set<base::string16> flags_exp; 236 flags_exp.insert(google_update::kRegSendsPingsField); 237 flags_exp.insert(google_update::kRegWebAccessibleField); 238 flags_exp.insert(google_update::kRegRunAsUserField); 239 ValidateAppCommandFlags(ctx, app_cmd, flags_exp, name, is_valid); 240 } 241 242 // Validates the "install-application" Google Update product command. 243 void InstallationValidator::ValidateInstallAppCommand( 244 const ProductContext& ctx, 245 const AppCommand& app_cmd, 246 bool* is_valid) { 247 ValidateInstallCommand(ctx, app_cmd, kCmdInstallApp, 248 installer::kChromeAppHostExe, 249 ::switches::kInstallFromWebstore, is_valid); 250 } 251 252 // Validates the "install-extension" Google Update product command. 253 void InstallationValidator::ValidateInstallExtensionCommand( 254 const ProductContext& ctx, 255 const AppCommand& app_cmd, 256 bool* is_valid) { 257 ValidateInstallCommand(ctx, app_cmd, kCmdInstallExtension, 258 installer::kChromeExe, 259 ::switches::kLimitedInstallFromWebstore, is_valid); 260 } 261 262 // Validates the "on-os-upgrade" Google Update internal command. 263 void InstallationValidator::ValidateOnOsUpgradeCommand( 264 const ProductContext& ctx, 265 const AppCommand& app_cmd, 266 bool* is_valid) { 267 DCHECK(is_valid); 268 269 CommandLine cmd_line(CommandLine::FromString(app_cmd.command_line())); 270 base::string16 name(kCmdOnOsUpgrade); 271 272 ValidateSetupPath(ctx, cmd_line.GetProgram(), name, is_valid); 273 274 SwitchExpectations expected; 275 expected.push_back(std::make_pair(std::string(switches::kOnOsUpgrade), true)); 276 expected.push_back(std::make_pair(std::string(switches::kSystemLevel), 277 ctx.system_install)); 278 expected.push_back(std::make_pair(std::string(switches::kMultiInstall), 279 ctx.state.is_multi_install())); 280 // Expecting kChrome if and only if kMultiInstall. 281 expected.push_back(std::make_pair(std::string(switches::kChrome), 282 ctx.state.is_multi_install())); 283 284 ValidateCommandExpectations(ctx, cmd_line, expected, name, is_valid); 285 286 std::set<base::string16> flags_exp; 287 flags_exp.insert(google_update::kRegAutoRunOnOSUpgradeField); 288 ValidateAppCommandFlags(ctx, app_cmd, flags_exp, name, is_valid); 289 } 290 291 // Validates the "query-eula-acceptance" Google Update product command. 292 void InstallationValidator::ValidateQueryEULAAcceptanceCommand( 293 const ProductContext& ctx, 294 const AppCommand& app_cmd, 295 bool* is_valid) { 296 DCHECK(is_valid); 297 298 CommandLine cmd_line(CommandLine::FromString(app_cmd.command_line())); 299 base::string16 name(kCmdQueryEULAAcceptance); 300 301 ValidateSetupPath(ctx, cmd_line.GetProgram(), name, is_valid); 302 303 SwitchExpectations expected; 304 expected.push_back(std::make_pair(std::string(switches::kQueryEULAAcceptance), 305 true)); 306 expected.push_back(std::make_pair(std::string(switches::kSystemLevel), 307 ctx.system_install)); 308 309 ValidateCommandExpectations(ctx, cmd_line, expected, name, is_valid); 310 311 std::set<base::string16> flags_exp; 312 flags_exp.insert(google_update::kRegWebAccessibleField); 313 flags_exp.insert(google_update::kRegRunAsUserField); 314 ValidateAppCommandFlags(ctx, app_cmd, flags_exp, name, is_valid); 315 } 316 317 // Validates the "quick-enable-application-host" Google Update product command. 318 void InstallationValidator::ValidateQuickEnableApplicationHostCommand( 319 const ProductContext& ctx, 320 const AppCommand& app_cmd, 321 bool* is_valid) { 322 DCHECK(is_valid); 323 324 CommandLine cmd_line(CommandLine::FromString(app_cmd.command_line())); 325 base::string16 name(kCmdQuickEnableApplicationHost); 326 327 ValidateSetupPath(ctx, cmd_line.GetProgram(), name, is_valid); 328 329 SwitchExpectations expected; 330 331 expected.push_back(std::make_pair( 332 std::string(switches::kChromeAppLauncher), true)); 333 expected.push_back(std::make_pair( 334 std::string(switches::kSystemLevel), false)); 335 expected.push_back(std::make_pair( 336 std::string(switches::kMultiInstall), true)); 337 expected.push_back(std::make_pair( 338 std::string(switches::kEnsureGoogleUpdatePresent), true)); 339 340 ValidateCommandExpectations(ctx, cmd_line, expected, name, is_valid); 341 342 std::set<base::string16> flags_exp; 343 flags_exp.insert(google_update::kRegSendsPingsField); 344 flags_exp.insert(google_update::kRegWebAccessibleField); 345 flags_exp.insert(google_update::kRegRunAsUserField); 346 ValidateAppCommandFlags(ctx, app_cmd, flags_exp, name, is_valid); 347 } 348 349 // Validates a product's set of Google Update product commands against a 350 // collection of expectations. 351 void InstallationValidator::ValidateAppCommandExpectations( 352 const ProductContext& ctx, 353 const CommandExpectations& expectations, 354 bool* is_valid) { 355 DCHECK(is_valid); 356 357 CommandExpectations the_expectations(expectations); 358 359 AppCommands::CommandMapRange cmd_iterators( 360 ctx.state.commands().GetIterators()); 361 CommandExpectations::iterator expectation; 362 for (; cmd_iterators.first != cmd_iterators.second; ++cmd_iterators.first) { 363 const base::string16& cmd_id = cmd_iterators.first->first; 364 // Do we have an expectation for this command? 365 expectation = the_expectations.find(cmd_id); 366 if (expectation != the_expectations.end()) { 367 (expectation->second)(ctx, cmd_iterators.first->second, is_valid); 368 // Remove this command from the set of expectations since we found it. 369 the_expectations.erase(expectation); 370 } else { 371 *is_valid = false; 372 LOG(ERROR) << ctx.dist->GetDisplayName() 373 << " has an unexpected Google Update product command named \"" 374 << cmd_id << "\"."; 375 } 376 } 377 378 // Report on any expected commands that weren't present. 379 CommandExpectations::const_iterator scan(the_expectations.begin()); 380 CommandExpectations::const_iterator end(the_expectations.end()); 381 for (; scan != end; ++scan) { 382 *is_valid = false; 383 LOG(ERROR) << ctx.dist->GetDisplayName() 384 << " is missing the Google Update product command named \"" 385 << scan->first << "\"."; 386 } 387 } 388 389 // Validates the multi-install binaries' Google Update commands. 390 void InstallationValidator::ValidateBinariesCommands( 391 const ProductContext& ctx, 392 bool* is_valid) { 393 DCHECK(is_valid); 394 395 const ProductState* binaries_state = ctx.machine_state.GetProductState( 396 ctx.system_install, BrowserDistribution::CHROME_BINARIES); 397 398 CommandExpectations expectations; 399 400 if (binaries_state != NULL) { 401 expectations[kCmdQuickEnableApplicationHost] = 402 &ValidateQuickEnableApplicationHostCommand; 403 404 expectations[kCmdQueryEULAAcceptance] = &ValidateQueryEULAAcceptanceCommand; 405 } 406 407 ValidateAppCommandExpectations(ctx, expectations, is_valid); 408 } 409 410 // Validates the multi-install binaries at level |system_level|. 411 void InstallationValidator::ValidateBinaries( 412 const InstallationState& machine_state, 413 bool system_install, 414 const ProductState& binaries_state, 415 bool* is_valid) { 416 const ChannelInfo& channel = binaries_state.channel(); 417 418 // ap must have -multi 419 if (!channel.IsMultiInstall()) { 420 *is_valid = false; 421 LOG(ERROR) << "Chrome Binaries are missing \"-multi\" in channel name: \"" 422 << channel.value() << "\""; 423 } 424 425 // ap must have -chrome iff Chrome is installed 426 const ProductState* chrome_state = machine_state.GetProductState( 427 system_install, BrowserDistribution::CHROME_BROWSER); 428 if (chrome_state != NULL) { 429 if (!channel.IsChrome()) { 430 *is_valid = false; 431 LOG(ERROR) << "Chrome Binaries are missing \"chrome\" in channel name:" 432 << " \"" << channel.value() << "\""; 433 } 434 } else if (channel.IsChrome()) { 435 *is_valid = false; 436 LOG(ERROR) << "Chrome Binaries have \"-chrome\" in channel name, yet Chrome" 437 " is not installed: \"" << channel.value() << "\""; 438 } 439 440 // ap must have -chromeframe iff Chrome Frame is installed multi 441 const ProductState* cf_state = machine_state.GetProductState( 442 system_install, BrowserDistribution::CHROME_FRAME); 443 if (cf_state != NULL && cf_state->is_multi_install()) { 444 if (!channel.IsChromeFrame()) { 445 *is_valid = false; 446 LOG(ERROR) << "Chrome Binaries are missing \"-chromeframe\" in channel" 447 " name: \"" << channel.value() << "\""; 448 } 449 } else if (channel.IsChromeFrame()) { 450 *is_valid = false; 451 LOG(ERROR) << "Chrome Binaries have \"-chromeframe\" in channel name, yet " 452 "Chrome Frame is not installed multi: \"" << channel.value() 453 << "\""; 454 } 455 456 // ap must have -applauncher iff Chrome App Launcher is installed multi 457 const ProductState* app_host_state = machine_state.GetProductState( 458 system_install, BrowserDistribution::CHROME_APP_HOST); 459 if (app_host_state != NULL) { 460 if (!app_host_state->is_multi_install()) { 461 *is_valid = false; 462 LOG(ERROR) << "Chrome App Launcher is installed in non-multi mode."; 463 } 464 if (!channel.IsAppLauncher()) { 465 *is_valid = false; 466 LOG(ERROR) << "Chrome Binaries are missing \"-applauncher\" in channel" 467 " name: \"" << channel.value() << "\""; 468 } 469 } else if (channel.IsAppLauncher()) { 470 *is_valid = false; 471 LOG(ERROR) << "Chrome Binaries have \"-applauncher\" in channel name, yet " 472 "Chrome App Launcher is not installed: \"" << channel.value() 473 << "\""; 474 } 475 476 // Chrome, Chrome Frame, or App Host must be present 477 if (chrome_state == NULL && cf_state == NULL && app_host_state == NULL) { 478 *is_valid = false; 479 LOG(ERROR) << "Chrome Binaries are present with no other products."; 480 } 481 482 // Chrome must be multi-install if present. 483 if (chrome_state != NULL && !chrome_state->is_multi_install()) { 484 *is_valid = false; 485 LOG(ERROR) 486 << "Chrome Binaries are present yet Chrome is not multi-install."; 487 } 488 489 // Chrome Frame must be multi-install if Chrome & App Host are not present. 490 if (cf_state != NULL && app_host_state == NULL && chrome_state == NULL && 491 !cf_state->is_multi_install()) { 492 *is_valid = false; 493 LOG(ERROR) << "Chrome Binaries are present without Chrome nor App Launcher " 494 << "yet Chrome Frame is not multi-install."; 495 } 496 497 ChromeBinariesRules binaries_rules; 498 ProductContext ctx(machine_state, system_install, binaries_state, 499 binaries_rules); 500 501 ValidateBinariesCommands(ctx, is_valid); 502 503 ValidateUsageStats(ctx, is_valid); 504 } 505 506 // Validates the path to |setup_exe| for the product described by |ctx|. 507 void InstallationValidator::ValidateSetupPath(const ProductContext& ctx, 508 const base::FilePath& setup_exe, 509 const base::string16& purpose, 510 bool* is_valid) { 511 DCHECK(is_valid); 512 513 BrowserDistribution* bins_dist = ctx.dist; 514 if (ctx.state.is_multi_install()) { 515 bins_dist = BrowserDistribution::GetSpecificDistribution( 516 BrowserDistribution::CHROME_BINARIES); 517 } 518 519 base::FilePath expected_path = installer::GetChromeInstallPath( 520 ctx.system_install, bins_dist); 521 expected_path = expected_path 522 .AppendASCII(ctx.state.version().GetString()) 523 .Append(installer::kInstallerDir) 524 .Append(installer::kSetupExe); 525 if (!base::FilePath::CompareEqualIgnoreCase(expected_path.value(), 526 setup_exe.value())) { 527 *is_valid = false; 528 LOG(ERROR) << ctx.dist->GetDisplayName() << " path to " << purpose 529 << " is not " << expected_path.value() << ": " 530 << setup_exe.value(); 531 } 532 } 533 534 // Validates that |command| meets the expectations described in |expected|. 535 void InstallationValidator::ValidateCommandExpectations( 536 const ProductContext& ctx, 537 const CommandLine& command, 538 const SwitchExpectations& expected, 539 const base::string16& source, 540 bool* is_valid) { 541 for (SwitchExpectations::size_type i = 0, size = expected.size(); i < size; 542 ++i) { 543 const SwitchExpectations::value_type& expectation = expected[i]; 544 if (command.HasSwitch(expectation.first) != expectation.second) { 545 *is_valid = false; 546 LOG(ERROR) << ctx.dist->GetDisplayName() << " " << source 547 << (expectation.second ? " is missing" : " has") << " \"" 548 << expectation.first << "\"" 549 << (expectation.second ? "" : " but shouldn't") << ": " 550 << command.GetCommandLineString(); 551 } 552 } 553 } 554 555 // Validates that |command|, originating from |source|, is formed properly for 556 // the product described by |ctx| 557 void InstallationValidator::ValidateUninstallCommand( 558 const ProductContext& ctx, 559 const CommandLine& command, 560 const base::string16& source, 561 bool* is_valid) { 562 DCHECK(is_valid); 563 564 ValidateSetupPath(ctx, command.GetProgram(), 565 base::ASCIIToUTF16("uninstaller"), 566 is_valid); 567 568 const bool is_multi_install = ctx.state.is_multi_install(); 569 SwitchExpectations expected; 570 571 expected.push_back(std::make_pair(std::string(switches::kUninstall), true)); 572 expected.push_back(std::make_pair(std::string(switches::kSystemLevel), 573 ctx.system_install)); 574 expected.push_back(std::make_pair(std::string(switches::kMultiInstall), 575 is_multi_install)); 576 ctx.rules.AddUninstallSwitchExpectations(ctx, &expected); 577 578 ValidateCommandExpectations(ctx, command, expected, source, is_valid); 579 } 580 581 // Validates the rename command for the product described by |ctx|. 582 void InstallationValidator::ValidateRenameCommand(const ProductContext& ctx, 583 bool* is_valid) { 584 DCHECK(is_valid); 585 DCHECK(!ctx.state.rename_cmd().empty()); 586 587 CommandLine command = CommandLine::FromString(ctx.state.rename_cmd()); 588 base::string16 name(base::ASCIIToUTF16("in-use renamer")); 589 590 ValidateSetupPath(ctx, command.GetProgram(), name, is_valid); 591 592 SwitchExpectations expected; 593 594 expected.push_back(std::make_pair(std::string(switches::kRenameChromeExe), 595 true)); 596 expected.push_back(std::make_pair(std::string(switches::kSystemLevel), 597 ctx.system_install)); 598 expected.push_back(std::make_pair(std::string(switches::kMultiInstall), 599 ctx.state.is_multi_install())); 600 ctx.rules.AddRenameSwitchExpectations(ctx, &expected); 601 602 ValidateCommandExpectations(ctx, command, expected, name, is_valid); 603 } 604 605 // Validates the "opv" and "cmd" values for the product described in |ctx|. 606 void InstallationValidator::ValidateOldVersionValues( 607 const ProductContext& ctx, 608 bool* is_valid) { 609 DCHECK(is_valid); 610 611 // opv and cmd must both be present or both absent 612 if (ctx.state.old_version() == NULL) { 613 if (!ctx.state.rename_cmd().empty()) { 614 *is_valid = false; 615 LOG(ERROR) << ctx.dist->GetDisplayName() 616 << " has a rename command but no opv: " 617 << ctx.state.rename_cmd(); 618 } 619 } else { 620 if (ctx.state.rename_cmd().empty()) { 621 *is_valid = false; 622 LOG(ERROR) << ctx.dist->GetDisplayName() 623 << " has an opv but no rename command: " 624 << ctx.state.old_version()->GetString(); 625 } else { 626 ValidateRenameCommand(ctx, is_valid); 627 } 628 } 629 } 630 631 // Validates the multi-install state of the product described in |ctx|. 632 void InstallationValidator::ValidateMultiInstallProduct( 633 const ProductContext& ctx, 634 bool* is_valid) { 635 DCHECK(is_valid); 636 637 const ProductState* binaries = 638 ctx.machine_state.GetProductState(ctx.system_install, 639 BrowserDistribution::CHROME_BINARIES); 640 if (!binaries) { 641 if (ctx.dist->GetType() == BrowserDistribution::CHROME_APP_HOST) { 642 if (!ctx.machine_state.GetProductState( 643 true, // system-level 644 BrowserDistribution::CHROME_BINARIES) && 645 !ctx.machine_state.GetProductState( 646 true, // system-level 647 BrowserDistribution::CHROME_BROWSER)) { 648 *is_valid = false; 649 LOG(ERROR) << ctx.dist->GetDisplayName() 650 << " (" << ctx.state.version().GetString() << ") is " 651 << "installed without Chrome Binaries or a system-level " 652 << "Chrome."; 653 } 654 } else { 655 *is_valid = false; 656 LOG(ERROR) << ctx.dist->GetDisplayName() 657 << " (" << ctx.state.version().GetString() << ") is installed " 658 << "without Chrome Binaries."; 659 } 660 } else { 661 // Version must match that of binaries. 662 if (ctx.state.version().CompareTo(binaries->version()) != 0) { 663 *is_valid = false; 664 LOG(ERROR) << "Version of " << ctx.dist->GetDisplayName() 665 << " (" << ctx.state.version().GetString() << ") does not " 666 "match that of Chrome Binaries (" 667 << binaries->version().GetString() << ")."; 668 } 669 670 // Channel value must match that of binaries. 671 if (!ctx.state.channel().Equals(binaries->channel())) { 672 *is_valid = false; 673 LOG(ERROR) << "Channel name of " << ctx.dist->GetDisplayName() 674 << " (" << ctx.state.channel().value() 675 << ") does not match that of Chrome Binaries (" 676 << binaries->channel().value() << ")."; 677 } 678 } 679 } 680 681 // Validates the Google Update commands for the product described in |ctx|. 682 void InstallationValidator::ValidateAppCommands( 683 const ProductContext& ctx, 684 bool* is_valid) { 685 DCHECK(is_valid); 686 687 CommandExpectations expectations; 688 689 if (ctx.dist->GetType() == BrowserDistribution::CHROME_APP_HOST) { 690 expectations[kCmdInstallApp] = &ValidateInstallAppCommand; 691 } 692 if (ctx.dist->GetType() == BrowserDistribution::CHROME_BROWSER) { 693 expectations[kCmdInstallExtension] = &ValidateInstallExtensionCommand; 694 expectations[kCmdOnOsUpgrade] = &ValidateOnOsUpgradeCommand; 695 } 696 697 ValidateAppCommandExpectations(ctx, expectations, is_valid); 698 } 699 700 // Validates usagestats for the product or binaries in |ctx|. 701 void InstallationValidator::ValidateUsageStats(const ProductContext& ctx, 702 bool* is_valid) { 703 DWORD usagestats = 0; 704 if (ctx.state.GetUsageStats(&usagestats)) { 705 if (!ctx.rules.UsageStatsAllowed(ctx)) { 706 *is_valid = false; 707 LOG(ERROR) << ctx.dist->GetDisplayName() 708 << " has a usagestats value (" << usagestats 709 << "), yet should not."; 710 } else if (usagestats != 0 && usagestats != 1) { 711 *is_valid = false; 712 LOG(ERROR) << ctx.dist->GetDisplayName() 713 << " has an unsupported usagestats value (" << usagestats 714 << ")."; 715 } 716 } 717 } 718 719 // Validates the product described in |product_state| according to |rules|. 720 void InstallationValidator::ValidateProduct( 721 const InstallationState& machine_state, 722 bool system_install, 723 const ProductState& product_state, 724 const ProductRules& rules, 725 bool* is_valid) { 726 DCHECK(is_valid); 727 728 ProductContext ctx(machine_state, system_install, product_state, rules); 729 730 ValidateUninstallCommand(ctx, ctx.state.uninstall_command(), 731 base::ASCIIToUTF16( 732 "Google Update uninstall command"), 733 is_valid); 734 735 ValidateOldVersionValues(ctx, is_valid); 736 737 if (ctx.state.is_multi_install()) 738 ValidateMultiInstallProduct(ctx, is_valid); 739 740 ValidateAppCommands(ctx, is_valid); 741 742 ValidateUsageStats(ctx, is_valid); 743 } 744 745 // static 746 bool InstallationValidator::ValidateInstallationTypeForState( 747 const InstallationState& machine_state, 748 bool system_level, 749 InstallationType* type) { 750 DCHECK(type); 751 bool rock_on = true; 752 *type = NO_PRODUCTS; 753 754 // Does the system have any multi-installed products? 755 const ProductState* multi_state = 756 machine_state.GetProductState(system_level, 757 BrowserDistribution::CHROME_BINARIES); 758 if (multi_state != NULL) 759 ValidateBinaries(machine_state, system_level, *multi_state, &rock_on); 760 761 // Is Chrome installed? 762 const ProductState* product_state = 763 machine_state.GetProductState(system_level, 764 BrowserDistribution::CHROME_BROWSER); 765 if (product_state != NULL) { 766 ChromeRules chrome_rules; 767 ValidateProduct(machine_state, system_level, *product_state, 768 chrome_rules, &rock_on); 769 *type = static_cast<InstallationType>( 770 *type | (product_state->is_multi_install() ? 771 ProductBits::CHROME_MULTI : 772 ProductBits::CHROME_SINGLE)); 773 } 774 775 // Is Chrome Frame installed? 776 product_state = 777 machine_state.GetProductState(system_level, 778 BrowserDistribution::CHROME_FRAME); 779 if (product_state != NULL) { 780 ChromeFrameRules chrome_frame_rules; 781 ValidateProduct(machine_state, system_level, *product_state, 782 chrome_frame_rules, &rock_on); 783 int cf_bit = !product_state->is_multi_install() ? 784 ProductBits::CHROME_FRAME_SINGLE : 785 ProductBits::CHROME_FRAME_MULTI; 786 *type = static_cast<InstallationType>(*type | cf_bit); 787 } 788 789 // Is Chrome App Host installed? 790 product_state = 791 machine_state.GetProductState(system_level, 792 BrowserDistribution::CHROME_APP_HOST); 793 if (product_state != NULL) { 794 ChromeAppHostRules chrome_app_host_rules; 795 ValidateProduct(machine_state, system_level, *product_state, 796 chrome_app_host_rules, &rock_on); 797 *type = static_cast<InstallationType>(*type | ProductBits::CHROME_APP_HOST); 798 if (!product_state->is_multi_install()) { 799 LOG(ERROR) << "Chrome App Launcher must always be multi-install."; 800 rock_on = false; 801 } 802 } 803 804 DCHECK_NE(std::find(&kInstallationTypes[0], 805 &kInstallationTypes[arraysize(kInstallationTypes)], 806 *type), 807 &kInstallationTypes[arraysize(kInstallationTypes)]) 808 << "Invalid combination of products found on system (" << *type << ")"; 809 810 return rock_on; 811 } 812 813 // static 814 bool InstallationValidator::ValidateInstallationType(bool system_level, 815 InstallationType* type) { 816 DCHECK(type); 817 InstallationState machine_state; 818 819 machine_state.Initialize(); 820 821 return ValidateInstallationTypeForState(machine_state, system_level, type); 822 } 823 824 } // namespace installer 825