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 // This file declares utility functions for the installer. The original reason
6 // for putting these functions in installer\util library is so that we can
7 // separate out the critical logic and write unit tests for it.
8 
9 #ifndef CHROME_INSTALLER_UTIL_INSTALL_UTIL_H_
10 #define CHROME_INSTALLER_UTIL_INSTALL_UTIL_H_
11 
12 #include <windows.h>
13 #include <string>
14 #include <utility>
15 #include <vector>
16 
17 #include "base/command_line.h"
18 #include "base/files/file.h"
19 #include "base/files/file_path.h"
20 #include "base/macros.h"
21 #include "base/optional.h"
22 #include "base/strings/string16.h"
23 #include "base/strings/string_piece.h"
24 #include "base/util/type_safety/strong_alias.h"
25 #include "base/version.h"
26 #include "base/win/registry.h"
27 #include "base/win/scoped_handle.h"
28 #include "chrome/installer/util/util_constants.h"
29 
30 class WorkItemList;
31 
32 // This is a utility class that provides common installation related
33 // utility methods that can be used by installer and also unit tested
34 // independently.
35 class InstallUtil {
36  public:
37   // Attempts to trigger the command that would be run by Active Setup for a
38   // system-level Chrome. For use only when system-level Chrome is installed.
39   static void TriggerActiveSetupCommand();
40 
41   // Launches given exe as admin on Vista.
42   static bool ExecuteExeAsAdmin(const base::CommandLine& cmd, DWORD* exit_code);
43 
44   // Reads the uninstall command for Chromium from the Windows registry and
45   // returns it. If |system_install| is true the command is read from HKLM,
46   // otherwise from HKCU. Returns an empty CommandLine if Chrome is not
47   // installed.
48   static base::CommandLine GetChromeUninstallCmd(bool system_install);
49 
50   // Returns the version of Chrome registered with Google Update, or an invalid
51   // Version in case no such value could be found. |system_install| indicates
52   // whether HKLM (true) or HKCU (false) should be checked.
53   static base::Version GetChromeVersion(bool system_install);
54 
55   // Returns the last critical update (version) of Chrome, or an invalid Version
56   // in case no such value is found. A critical update is a specially flagged
57   // version (by Google Update) that contains an important security fix.
58   static base::Version GetCriticalUpdateVersion();
59 
60   // This function checks if the current OS is supported for Chromium.
61   static bool IsOSSupported();
62 
63   // Adds work items to |install_list| to set installer error information in the
64   // registry for consumption by Google Update. |install_list| must be best-
65   // effort with rollback disabled. |state_key| must be the full path to an
66   // app's ClientState key.  See InstallerState::WriteInstallerResult for more
67   // details.
68   static void AddInstallerResultItems(bool system_install,
69                                       const base::string16& state_key,
70                                       installer::InstallStatus status,
71                                       int string_resource_id,
72                                       const base::string16* const launch_cmd,
73                                       WorkItemList* install_list);
74 
75   // Returns true if this installation path is per user, otherwise returns false
76   // (per machine install, meaning: the exe_path contains the path to Program
77   // Files).
78   // TODO(grt): consider replacing all callers with direct use of
79   // InstallDetails.
80   static bool IsPerUserInstall();
81 
82   // Returns true if the sentinel file exists (or the path cannot be obtained).
83   static bool IsFirstRunSentinelPresent();
84 
85   // Test to see if a Start menu shortcut exists with the right toast activator
86   // CLSID registered.
87   static bool IsStartMenuShortcutWithActivatorGuidInstalled();
88 
89   // Returns the toast activator registry path.
90   static base::string16 GetToastActivatorRegistryPath();
91 
92   // Populates |path| with EULA sentinel file path. Returns false on error.
93   static bool GetEulaSentinelFilePath(base::FilePath* path);
94 
95   // Deletes the registry key at path key_path under the key given by root_key.
96   static bool DeleteRegistryKey(HKEY root_key,
97                                 const base::string16& key_path,
98                                 REGSAM wow64_access);
99 
100   // Deletes the registry value named value_name at path key_path under the key
101   // given by reg_root.
102   static bool DeleteRegistryValue(HKEY reg_root,
103                                   const base::string16& key_path,
104                                   REGSAM wow64_access,
105                                   const base::string16& value_name);
106 
107   // An interface to a predicate function for use by DeleteRegistryKeyIf and
108   // DeleteRegistryValueIf.
109   class RegistryValuePredicate {
110    public:
~RegistryValuePredicate()111     virtual ~RegistryValuePredicate() {}
112     virtual bool Evaluate(const base::string16& value) const = 0;
113   };
114 
115   // The result of a conditional delete operation (i.e., DeleteFOOIf).
116   enum ConditionalDeleteResult {
117     NOT_FOUND,     // The condition was not satisfied.
118     DELETED,       // The condition was satisfied and the delete succeeded.
119     DELETE_FAILED  // The condition was satisfied but the delete failed.
120   };
121 
122   // Deletes the key |key_to_delete_path| under |root_key| iff the value
123   // |value_name| in the key |key_to_test_path| under |root_key| satisfies
124   // |predicate|.  |value_name| may be either nullptr or an empty string to test
125   // the key's default value.
126   static ConditionalDeleteResult DeleteRegistryKeyIf(
127       HKEY root_key,
128       const base::string16& key_to_delete_path,
129       const base::string16& key_to_test_path,
130       REGSAM wow64_access,
131       const wchar_t* value_name,
132       const RegistryValuePredicate& predicate);
133 
134   // Deletes the value |value_name| in the key |key_path| under |root_key| iff
135   // its current value satisfies |predicate|.  |value_name| may be either
136   // nullptr or an empty string to test/delete the key's default value.
137   static ConditionalDeleteResult DeleteRegistryValueIf(
138       HKEY root_key,
139       const wchar_t* key_path,
140       REGSAM wow64_access,
141       const wchar_t* value_name,
142       const RegistryValuePredicate& predicate);
143 
144   // A predicate that performs a case-sensitive string comparison.
145   class ValueEquals : public RegistryValuePredicate {
146    public:
ValueEquals(const base::string16 & value_to_match)147     explicit ValueEquals(const base::string16& value_to_match)
148         : value_to_match_(value_to_match) {}
149     bool Evaluate(const base::string16& value) const override;
150 
151    protected:
152     base::string16 value_to_match_;
153 
154    private:
155     DISALLOW_COPY_AND_ASSIGN(ValueEquals);
156   };
157 
158   // Returns zero on install success, or an InstallStatus value otherwise.
159   static int GetInstallReturnCode(installer::InstallStatus install_status);
160 
161   // Composes |program| and |arguments| into |command_line|.
162   static void ComposeCommandLine(const base::string16& program,
163                                  const base::string16& arguments,
164                                  base::CommandLine* command_line);
165 
166   // Appends the installer switch that selects the current install mode and
167   // policy-specified channel (see install_static::InstallDetails).
168   static void AppendModeAndChannelSwitches(base::CommandLine* command_line);
169 
170   // Returns a string in the form YYYYMMDD of the current date.
171   static base::string16 GetCurrentDate();
172 
173   // Returns the highest Chrome version that was installed prior to a downgrade,
174   // or no value if Chrome was not previously downgraded from a newer version.
175   static base::Optional<base::Version> GetDowngradeVersion();
176 
177   // Adds or removes downgrade version registry value. This function should only
178   // be used for Chrome install.
179   static void AddUpdateDowngradeVersionItem(
180       HKEY root,
181       const base::Version& current_version,
182       const base::Version& new_version,
183       WorkItemList* list);
184 
185   // Returns pairs of registry key paths and value names where the enrollment
186   // token is stored for machine level user cloud policies. The locations are
187   // returned in order of preference.
188   static std::vector<std::pair<std::wstring, std::wstring>>
189   GetCloudManagementEnrollmentTokenRegistryPaths();
190 
191   using ReadOnly = util::StrongAlias<class ReadOnlyTag, bool>;
192   using BrowserLocation = util::StrongAlias<class BrowserLocationTag, bool>;
193 
194   // Returns the registry key and value name from/to which a cloud management DM
195   // token may be read/written. |read_only| indicates whether they key is opened
196   // for reading the value or writing it. |browser_location| indicates whether
197   // the legacy browser-specific location is returned rather than the
198   // app-neutral location. The returned key will be invalid if it could not be
199   // opened/created.
200   static std::pair<base::win::RegKey, std::wstring>
201   GetCloudManagementDmTokenLocation(ReadOnly read_only,
202                                     BrowserLocation browser_location);
203 
204   // Returns the token used to enroll this chrome instance for machine level
205   // user cloud policies.  Returns an empty string if this machine should not
206   // be enrolled.
207   static base::string16 GetCloudManagementEnrollmentToken();
208 
209   // Returns true if cloud management enrollment is mandatory.
210   static bool ShouldCloudManagementBlockOnFailure();
211 
212   // Returns the localized name of the browser.
213   static base::string16 GetDisplayName();
214 
215   // Returns the app description for shortcuts.
216   static base::string16 GetAppDescription();
217 
218   // Returns the name of the browser's publisher.
219   static base::string16 GetPublisherName();
220 
221   // Returns the name of Chrome's shortcut in the Start Menu (among other
222   // places).
223   static base::string16 GetShortcutName();
224 
225   // Returns the name of the subdirectory in which Chrome's Start Menu shortcut
226   // was once placed. This remains purely to migrate old installs to the new
227   // style.
228   static base::string16 GetChromeShortcutDirNameDeprecated();
229 
230   // Returns the name of the subdirectory in the Start Menu in which Chrome
231   // apps' shortcuts are placed.
232   static base::string16 GetChromeAppsShortcutDirName();
233 
234   // Returns the long description of Chrome used when registering as a browser
235   // with Windows.
236   static base::string16 GetLongAppDescription();
237 
238   // A predicate that compares the program portion of a command line with a
239   // given file path.  First, the file paths are compared directly.  If they do
240   // not match, the filesystem is consulted to determine if the paths reference
241   // the same file.
242   class ProgramCompare : public RegistryValuePredicate {
243    public:
244     explicit ProgramCompare(const base::FilePath& path_to_match);
245     ~ProgramCompare() override;
246     bool Evaluate(const base::string16& value) const override;
247     bool EvaluatePath(const base::FilePath& path) const;
248 
249    protected:
250     static bool OpenForInfo(const base::FilePath& path, base::File* file);
251     static bool GetInfo(const base::File& file,
252                         BY_HANDLE_FILE_INFORMATION* info);
253 
254     base::FilePath path_to_match_;
255     base::File file_;
256     BY_HANDLE_FILE_INFORMATION file_info_;
257 
258    private:
259     DISALLOW_COPY_AND_ASSIGN(ProgramCompare);
260   };  // class ProgramCompare
261 
262   // Converts a product GUID into a SQuished gUID that is used for MSI installer
263   // registry entries.
264   static base::string16 GuidToSquid(base::StringPiece16 guid);
265 
266  private:
267   DISALLOW_COPY_AND_ASSIGN(InstallUtil);
268 };
269 
270 #endif  // CHROME_INSTALLER_UTIL_INSTALL_UTIL_H_
271