Add new certificateProvider extension API.
[chromium-blink-merge.git] / chrome / installer / util / installation_validator.cc
blob5c0e25fc68be3b603a19347aef4607fc0db1e65e
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.
5 // Implementation of the installation validator.
7 #include "chrome/installer/util/installation_validator.h"
9 #include <algorithm>
10 #include <set>
11 #include <string>
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"
22 namespace installer {
24 BrowserDistribution::Type
25 InstallationValidator::ChromeRules::distribution_type() const {
26 return BrowserDistribution::CHROME_BROWSER;
29 void InstallationValidator::ChromeRules::AddUninstallSwitchExpectations(
30 const ProductContext& ctx,
31 SwitchExpectations* expectations) const {
32 // --chrome should be present for uninstall iff --multi-install. This wasn't
33 // the case in Chrome 10 (between r68996 and r72497), though, so consider it
34 // optional.
37 void InstallationValidator::ChromeRules::AddRenameSwitchExpectations(
38 const ProductContext& ctx,
39 SwitchExpectations* expectations) const {
40 // --chrome should not be present for rename. It was for a time, so we'll be
41 // lenient so that mini_installer tests pass.
43 // --chrome-frame should never be present.
44 expectations->push_back(
45 std::make_pair(std::string(switches::kChromeFrame), false));
48 bool InstallationValidator::ChromeRules::UsageStatsAllowed(
49 const ProductContext& ctx) const {
50 // Products must not have usagestats consent values when multi-install
51 // (only the multi-install binaries may).
52 return !ctx.state.is_multi_install();
55 BrowserDistribution::Type
56 InstallationValidator::ChromeFrameRules::distribution_type() const {
57 return BrowserDistribution::CHROME_FRAME;
60 void InstallationValidator::ChromeFrameRules::AddUninstallSwitchExpectations(
61 const ProductContext& ctx,
62 SwitchExpectations* expectations) const {
63 // --chrome-frame must be present.
64 expectations->push_back(std::make_pair(std::string(switches::kChromeFrame),
65 true));
66 // --chrome must not be present.
67 expectations->push_back(std::make_pair(std::string(switches::kChrome),
68 false));
71 void InstallationValidator::ChromeFrameRules::AddRenameSwitchExpectations(
72 const ProductContext& ctx,
73 SwitchExpectations* expectations) const {
74 // --chrome-frame must be present for SxS rename.
75 expectations->push_back(std::make_pair(std::string(switches::kChromeFrame),
76 !ctx.state.is_multi_install()));
77 // --chrome must not be present.
78 expectations->push_back(std::make_pair(std::string(switches::kChrome),
79 false));
82 bool InstallationValidator::ChromeFrameRules::UsageStatsAllowed(
83 const ProductContext& ctx) const {
84 // Products must not have usagestats consent values when multi-install
85 // (only the multi-install binaries may).
86 return !ctx.state.is_multi_install();
89 BrowserDistribution::Type
90 InstallationValidator::ChromeBinariesRules::distribution_type() const {
91 return BrowserDistribution::CHROME_BINARIES;
94 void InstallationValidator::ChromeBinariesRules::AddUninstallSwitchExpectations(
95 const ProductContext& ctx,
96 SwitchExpectations* expectations) const {
97 NOTREACHED();
100 void InstallationValidator::ChromeBinariesRules::AddRenameSwitchExpectations(
101 const ProductContext& ctx,
102 SwitchExpectations* expectations) const {
103 NOTREACHED();
106 bool InstallationValidator::ChromeBinariesRules::UsageStatsAllowed(
107 const ProductContext& ctx) const {
108 // UsageStats consent values are always allowed on the binaries.
109 return true;
112 // static
113 const InstallationValidator::InstallationType
114 InstallationValidator::kInstallationTypes[] = {
115 NO_PRODUCTS,
116 CHROME_SINGLE,
117 CHROME_MULTI,
118 CHROME_FRAME_SINGLE,
119 CHROME_FRAME_SINGLE_CHROME_SINGLE,
120 CHROME_FRAME_SINGLE_CHROME_MULTI,
121 CHROME_FRAME_MULTI,
122 CHROME_FRAME_MULTI_CHROME_MULTI,
125 void InstallationValidator::ValidateAppCommandFlags(
126 const ProductContext& ctx,
127 const AppCommand& app_cmd,
128 const std::set<base::string16>& flags_exp,
129 const base::string16& name,
130 bool* is_valid) {
131 const struct {
132 const base::string16 exp_key;
133 bool val;
134 const char* msg;
135 } check_list[] = {
136 {google_update::kRegSendsPingsField,
137 app_cmd.sends_pings(),
138 "be configured to send pings"},
139 {google_update::kRegWebAccessibleField,
140 app_cmd.is_web_accessible(),
141 "be web accessible"},
142 {google_update::kRegAutoRunOnOSUpgradeField,
143 app_cmd.is_auto_run_on_os_upgrade(),
144 "be marked to run on OS upgrade"},
145 {google_update::kRegRunAsUserField,
146 app_cmd.is_run_as_user(),
147 "be marked to run as user"},
149 for (int i = 0; i < arraysize(check_list); ++i) {
150 bool expected = flags_exp.find(check_list[i].exp_key) != flags_exp.end();
151 if (check_list[i].val != expected) {
152 *is_valid = false;
153 LOG(ERROR) << ctx.dist->GetDisplayName() << ": "
154 << name << " command should " << (expected ? "" : "not ")
155 << check_list[i].msg << ".";
160 // Validates the "on-os-upgrade" Google Update internal command.
161 void InstallationValidator::ValidateOnOsUpgradeCommand(
162 const ProductContext& ctx,
163 const AppCommand& app_cmd,
164 bool* is_valid) {
165 DCHECK(is_valid);
167 base::CommandLine cmd_line(
168 base::CommandLine::FromString(app_cmd.command_line()));
169 base::string16 name(kCmdOnOsUpgrade);
171 ValidateSetupPath(ctx, cmd_line.GetProgram(), name, is_valid);
173 SwitchExpectations expected;
174 expected.push_back(std::make_pair(std::string(switches::kOnOsUpgrade), true));
175 expected.push_back(std::make_pair(std::string(switches::kSystemLevel),
176 ctx.system_install));
177 expected.push_back(std::make_pair(std::string(switches::kMultiInstall),
178 ctx.state.is_multi_install()));
179 // Expecting kChrome if and only if kMultiInstall.
180 expected.push_back(std::make_pair(std::string(switches::kChrome),
181 ctx.state.is_multi_install()));
183 ValidateCommandExpectations(ctx, cmd_line, expected, name, is_valid);
185 std::set<base::string16> flags_exp;
186 flags_exp.insert(google_update::kRegAutoRunOnOSUpgradeField);
187 ValidateAppCommandFlags(ctx, app_cmd, flags_exp, name, is_valid);
190 // Validates a product's set of Google Update product commands against a
191 // collection of expectations.
192 void InstallationValidator::ValidateAppCommandExpectations(
193 const ProductContext& ctx,
194 const CommandExpectations& expectations,
195 bool* is_valid) {
196 DCHECK(is_valid);
198 CommandExpectations the_expectations(expectations);
200 AppCommands::CommandMapRange cmd_iterators(
201 ctx.state.commands().GetIterators());
202 CommandExpectations::iterator expectation;
203 for (; cmd_iterators.first != cmd_iterators.second; ++cmd_iterators.first) {
204 const base::string16& cmd_id = cmd_iterators.first->first;
205 // Do we have an expectation for this command?
206 expectation = the_expectations.find(cmd_id);
207 if (expectation != the_expectations.end()) {
208 (expectation->second)(ctx, cmd_iterators.first->second, is_valid);
209 // Remove this command from the set of expectations since we found it.
210 the_expectations.erase(expectation);
211 } else {
212 *is_valid = false;
213 LOG(ERROR) << ctx.dist->GetDisplayName()
214 << " has an unexpected Google Update product command named \""
215 << cmd_id << "\".";
219 // Report on any expected commands that weren't present.
220 CommandExpectations::const_iterator scan(the_expectations.begin());
221 CommandExpectations::const_iterator end(the_expectations.end());
222 for (; scan != end; ++scan) {
223 *is_valid = false;
224 LOG(ERROR) << ctx.dist->GetDisplayName()
225 << " is missing the Google Update product command named \""
226 << scan->first << "\".";
230 // Validates the multi-install binaries at level |system_level|.
231 void InstallationValidator::ValidateBinaries(
232 const InstallationState& machine_state,
233 bool system_install,
234 const ProductState& binaries_state,
235 bool* is_valid) {
236 const ChannelInfo& channel = binaries_state.channel();
238 // ap must have -multi
239 if (!channel.IsMultiInstall()) {
240 *is_valid = false;
241 LOG(ERROR) << "Chrome Binaries are missing \"-multi\" in channel name: \""
242 << channel.value() << "\"";
245 // ap must have -chrome iff Chrome is installed
246 const ProductState* chrome_state = machine_state.GetProductState(
247 system_install, BrowserDistribution::CHROME_BROWSER);
248 if (chrome_state != NULL) {
249 if (!channel.IsChrome()) {
250 *is_valid = false;
251 LOG(ERROR) << "Chrome Binaries are missing \"chrome\" in channel name:"
252 << " \"" << channel.value() << "\"";
254 } else if (channel.IsChrome()) {
255 *is_valid = false;
256 LOG(ERROR) << "Chrome Binaries have \"-chrome\" in channel name, yet Chrome"
257 " is not installed: \"" << channel.value() << "\"";
260 // ap must have -chromeframe iff Chrome Frame is installed multi
261 const ProductState* cf_state = machine_state.GetProductState(
262 system_install, BrowserDistribution::CHROME_FRAME);
263 if (cf_state != NULL && cf_state->is_multi_install()) {
264 if (!channel.IsChromeFrame()) {
265 *is_valid = false;
266 LOG(ERROR) << "Chrome Binaries are missing \"-chromeframe\" in channel"
267 " name: \"" << channel.value() << "\"";
269 } else if (channel.IsChromeFrame()) {
270 *is_valid = false;
271 LOG(ERROR) << "Chrome Binaries have \"-chromeframe\" in channel name, yet "
272 "Chrome Frame is not installed multi: \"" << channel.value()
273 << "\"";
276 // Chrome or Chrome Frame must be present
277 if (chrome_state == NULL && cf_state == NULL) {
278 *is_valid = false;
279 LOG(ERROR) << "Chrome Binaries are present with no other products.";
283 // Chrome must be multi-install if present.
284 if (chrome_state != NULL && !chrome_state->is_multi_install()) {
285 *is_valid = false;
286 LOG(ERROR)
287 << "Chrome Binaries are present yet Chrome is not multi-install.";
290 // Chrome Frame must be multi-install if Chrome is not present.
291 if (cf_state != NULL && chrome_state == NULL &&
292 !cf_state->is_multi_install()) {
293 *is_valid = false;
294 LOG(ERROR) << "Chrome Binaries are present without Chrome, yet Chrome Frame"
295 << " is not multi-install.";
298 ChromeBinariesRules binaries_rules;
299 ProductContext ctx(machine_state, system_install, binaries_state,
300 binaries_rules);
302 ValidateUsageStats(ctx, is_valid);
305 // Validates the path to |setup_exe| for the product described by |ctx|.
306 void InstallationValidator::ValidateSetupPath(const ProductContext& ctx,
307 const base::FilePath& setup_exe,
308 const base::string16& purpose,
309 bool* is_valid) {
310 DCHECK(is_valid);
312 BrowserDistribution* bins_dist = ctx.dist;
313 if (ctx.state.is_multi_install()) {
314 bins_dist = BrowserDistribution::GetSpecificDistribution(
315 BrowserDistribution::CHROME_BINARIES);
318 base::FilePath expected_path = installer::GetChromeInstallPath(
319 ctx.system_install, bins_dist);
320 expected_path = expected_path
321 .AppendASCII(ctx.state.version().GetString())
322 .Append(installer::kInstallerDir)
323 .Append(installer::kSetupExe);
324 if (!base::FilePath::CompareEqualIgnoreCase(expected_path.value(),
325 setup_exe.value())) {
326 *is_valid = false;
327 LOG(ERROR) << ctx.dist->GetDisplayName() << " path to " << purpose
328 << " is not " << expected_path.value() << ": "
329 << setup_exe.value();
333 // Validates that |command| meets the expectations described in |expected|.
334 void InstallationValidator::ValidateCommandExpectations(
335 const ProductContext& ctx,
336 const base::CommandLine& command,
337 const SwitchExpectations& expected,
338 const base::string16& source,
339 bool* is_valid) {
340 for (SwitchExpectations::size_type i = 0, size = expected.size(); i < size;
341 ++i) {
342 const SwitchExpectations::value_type& expectation = expected[i];
343 if (command.HasSwitch(expectation.first) != expectation.second) {
344 *is_valid = false;
345 LOG(ERROR) << ctx.dist->GetDisplayName() << " " << source
346 << (expectation.second ? " is missing" : " has") << " \""
347 << expectation.first << "\""
348 << (expectation.second ? "" : " but shouldn't") << ": "
349 << command.GetCommandLineString();
354 // Validates that |command|, originating from |source|, is formed properly for
355 // the product described by |ctx|
356 void InstallationValidator::ValidateUninstallCommand(
357 const ProductContext& ctx,
358 const base::CommandLine& command,
359 const base::string16& source,
360 bool* is_valid) {
361 DCHECK(is_valid);
363 ValidateSetupPath(ctx, command.GetProgram(),
364 base::ASCIIToUTF16("uninstaller"),
365 is_valid);
367 const bool is_multi_install = ctx.state.is_multi_install();
368 SwitchExpectations expected;
370 expected.push_back(std::make_pair(std::string(switches::kUninstall), true));
371 expected.push_back(std::make_pair(std::string(switches::kSystemLevel),
372 ctx.system_install));
373 expected.push_back(std::make_pair(std::string(switches::kMultiInstall),
374 is_multi_install));
375 ctx.rules.AddUninstallSwitchExpectations(ctx, &expected);
377 ValidateCommandExpectations(ctx, command, expected, source, is_valid);
380 // Validates the rename command for the product described by |ctx|.
381 void InstallationValidator::ValidateRenameCommand(const ProductContext& ctx,
382 bool* is_valid) {
383 DCHECK(is_valid);
384 DCHECK(!ctx.state.rename_cmd().empty());
386 base::CommandLine command =
387 base::CommandLine::FromString(ctx.state.rename_cmd());
388 base::string16 name(base::ASCIIToUTF16("in-use renamer"));
390 ValidateSetupPath(ctx, command.GetProgram(), name, is_valid);
392 SwitchExpectations expected;
394 expected.push_back(std::make_pair(std::string(switches::kRenameChromeExe),
395 true));
396 expected.push_back(std::make_pair(std::string(switches::kSystemLevel),
397 ctx.system_install));
398 expected.push_back(std::make_pair(std::string(switches::kMultiInstall),
399 ctx.state.is_multi_install()));
400 ctx.rules.AddRenameSwitchExpectations(ctx, &expected);
402 ValidateCommandExpectations(ctx, command, expected, name, is_valid);
405 // Validates the "opv" and "cmd" values for the product described in |ctx|.
406 void InstallationValidator::ValidateOldVersionValues(
407 const ProductContext& ctx,
408 bool* is_valid) {
409 DCHECK(is_valid);
411 // opv and cmd must both be present or both absent
412 if (ctx.state.old_version() == NULL) {
413 if (!ctx.state.rename_cmd().empty()) {
414 *is_valid = false;
415 LOG(ERROR) << ctx.dist->GetDisplayName()
416 << " has a rename command but no opv: "
417 << ctx.state.rename_cmd();
419 } else {
420 if (ctx.state.rename_cmd().empty()) {
421 *is_valid = false;
422 LOG(ERROR) << ctx.dist->GetDisplayName()
423 << " has an opv but no rename command: "
424 << ctx.state.old_version()->GetString();
425 } else {
426 ValidateRenameCommand(ctx, is_valid);
431 // Validates the multi-install state of the product described in |ctx|.
432 void InstallationValidator::ValidateMultiInstallProduct(
433 const ProductContext& ctx,
434 bool* is_valid) {
435 DCHECK(is_valid);
437 const ProductState* binaries =
438 ctx.machine_state.GetProductState(ctx.system_install,
439 BrowserDistribution::CHROME_BINARIES);
440 if (!binaries) {
441 *is_valid = false;
442 LOG(ERROR) << ctx.dist->GetDisplayName()
443 << " (" << ctx.state.version().GetString() << ") is installed "
444 << "without Chrome Binaries.";
445 } else {
446 // Version must match that of binaries.
447 if (ctx.state.version().CompareTo(binaries->version()) != 0) {
448 *is_valid = false;
449 LOG(ERROR) << "Version of " << ctx.dist->GetDisplayName()
450 << " (" << ctx.state.version().GetString() << ") does not "
451 "match that of Chrome Binaries ("
452 << binaries->version().GetString() << ").";
455 // Channel value must match that of binaries.
456 if (!ctx.state.channel().Equals(binaries->channel())) {
457 *is_valid = false;
458 LOG(ERROR) << "Channel name of " << ctx.dist->GetDisplayName()
459 << " (" << ctx.state.channel().value()
460 << ") does not match that of Chrome Binaries ("
461 << binaries->channel().value() << ").";
466 // Validates the Google Update commands for the product described in |ctx|.
467 void InstallationValidator::ValidateAppCommands(
468 const ProductContext& ctx,
469 bool* is_valid) {
470 DCHECK(is_valid);
472 CommandExpectations expectations;
474 if (ctx.dist->GetType() == BrowserDistribution::CHROME_BROWSER)
475 expectations[kCmdOnOsUpgrade] = &ValidateOnOsUpgradeCommand;
477 ValidateAppCommandExpectations(ctx, expectations, is_valid);
480 // Validates usagestats for the product or binaries in |ctx|.
481 void InstallationValidator::ValidateUsageStats(const ProductContext& ctx,
482 bool* is_valid) {
483 DWORD usagestats = 0;
484 if (ctx.state.GetUsageStats(&usagestats)) {
485 if (!ctx.rules.UsageStatsAllowed(ctx)) {
486 *is_valid = false;
487 LOG(ERROR) << ctx.dist->GetDisplayName()
488 << " has a usagestats value (" << usagestats
489 << "), yet should not.";
490 } else if (usagestats != 0 && usagestats != 1) {
491 *is_valid = false;
492 LOG(ERROR) << ctx.dist->GetDisplayName()
493 << " has an unsupported usagestats value (" << usagestats
494 << ").";
499 // Validates the product described in |product_state| according to |rules|.
500 void InstallationValidator::ValidateProduct(
501 const InstallationState& machine_state,
502 bool system_install,
503 const ProductState& product_state,
504 const ProductRules& rules,
505 bool* is_valid) {
506 DCHECK(is_valid);
508 ProductContext ctx(machine_state, system_install, product_state, rules);
510 ValidateUninstallCommand(ctx, ctx.state.uninstall_command(),
511 base::ASCIIToUTF16(
512 "Google Update uninstall command"),
513 is_valid);
515 ValidateOldVersionValues(ctx, is_valid);
517 if (ctx.state.is_multi_install())
518 ValidateMultiInstallProduct(ctx, is_valid);
520 ValidateAppCommands(ctx, is_valid);
522 ValidateUsageStats(ctx, is_valid);
525 // static
526 bool InstallationValidator::ValidateInstallationTypeForState(
527 const InstallationState& machine_state,
528 bool system_level,
529 InstallationType* type) {
530 DCHECK(type);
531 bool rock_on = true;
532 *type = NO_PRODUCTS;
534 // Does the system have any multi-installed products?
535 const ProductState* multi_state =
536 machine_state.GetProductState(system_level,
537 BrowserDistribution::CHROME_BINARIES);
538 if (multi_state != NULL)
539 ValidateBinaries(machine_state, system_level, *multi_state, &rock_on);
541 // Is Chrome installed?
542 const ProductState* product_state =
543 machine_state.GetProductState(system_level,
544 BrowserDistribution::CHROME_BROWSER);
545 if (product_state != NULL) {
546 ChromeRules chrome_rules;
547 ValidateProduct(machine_state, system_level, *product_state,
548 chrome_rules, &rock_on);
549 *type = static_cast<InstallationType>(
550 *type | (product_state->is_multi_install() ?
551 ProductBits::CHROME_MULTI :
552 ProductBits::CHROME_SINGLE));
555 // Is Chrome Frame installed?
556 product_state =
557 machine_state.GetProductState(system_level,
558 BrowserDistribution::CHROME_FRAME);
559 if (product_state != NULL) {
560 ChromeFrameRules chrome_frame_rules;
561 ValidateProduct(machine_state, system_level, *product_state,
562 chrome_frame_rules, &rock_on);
563 int cf_bit = !product_state->is_multi_install() ?
564 ProductBits::CHROME_FRAME_SINGLE :
565 ProductBits::CHROME_FRAME_MULTI;
566 *type = static_cast<InstallationType>(*type | cf_bit);
569 DCHECK_NE(std::find(&kInstallationTypes[0],
570 &kInstallationTypes[arraysize(kInstallationTypes)],
571 *type),
572 &kInstallationTypes[arraysize(kInstallationTypes)])
573 << "Invalid combination of products found on system (" << *type << ")";
575 return rock_on;
578 // static
579 bool InstallationValidator::ValidateInstallationType(bool system_level,
580 InstallationType* type) {
581 DCHECK(type);
582 InstallationState machine_state;
584 machine_state.Initialize();
586 return ValidateInstallationTypeForState(machine_state, system_level, type);
589 } // namespace installer