OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 // | 4 // |
5 // This file defines functions that integrate Chrome in Windows shell. These | 5 // This file defines functions that integrate Chrome in Windows shell. These |
6 // functions can be used by Chrome as well as Chrome installer. All of the | 6 // functions can be used by Chrome as well as Chrome installer. All of the |
7 // work is done by the local functions defined in anonymous namespace in | 7 // work is done by the local functions defined in anonymous namespace in |
8 // this class. | 8 // this class. |
9 | 9 |
10 #include "chrome/installer/util/shell_util.h" | 10 #include "chrome/installer/util/shell_util.h" |
11 | 11 |
| 12 #include <shlobj.h> |
12 #include <windows.h> | 13 #include <windows.h> |
13 #include <shlobj.h> | |
14 | 14 |
| 15 #include <limits> |
15 #include <list> | 16 #include <list> |
16 | 17 |
17 #include "base/command_line.h" | 18 #include "base/command_line.h" |
18 #include "base/file_path.h" | 19 #include "base/file_path.h" |
19 #include "base/file_util.h" | 20 #include "base/file_util.h" |
| 21 #include "base/lazy_instance.h" |
20 #include "base/logging.h" | 22 #include "base/logging.h" |
| 23 #include "base/md5.h" |
21 #include "base/memory/scoped_ptr.h" | 24 #include "base/memory/scoped_ptr.h" |
22 #include "base/path_service.h" | 25 #include "base/path_service.h" |
23 #include "base/stl_util.h" | 26 #include "base/stl_util.h" |
24 #include "base/string_number_conversions.h" | 27 #include "base/string_number_conversions.h" |
25 #include "base/string_split.h" | 28 #include "base/string_split.h" |
26 #include "base/string_util.h" | 29 #include "base/string_util.h" |
27 #include "base/utf_string_conversions.h" | 30 #include "base/utf_string_conversions.h" |
28 #include "base/values.h" | 31 #include "base/values.h" |
29 #include "base/win/registry.h" | 32 #include "base/win/registry.h" |
30 #include "base/win/scoped_comptr.h" | 33 #include "base/win/scoped_comptr.h" |
| 34 #include "base/win/win_util.h" |
31 #include "base/win/windows_version.h" | 35 #include "base/win/windows_version.h" |
32 #include "chrome/common/chrome_constants.h" | 36 #include "chrome/common/chrome_constants.h" |
33 #include "chrome/common/chrome_switches.h" | 37 #include "chrome/common/chrome_switches.h" |
34 #include "chrome/installer/util/browser_distribution.h" | 38 #include "chrome/installer/util/browser_distribution.h" |
35 #include "chrome/installer/util/install_util.h" | 39 #include "chrome/installer/util/install_util.h" |
36 #include "chrome/installer/util/master_preferences.h" | 40 #include "chrome/installer/util/master_preferences.h" |
37 #include "chrome/installer/util/master_preferences_constants.h" | 41 #include "chrome/installer/util/master_preferences_constants.h" |
38 | 42 |
39 using base::win::RegKey; | 43 using base::win::RegKey; |
40 | 44 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
78 VER_SET_CONDITION(condition_mask, VER_BUILDNUMBER, VER_GREATER_EQUAL); | 82 VER_SET_CONDITION(condition_mask, VER_BUILDNUMBER, VER_GREATER_EQUAL); |
79 VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); | 83 VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); |
80 VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL); | 84 VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL); |
81 | 85 |
82 DWORD type_mask = VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER | | 86 DWORD type_mask = VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER | |
83 VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR; | 87 VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR; |
84 | 88 |
85 return VerifyVersionInfo(&min_version_info, type_mask, condition_mask) != 0; | 89 return VerifyVersionInfo(&min_version_info, type_mask, condition_mask) != 0; |
86 } | 90 } |
87 | 91 |
| 92 // Returns the current (or installed) browser's ProgId (e.g. |
| 93 // "ChromeHTML|suffix|"). |
| 94 // |suffix| can be the empty string. |
| 95 string16 GetBrowserProgId(const string16& suffix) { |
| 96 string16 chrome_html(ShellUtil::kChromeHTMLProgId); |
| 97 chrome_html.append(suffix); |
| 98 |
| 99 // ProgIds cannot be longer than 39 characters. |
| 100 // Ref: http://msdn.microsoft.com/en-us/library/aa911706.aspx. |
| 101 // Make all new registrations comply with this requirement (existing |
| 102 // registrations must be preserved). |
| 103 string16 new_style_suffix; |
| 104 if (ShellUtil::GetUserSpecificRegistrySuffix(&new_style_suffix) && |
| 105 suffix == new_style_suffix && chrome_html.length() > 39) { |
| 106 NOTREACHED(); |
| 107 chrome_html.erase(39); |
| 108 } |
| 109 return chrome_html; |
| 110 } |
| 111 |
| 112 // This class is used to initialize and cache a base 32 encoding of the md5 hash |
| 113 // of this user's sid preceded by a dot. |
| 114 // This is guaranteed to be unique on the machine and 27 characters long |
| 115 // (including the '.'). |
| 116 // This is then meant to be used as a suffix on all registrations that may |
| 117 // conflict with another user-level Chrome install. |
| 118 class UserSpecificRegistrySuffix { |
| 119 public: |
| 120 // All the initialization is done in the constructor to be able to build the |
| 121 // suffix in a thread-safe manner when used in conjunction with a |
| 122 // LazyInstance. |
| 123 UserSpecificRegistrySuffix(); |
| 124 |
| 125 // Sets |suffix| to the pre-computed suffix cached in this object. |
| 126 // Returns true unless the initialization originally failed. |
| 127 bool GetSuffix(string16* suffix); |
| 128 |
| 129 private: |
| 130 string16 suffix_; |
| 131 |
| 132 DISALLOW_COPY_AND_ASSIGN(UserSpecificRegistrySuffix); |
| 133 }; // class UserSpecificRegistrySuffix |
| 134 |
| 135 UserSpecificRegistrySuffix::UserSpecificRegistrySuffix() { |
| 136 string16 user_sid; |
| 137 if (!base::win::GetUserSidString(&user_sid)) { |
| 138 NOTREACHED(); |
| 139 return; |
| 140 } |
| 141 COMPILE_ASSERT(sizeof(base::MD5Digest) == 16, size_of_MD5_not_as_expected_); |
| 142 base::MD5Digest md5_digest; |
| 143 base::MD5Sum(user_sid.c_str(), user_sid.length(), &md5_digest); |
| 144 const string16 base32_md5( |
| 145 ShellUtil::ByteArrayToBase32(md5_digest.a, arraysize(md5_digest.a))); |
| 146 // The value returned by the base32 algorithm above must never change and |
| 147 // must always be 26 characters long (i.e. if someone ever moves this to |
| 148 // base and implements the full base32 algorithm (i.e. with appended '=' |
| 149 // signs in the output), they must provide a flag to allow this method to |
| 150 // still request the output with no appended '=' signs). |
| 151 DCHECK_EQ(base32_md5.length(), 26U); |
| 152 suffix_.reserve(base32_md5.length() + 1); |
| 153 suffix_.assign(1, L'.'); |
| 154 suffix_.append(base32_md5); |
| 155 } |
| 156 |
| 157 bool UserSpecificRegistrySuffix::GetSuffix(string16* suffix) { |
| 158 if (suffix_.empty()) { |
| 159 NOTREACHED(); |
| 160 return false; |
| 161 } |
| 162 suffix->assign(suffix_); |
| 163 return true; |
| 164 } |
| 165 |
88 // This class represents a single registry entry. The objective is to | 166 // This class represents a single registry entry. The objective is to |
89 // encapsulate all the registry entries required for registering Chrome at one | 167 // encapsulate all the registry entries required for registering Chrome at one |
90 // place. This class can not be instantiated outside the class and the objects | 168 // place. This class can not be instantiated outside the class and the objects |
91 // of this class type can be obtained only by calling a static method of this | 169 // of this class type can be obtained only by calling a static method of this |
92 // class. | 170 // class. |
93 class RegistryEntry { | 171 class RegistryEntry { |
94 public: | 172 public: |
95 // A bit-field enum of places to look for this key in the Windows registry. | 173 // A bit-field enum of places to look for this key in the Windows registry. |
96 enum LookForIn { | 174 enum LookForIn { |
97 LOOK_IN_HKCU = 1 << 0, | 175 LOOK_IN_HKCU = 1 << 0, |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
174 // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb>\command | 252 // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb>\command |
175 entries->push_front(new RegistryEntry(sub_path, delegate_command)); | 253 entries->push_front(new RegistryEntry(sub_path, delegate_command)); |
176 entries->push_front(new RegistryEntry( | 254 entries->push_front(new RegistryEntry( |
177 sub_path, ShellUtil::kRegDelegateExecute, delegate_guid)); | 255 sub_path, ShellUtil::kRegDelegateExecute, delegate_guid)); |
178 } | 256 } |
179 } | 257 } |
180 | 258 |
181 // File association ProgId | 259 // File association ProgId |
182 string16 chrome_html_prog_id(ShellUtil::kRegClasses); | 260 string16 chrome_html_prog_id(ShellUtil::kRegClasses); |
183 chrome_html_prog_id.push_back(FilePath::kSeparators[0]); | 261 chrome_html_prog_id.push_back(FilePath::kSeparators[0]); |
184 chrome_html_prog_id.append(ShellUtil::kChromeHTMLProgId); | 262 chrome_html_prog_id.append(GetBrowserProgId(suffix)); |
185 chrome_html_prog_id.append(suffix); | |
186 entries->push_front(new RegistryEntry( | 263 entries->push_front(new RegistryEntry( |
187 chrome_html_prog_id, ShellUtil::kChromeHTMLProgIdDesc)); | 264 chrome_html_prog_id, ShellUtil::kChromeHTMLProgIdDesc)); |
188 entries->push_front(new RegistryEntry( | 265 entries->push_front(new RegistryEntry( |
189 chrome_html_prog_id, ShellUtil::kRegUrlProtocol, L"")); | 266 chrome_html_prog_id, ShellUtil::kRegUrlProtocol, L"")); |
190 entries->push_front(new RegistryEntry( | 267 entries->push_front(new RegistryEntry( |
191 chrome_html_prog_id + ShellUtil::kRegDefaultIcon, icon_path)); | 268 chrome_html_prog_id + ShellUtil::kRegDefaultIcon, icon_path)); |
192 entries->push_front(new RegistryEntry( | 269 entries->push_front(new RegistryEntry( |
193 chrome_html_prog_id + ShellUtil::kRegShellOpen, open_cmd)); | 270 chrome_html_prog_id + ShellUtil::kRegShellOpen, open_cmd)); |
194 if (set_delegate_execute) { | 271 if (set_delegate_execute) { |
195 entries->push_front(new RegistryEntry( | 272 entries->push_front(new RegistryEntry( |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
227 } | 304 } |
228 | 305 |
229 // This method returns a list of the registry entries needed to declare a | 306 // This method returns a list of the registry entries needed to declare a |
230 // capability of handling a protocol on Windows. | 307 // capability of handling a protocol on Windows. |
231 static bool GetProtocolCapabilityEntries(BrowserDistribution* dist, | 308 static bool GetProtocolCapabilityEntries(BrowserDistribution* dist, |
232 const string16& suffix, | 309 const string16& suffix, |
233 const string16& protocol, | 310 const string16& protocol, |
234 std::list<RegistryEntry*>* entries) { | 311 std::list<RegistryEntry*>* entries) { |
235 entries->push_front(new RegistryEntry( | 312 entries->push_front(new RegistryEntry( |
236 GetCapabilitiesKey(dist, suffix).append(L"\\URLAssociations"), | 313 GetCapabilitiesKey(dist, suffix).append(L"\\URLAssociations"), |
237 protocol, string16(ShellUtil::kChromeHTMLProgId).append(suffix))); | 314 protocol, GetBrowserProgId(suffix))); |
238 return true; | 315 return true; |
239 } | 316 } |
240 | 317 |
241 // This method returns a list of all the registry entries required to fully | 318 // This method returns a list of all the registry entries required to fully |
242 // integrate Chrome with Windows (i.e. StartMenuInternet, Default Programs, | 319 // integrate Chrome with Windows (i.e. StartMenuInternet, Default Programs, |
243 // AppPaths, etc.). This entries need to be registered in HKLM prior to Win8. | 320 // AppPaths, etc.). This entries need to be registered in HKLM prior to Win8. |
244 static bool GetShellIntegrationEntries(BrowserDistribution* dist, | 321 static bool GetShellIntegrationEntries(BrowserDistribution* dist, |
245 const string16& chrome_exe, | 322 const string16& chrome_exe, |
246 const string16& suffix, | 323 const string16& suffix, |
247 std::list<RegistryEntry*>* entries) { | 324 std::list<RegistryEntry*>* entries) { |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
288 dist->GetLongAppDescription())); | 365 dist->GetLongAppDescription())); |
289 entries->push_front(new RegistryEntry( | 366 entries->push_front(new RegistryEntry( |
290 capabilities, ShellUtil::kRegApplicationIcon, icon_path)); | 367 capabilities, ShellUtil::kRegApplicationIcon, icon_path)); |
291 entries->push_front(new RegistryEntry( | 368 entries->push_front(new RegistryEntry( |
292 capabilities, ShellUtil::kRegApplicationName, | 369 capabilities, ShellUtil::kRegApplicationName, |
293 dist->GetAppShortCutName())); | 370 dist->GetAppShortCutName())); |
294 | 371 |
295 entries->push_front(new RegistryEntry(capabilities + L"\\Startmenu", | 372 entries->push_front(new RegistryEntry(capabilities + L"\\Startmenu", |
296 L"StartMenuInternet", reg_app_name)); | 373 L"StartMenuInternet", reg_app_name)); |
297 | 374 |
298 string16 html_prog_id(ShellUtil::kChromeHTMLProgId); | 375 string16 html_prog_id(GetBrowserProgId(suffix)); |
299 html_prog_id.append(suffix); | |
300 for (int i = 0; ShellUtil::kFileAssociations[i] != NULL; i++) { | 376 for (int i = 0; ShellUtil::kFileAssociations[i] != NULL; i++) { |
301 entries->push_front(new RegistryEntry( | 377 entries->push_front(new RegistryEntry( |
302 capabilities + L"\\FileAssociations", | 378 capabilities + L"\\FileAssociations", |
303 ShellUtil::kFileAssociations[i], html_prog_id)); | 379 ShellUtil::kFileAssociations[i], html_prog_id)); |
304 } | 380 } |
305 for (int i = 0; ShellUtil::kPotentialProtocolAssociations[i] != NULL; | 381 for (int i = 0; ShellUtil::kPotentialProtocolAssociations[i] != NULL; |
306 i++) { | 382 i++) { |
307 entries->push_front(new RegistryEntry( | 383 entries->push_front(new RegistryEntry( |
308 capabilities + L"\\URLAssociations", | 384 capabilities + L"\\URLAssociations", |
309 ShellUtil::kPotentialProtocolAssociations[i], html_prog_id)); | 385 ShellUtil::kPotentialProtocolAssociations[i], html_prog_id)); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
358 return true; | 434 return true; |
359 } | 435 } |
360 | 436 |
361 // This method returns a list of all the user level registry entries that | 437 // This method returns a list of all the user level registry entries that |
362 // are needed to make Chromium default browser. | 438 // are needed to make Chromium default browser. |
363 static bool GetUserEntries(BrowserDistribution* dist, | 439 static bool GetUserEntries(BrowserDistribution* dist, |
364 const string16& chrome_exe, | 440 const string16& chrome_exe, |
365 const string16& suffix, | 441 const string16& suffix, |
366 std::list<RegistryEntry*>* entries) { | 442 std::list<RegistryEntry*>* entries) { |
367 // File extension associations. | 443 // File extension associations. |
368 string16 html_prog_id(ShellUtil::kChromeHTMLProgId); | 444 string16 html_prog_id(GetBrowserProgId(suffix)); |
369 html_prog_id.append(suffix); | |
370 for (int i = 0; ShellUtil::kFileAssociations[i] != NULL; i++) { | 445 for (int i = 0; ShellUtil::kFileAssociations[i] != NULL; i++) { |
371 string16 ext_key(ShellUtil::kRegClasses); | 446 string16 ext_key(ShellUtil::kRegClasses); |
372 ext_key.push_back(FilePath::kSeparators[0]); | 447 ext_key.push_back(FilePath::kSeparators[0]); |
373 ext_key.append(ShellUtil::kFileAssociations[i]); | 448 ext_key.append(ShellUtil::kFileAssociations[i]); |
374 entries->push_front(new RegistryEntry(ext_key, html_prog_id)); | 449 entries->push_front(new RegistryEntry(ext_key, html_prog_id)); |
375 } | 450 } |
376 | 451 |
377 // Protocols associations. | 452 // Protocols associations. |
378 string16 chrome_open = ShellUtil::GetChromeShellOpenCmd(chrome_exe); | 453 string16 chrome_open = ShellUtil::GetChromeShellOpenCmd(chrome_exe); |
379 string16 chrome_icon = ShellUtil::GetChromeIcon(dist, chrome_exe); | 454 string16 chrome_icon = ShellUtil::GetChromeIcon(dist, chrome_exe); |
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
670 | 745 |
671 // <root hkey>\Software\Classes\<app_id> | 746 // <root hkey>\Software\Classes\<app_id> |
672 string16 key(ShellUtil::kRegClasses); | 747 string16 key(ShellUtil::kRegClasses); |
673 key.push_back(FilePath::kSeparators[0]); | 748 key.push_back(FilePath::kSeparators[0]); |
674 key.append(app_id); | 749 key.append(app_id); |
675 InstallUtil::DeleteRegistryKey(root_key, key); | 750 InstallUtil::DeleteRegistryKey(root_key, key); |
676 | 751 |
677 // <root hkey>\Software\Classes\ChromiumHTML[.user]\shell\open\command | 752 // <root hkey>\Software\Classes\ChromiumHTML[.user]\shell\open\command |
678 key = ShellUtil::kRegClasses; | 753 key = ShellUtil::kRegClasses; |
679 key.push_back(FilePath::kSeparators[0]); | 754 key.push_back(FilePath::kSeparators[0]); |
680 key.append(ShellUtil::kChromeHTMLProgId); | 755 key.append(GetBrowserProgId(installation_suffix)); |
681 key.append(installation_suffix); | |
682 key.append(ShellUtil::kRegShellOpen); | 756 key.append(ShellUtil::kRegShellOpen); |
683 InstallUtil::DeleteRegistryValue(root_key, key, | 757 InstallUtil::DeleteRegistryValue(root_key, key, |
684 ShellUtil::kRegDelegateExecute); | 758 ShellUtil::kRegDelegateExecute); |
685 } | 759 } |
686 } | 760 } |
687 | 761 |
688 // Returns true if the current install's |chrome_exe| has been registered with | 762 // Returns true if the current install's |chrome_exe| has been registered with |
689 // |suffix|. | 763 // |suffix|. |
690 // |confirmation_level| is the level of verification desired as described in | 764 // |confirmation_level| is the level of verification desired as described in |
691 // the RegistrationConfirmationLevel enum above. | 765 // the RegistrationConfirmationLevel enum above. |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
740 // Assert that |reg_key| points to |chrome_exe| in HKLM. | 814 // Assert that |reg_key| points to |chrome_exe| in HKLM. |
741 const RegKey key_hklm(HKEY_LOCAL_MACHINE, reg_key.c_str(), KEY_QUERY_VALUE); | 815 const RegKey key_hklm(HKEY_LOCAL_MACHINE, reg_key.c_str(), KEY_QUERY_VALUE); |
742 string16 hklm_value; | 816 string16 hklm_value; |
743 if (key_hklm.ReadValue(L"", &hklm_value) == ERROR_SUCCESS) { | 817 if (key_hklm.ReadValue(L"", &hklm_value) == ERROR_SUCCESS) { |
744 return InstallUtil::ProgramCompare( | 818 return InstallUtil::ProgramCompare( |
745 FilePath(chrome_exe)).Evaluate(hklm_value); | 819 FilePath(chrome_exe)).Evaluate(hklm_value); |
746 } | 820 } |
747 return false; | 821 return false; |
748 } | 822 } |
749 | 823 |
750 // Sets |suffix| to this user's username preceded by a dot. This suffix is then | 824 // Sets |suffix| to a 27 character string that is specific to this user on this |
751 // meant to be added to all registration that may conflict with another | 825 // machine (on user-level installs only). |
752 // user-level Chrome install. | 826 // To support old-style user-level installs however, |suffix| is cleared if the |
753 // Returns true unless the OS call to retrieve the username fails. | 827 // user currently owns the non-suffixed HKLM registrations. |
754 bool GetUserSpecificRegistrySuffix(string16* suffix) { | 828 // |suffix| can also be set to the user's username if the current install is |
755 wchar_t user_name[256]; | 829 // suffixed as per the old-style registrations. |
756 DWORD size = arraysize(user_name); | 830 // |suffix| is cleared on system-level installs. |
757 if (::GetUserName(user_name, &size) == 0 || size < 1) { | |
758 PLOG(DFATAL) << "GetUserName failed"; | |
759 return false; | |
760 } | |
761 suffix->reserve(size); | |
762 suffix->assign(1, L'.'); | |
763 suffix->append(user_name, size - 1); | |
764 return true; | |
765 } | |
766 | |
767 // Sets |suffix| to the current user's username, preceded by a dot, on | |
768 // user-level installs. | |
769 // To support old-style user-level installs however, |suffix| is cleared if | |
770 // the user currently owns the non-suffixed HKLM registrations. | |
771 // |suffix| is also cleared on system-level installs. | |
772 // |suffix| should then be appended to all Chrome properties that may conflict | 831 // |suffix| should then be appended to all Chrome properties that may conflict |
773 // with other Chrome user-level installs. | 832 // with other Chrome user-level installs. |
774 // Returns true unless one of the underlying calls fails. | 833 // Returns true unless one of the underlying calls fails. |
775 bool GetInstallationSpecificSuffix(BrowserDistribution* dist, | 834 bool GetInstallationSpecificSuffix(BrowserDistribution* dist, |
776 const string16& chrome_exe, | 835 const string16& chrome_exe, |
777 string16* suffix) { | 836 string16* suffix) { |
778 if (!InstallUtil::IsPerUserInstall(chrome_exe.c_str()) || | 837 if (!InstallUtil::IsPerUserInstall(chrome_exe.c_str()) || |
779 QuickIsChromeRegistered(dist, chrome_exe, string16(), | 838 QuickIsChromeRegistered(dist, chrome_exe, string16(), |
780 CONFIRM_SHELL_REGISTRATION)) { | 839 CONFIRM_SHELL_REGISTRATION)) { |
781 // No suffix on system-level installs and user-level installs already | 840 // No suffix on system-level installs and user-level installs already |
782 // registered with no suffix. | 841 // registered with no suffix. |
783 suffix->clear(); | 842 suffix->clear(); |
784 return true; | 843 return true; |
785 } else { | |
786 return GetUserSpecificRegistrySuffix(suffix); | |
787 } | 844 } |
| 845 |
| 846 // Get the old suffix for the check below. |
| 847 if (!ShellUtil::GetOldUserSpecificRegistrySuffix(suffix)) { |
| 848 NOTREACHED(); |
| 849 return false; |
| 850 } |
| 851 if (QuickIsChromeRegistered(dist, chrome_exe, *suffix, |
| 852 CONFIRM_SHELL_REGISTRATION)) { |
| 853 // Username suffix for installs that are suffixed as per the old-style. |
| 854 return true; |
| 855 } |
| 856 |
| 857 return ShellUtil::GetUserSpecificRegistrySuffix(suffix); |
788 } | 858 } |
789 | 859 |
790 // Returns the root registry key (HKLM or HKCU) into which shell integration | 860 // Returns the root registry key (HKLM or HKCU) into which shell integration |
791 // registration for default protocols must be placed. As of Windows 8 everything | 861 // registration for default protocols must be placed. As of Windows 8 everything |
792 // can go in HKCU for per-user installs. | 862 // can go in HKCU for per-user installs. |
793 HKEY DetermineShellIntegrationRoot(bool is_per_user) { | 863 HKEY DetermineShellIntegrationRoot(bool is_per_user) { |
794 return is_per_user && base::win::GetVersion() >= base::win::VERSION_WIN8 ? | 864 return is_per_user && base::win::GetVersion() >= base::win::VERSION_WIN8 ? |
795 HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE; | 865 HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE; |
796 } | 866 } |
797 | 867 |
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1053 key.ReadValue(kReinstallCommand, &command) == ERROR_SUCCESS && | 1123 key.ReadValue(kReinstallCommand, &command) == ERROR_SUCCESS && |
1054 !command.empty()) { | 1124 !command.empty()) { |
1055 (*browsers)[name] = command; | 1125 (*browsers)[name] = command; |
1056 } | 1126 } |
1057 } | 1127 } |
1058 } | 1128 } |
1059 } | 1129 } |
1060 | 1130 |
1061 string16 ShellUtil::GetCurrentInstallationSuffix(BrowserDistribution* dist, | 1131 string16 ShellUtil::GetCurrentInstallationSuffix(BrowserDistribution* dist, |
1062 const string16& chrome_exe) { | 1132 const string16& chrome_exe) { |
| 1133 // This method is somewhat the opposite of GetInstallationSpecificSuffix(). |
| 1134 // In this case we are not trying to determine the current suffix for the |
| 1135 // upcoming installation (i.e. not trying to stick to a currently bad |
| 1136 // registration style if one is present). |
| 1137 // Here we want to determine which suffix we should use at run-time. |
| 1138 // In order of preference, we prefer (for user-level installs): |
| 1139 // 1) Base 32 encoding of the md5 hash of the user's sid (new-style). |
| 1140 // 2) Username (old-style). |
| 1141 // 3) Unsuffixed (even worse). |
1063 string16 tested_suffix; | 1142 string16 tested_suffix; |
1064 if (!InstallUtil::IsPerUserInstall(chrome_exe.c_str()) || | 1143 if (InstallUtil::IsPerUserInstall(chrome_exe.c_str()) && |
1065 !GetUserSpecificRegistrySuffix(&tested_suffix) || | 1144 (!GetUserSpecificRegistrySuffix(&tested_suffix) || |
1066 !QuickIsChromeRegistered(dist, chrome_exe, tested_suffix, | 1145 !QuickIsChromeRegistered(dist, chrome_exe, tested_suffix, |
| 1146 CONFIRM_PROGID_REGISTRATION)) && |
| 1147 (!GetOldUserSpecificRegistrySuffix(&tested_suffix) || |
| 1148 !QuickIsChromeRegistered(dist, chrome_exe, tested_suffix, |
| 1149 CONFIRM_PROGID_REGISTRATION)) && |
| 1150 !QuickIsChromeRegistered(dist, chrome_exe, tested_suffix.erase(), |
1067 CONFIRM_PROGID_REGISTRATION)) { | 1151 CONFIRM_PROGID_REGISTRATION)) { |
1068 return string16(); | 1152 // If Chrome is not registered under any of the possible suffixes (e.g. |
| 1153 // tests, Canary, etc.): use the new-style suffix at run-time. |
| 1154 if (!GetUserSpecificRegistrySuffix(&tested_suffix)) |
| 1155 NOTREACHED(); |
1069 } | 1156 } |
1070 return tested_suffix; | 1157 return tested_suffix; |
1071 } | 1158 } |
1072 | 1159 |
1073 string16 ShellUtil::GetApplicationName(BrowserDistribution* dist, | 1160 string16 ShellUtil::GetApplicationName(BrowserDistribution* dist, |
1074 const string16& chrome_exe) { | 1161 const string16& chrome_exe) { |
1075 string16 app_name = dist->GetBaseAppName(); | 1162 string16 app_name = dist->GetBaseAppName(); |
1076 app_name += GetCurrentInstallationSuffix(dist, chrome_exe); | 1163 app_name += GetCurrentInstallationSuffix(dist, chrome_exe); |
1077 return app_name; | 1164 return app_name; |
1078 } | 1165 } |
(...skipping 434 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1513 chrome_exe.c_str(), | 1600 chrome_exe.c_str(), |
1514 shortcut.c_str(), | 1601 shortcut.c_str(), |
1515 chrome_path.value().c_str(), | 1602 chrome_path.value().c_str(), |
1516 arguments.c_str(), | 1603 arguments.c_str(), |
1517 description.c_str(), | 1604 description.c_str(), |
1518 icon_path.c_str(), | 1605 icon_path.c_str(), |
1519 icon_index, | 1606 icon_index, |
1520 app_id.c_str(), | 1607 app_id.c_str(), |
1521 ConvertShellUtilShortcutOptionsToFileUtil(options)); | 1608 ConvertShellUtilShortcutOptionsToFileUtil(options)); |
1522 } | 1609 } |
| 1610 |
| 1611 bool ShellUtil::GetUserSpecificRegistrySuffix(string16* suffix) { |
| 1612 // Use a thread-safe cache for the user's suffix. |
| 1613 static base::LazyInstance<UserSpecificRegistrySuffix>::Leaky suffix_instance = |
| 1614 LAZY_INSTANCE_INITIALIZER; |
| 1615 return suffix_instance.Get().GetSuffix(suffix); |
| 1616 } |
| 1617 |
| 1618 bool ShellUtil::GetOldUserSpecificRegistrySuffix(string16* suffix) { |
| 1619 wchar_t user_name[256]; |
| 1620 DWORD size = arraysize(user_name); |
| 1621 if (::GetUserName(user_name, &size) == 0 || size < 1) { |
| 1622 NOTREACHED(); |
| 1623 return false; |
| 1624 } |
| 1625 suffix->reserve(size); |
| 1626 suffix->assign(1, L'.'); |
| 1627 suffix->append(user_name, size - 1); |
| 1628 return true; |
| 1629 } |
| 1630 |
| 1631 string16 ShellUtil::ByteArrayToBase32(const uint8* bytes, size_t size) { |
| 1632 static const char kEncoding[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; |
| 1633 |
| 1634 // Eliminate special cases first. |
| 1635 if (size == 0) { |
| 1636 return string16(); |
| 1637 } else if (size == 1) { |
| 1638 string16 ret; |
| 1639 ret.push_back(kEncoding[(bytes[0] & 0xf8) >> 3]); |
| 1640 ret.push_back(kEncoding[(bytes[0] & 0x07) << 2]); |
| 1641 return ret; |
| 1642 } else if (size >= std::numeric_limits<size_t>::max() / 8) { |
| 1643 // If |size| is too big, the calculation of |encoded_length| below will |
| 1644 // overflow. |
| 1645 NOTREACHED(); |
| 1646 return string16(); |
| 1647 } |
| 1648 |
| 1649 // Overestimate the number of bits in the string by 4 so that dividing by 5 |
| 1650 // is the equivalent of rounding up the actual number of bits divided by 5. |
| 1651 const size_t encoded_length = (size * 8 + 4) / 5; |
| 1652 |
| 1653 string16 ret; |
| 1654 ret.reserve(encoded_length); |
| 1655 |
| 1656 // A bit stream which will be read from the left and appended to from the |
| 1657 // right as it's emptied. |
| 1658 uint16 bit_stream = (bytes[0] << 8) + bytes[1]; |
| 1659 size_t next_byte_index = 2; |
| 1660 int free_bits = 0; |
| 1661 while (free_bits < 16) { |
| 1662 // Extract the 5 leftmost bits in the stream |
| 1663 ret.push_back(kEncoding[(bit_stream & 0xf800) >> 11]); |
| 1664 bit_stream <<= 5; |
| 1665 free_bits += 5; |
| 1666 |
| 1667 // If there is enough room in the bit stream, inject another byte (if there |
| 1668 // are any left...). |
| 1669 if (free_bits >= 8 && next_byte_index < size) { |
| 1670 free_bits -= 8; |
| 1671 bit_stream += bytes[next_byte_index++] << free_bits; |
| 1672 } |
| 1673 } |
| 1674 |
| 1675 DCHECK_EQ(ret.length(), encoded_length); |
| 1676 return ret; |
| 1677 } |
OLD | NEW |