| 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 <windows.h> | 12 #include <windows.h> |
| 13 #include <shlobj.h> | 13 #include <shlobj.h> |
| 14 #include <shobjidl.h> | 14 #include <shobjidl.h> |
| 15 | 15 |
| 16 #include <algorithm> | 16 #include <algorithm> |
| 17 #include <iterator> | 17 #include <iterator> |
| 18 #include <limits> | 18 #include <limits> |
| 19 #include <memory> | 19 #include <memory> |
| 20 #include <string> | 20 #include <string> |
| 21 #include <utility> | 21 #include <utility> |
| 22 | 22 |
| 23 #include "base/bind.h" | 23 #include "base/bind.h" |
| 24 #include "base/callback_helpers.h" |
| 24 #include "base/command_line.h" | 25 #include "base/command_line.h" |
| 25 #include "base/files/file_enumerator.h" | 26 #include "base/files/file_enumerator.h" |
| 26 #include "base/files/file_path.h" | 27 #include "base/files/file_path.h" |
| 27 #include "base/files/file_util.h" | 28 #include "base/files/file_util.h" |
| 28 #include "base/lazy_instance.h" | 29 #include "base/lazy_instance.h" |
| 29 #include "base/logging.h" | 30 #include "base/logging.h" |
| 30 #include "base/macros.h" | 31 #include "base/macros.h" |
| 31 #include "base/md5.h" | 32 #include "base/md5.h" |
| 32 #include "base/memory/ptr_util.h" | 33 #include "base/memory/ptr_util.h" |
| 33 #include "base/metrics/histogram_macros.h" | 34 #include "base/metrics/histogram_macros.h" |
| (...skipping 641 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 675 uint32_t look_for_in) { | 676 uint32_t look_for_in) { |
| 676 std::vector<std::unique_ptr<RegistryEntry>> entries; | 677 std::vector<std::unique_ptr<RegistryEntry>> entries; |
| 677 GetProtocolCapabilityEntries(suffix, protocol, &entries); | 678 GetProtocolCapabilityEntries(suffix, protocol, &entries); |
| 678 return AreEntriesAsDesired(entries, look_for_in); | 679 return AreEntriesAsDesired(entries, look_for_in); |
| 679 } | 680 } |
| 680 | 681 |
| 681 // This method registers Chrome by launching an elevated setup.exe. That will | 682 // This method registers Chrome by launching an elevated setup.exe. That will |
| 682 // show the user the standard elevation prompt. If the user accepts it the new | 683 // show the user the standard elevation prompt. If the user accepts it the new |
| 683 // process will make the necessary changes and return SUCCESS that we capture | 684 // process will make the necessary changes and return SUCCESS that we capture |
| 684 // and return. If protocol is non-empty we will also register Chrome as being | 685 // and return. If protocol is non-empty we will also register Chrome as being |
| 685 // capable of handling the protocol. This is most commonly used on per-user | 686 // capable of handling the protocol. This is used for general browser |
| 686 // installs on Windows 7 where setup.exe did not have permission to register | 687 // registration on Windows 7 for per-user installs where setup.exe did not have |
| 687 // Chrome during install. It may also be used on all OSs for system-level | 688 // permission to register Chrome during install. It may also be used on Windows |
| 688 // installs in case Chrome's registration is somehow broken or missing. | 689 // 7 for system-level installs to register Chrome for a specific protocol. |
| 689 bool ElevateAndRegisterChrome(BrowserDistribution* dist, | 690 bool ElevateAndRegisterChrome(BrowserDistribution* dist, |
| 690 const base::FilePath& chrome_exe, | 691 const base::FilePath& chrome_exe, |
| 691 const base::string16& suffix, | 692 const base::string16& suffix, |
| 692 const base::string16& protocol) { | 693 const base::string16& protocol) { |
| 693 // Check for setup.exe in the same directory as chrome.exe, as is the case | 694 // Check for setup.exe in the same directory as chrome.exe, as is the case |
| 694 // when running out of a build output directory. | 695 // when running out of a build output directory. |
| 695 base::FilePath exe_path = chrome_exe.DirName().Append(installer::kSetupExe); | 696 base::FilePath exe_path = chrome_exe.DirName().Append(installer::kSetupExe); |
| 696 | 697 |
| 697 // Failing that, read the path to setup.exe from Chrome's ClientState key, | 698 // Failing that, read the path to setup.exe from Chrome's ClientState key, |
| 698 // which is the canonical location of the installer for all types of installs | 699 // which is the canonical location of the installer for all types of installs |
| (...skipping 1382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2081 // install is also present, it will lead IsChromeRegistered() to think this | 2082 // install is also present, it will lead IsChromeRegistered() to think this |
| 2082 // system-level install isn't registered properly as it is shadowed by the | 2083 // system-level install isn't registered properly as it is shadowed by the |
| 2083 // user-level install's registrations). | 2084 // user-level install's registrations). |
| 2084 uint32_t look_for_in = user_level ? RegistryEntry::LOOK_IN_HKCU_THEN_HKLM | 2085 uint32_t look_for_in = user_level ? RegistryEntry::LOOK_IN_HKCU_THEN_HKLM |
| 2085 : RegistryEntry::LOOK_IN_HKLM; | 2086 : RegistryEntry::LOOK_IN_HKLM; |
| 2086 | 2087 |
| 2087 // Check if chrome is already registered with this suffix. | 2088 // Check if chrome is already registered with this suffix. |
| 2088 if (IsChromeRegistered(dist, chrome_exe, suffix, look_for_in)) | 2089 if (IsChromeRegistered(dist, chrome_exe, suffix, look_for_in)) |
| 2089 return true; | 2090 return true; |
| 2090 | 2091 |
| 2091 bool result = true; | 2092 // Ensure that the shell is notified of the mutations below. Specific exit |
| 2093 // points may disable this if no mutations are made. |
| 2094 base::ScopedClosureRunner notify_on_exit(base::Bind([] { |
| 2095 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr); |
| 2096 })); |
| 2097 |
| 2098 // Do the full registration at user-level or if the user is an admin. |
| 2092 if (root == HKEY_CURRENT_USER || IsUserAnAdmin()) { | 2099 if (root == HKEY_CURRENT_USER || IsUserAnAdmin()) { |
| 2093 // Do the full registration if we can do it at user-level or if the user is | |
| 2094 // an admin. | |
| 2095 std::vector<std::unique_ptr<RegistryEntry>> progid_and_appreg_entries; | 2100 std::vector<std::unique_ptr<RegistryEntry>> progid_and_appreg_entries; |
| 2096 std::vector<std::unique_ptr<RegistryEntry>> shell_entries; | 2101 std::vector<std::unique_ptr<RegistryEntry>> shell_entries; |
| 2097 GetChromeProgIdEntries(dist, chrome_exe, suffix, | 2102 GetChromeProgIdEntries(dist, chrome_exe, suffix, |
| 2098 &progid_and_appreg_entries); | 2103 &progid_and_appreg_entries); |
| 2099 GetChromeAppRegistrationEntries(chrome_exe, suffix, | 2104 GetChromeAppRegistrationEntries(chrome_exe, suffix, |
| 2100 &progid_and_appreg_entries); | 2105 &progid_and_appreg_entries); |
| 2101 GetShellIntegrationEntries(dist, chrome_exe, suffix, &shell_entries); | 2106 GetShellIntegrationEntries(dist, chrome_exe, suffix, &shell_entries); |
| 2102 result = (AddRegistryEntries(root, progid_and_appreg_entries) && | 2107 return AddRegistryEntries(root, progid_and_appreg_entries) && |
| 2103 AddRegistryEntries(root, shell_entries)); | 2108 AddRegistryEntries(root, shell_entries); |
| 2104 } else if (elevate_if_not_admin && | 2109 } |
| 2105 base::win::GetVersion() >= base::win::VERSION_VISTA && | 2110 // The installer is responsible for registration for system-level installs, so |
| 2111 // never try to do it here. Getting to this point for a system-level install |
| 2112 // likely means that IsChromeRegistered thinks registration is broken due to |
| 2113 // localization issues (see https://crbug.com/717913#c18). It likely is not, |
| 2114 // so return success to allow Chrome to be made default. |
| 2115 if (!user_level) { |
| 2116 notify_on_exit.Release().Reset(); |
| 2117 return true; |
| 2118 } |
| 2119 // Try to elevate and register if requested for per-user installs if the user |
| 2120 // is not an admin. |
| 2121 if (elevate_if_not_admin && |
| 2106 ElevateAndRegisterChrome(dist, chrome_exe, suffix, base::string16())) { | 2122 ElevateAndRegisterChrome(dist, chrome_exe, suffix, base::string16())) { |
| 2107 // If the user is not an admin and OS is between Vista and Windows 7 | 2123 return true; |
| 2108 // inclusively, try to elevate and register. This is only intended for | 2124 } |
| 2109 // user-level installs as system-level installs should always be run with | 2125 // If we got to this point then all we can do is create ProgId and basic app |
| 2110 // admin rights. | 2126 // registrations under HKCU. |
| 2111 result = true; | 2127 std::vector<std::unique_ptr<RegistryEntry>> entries; |
| 2112 } else { | 2128 GetChromeProgIdEntries(dist, chrome_exe, base::string16(), &entries); |
| 2113 // If we got to this point then all we can do is create ProgId and basic app | 2129 // Prefer to use |suffix|; unless Chrome's ProgIds are already registered with |
| 2114 // registrations under HKCU. | 2130 // no suffix (as per the old registration style): in which case some other |
| 2115 std::vector<std::unique_ptr<RegistryEntry>> entries; | 2131 // registry entries could refer to them and since we were not able to set our |
| 2116 GetChromeProgIdEntries(dist, chrome_exe, base::string16(), &entries); | 2132 // HKLM entries above, we are better off not altering these here. |
| 2117 // Prefer to use |suffix|; unless Chrome's ProgIds are already registered | 2133 if (!AreEntriesAsDesired(entries, RegistryEntry::LOOK_IN_HKCU)) { |
| 2118 // with no suffix (as per the old registration style): in which case some | 2134 if (!suffix.empty()) { |
| 2119 // other registry entries could refer to them and since we were not able to | |
| 2120 // set our HKLM entries above, we are better off not altering these here. | |
| 2121 if (!AreEntriesAsDesired(entries, RegistryEntry::LOOK_IN_HKCU)) { | |
| 2122 if (!suffix.empty()) { | |
| 2123 entries.clear(); | |
| 2124 GetChromeProgIdEntries(dist, chrome_exe, suffix, &entries); | |
| 2125 GetChromeAppRegistrationEntries(chrome_exe, suffix, &entries); | |
| 2126 } | |
| 2127 result = AddRegistryEntries(HKEY_CURRENT_USER, entries); | |
| 2128 } else { | |
| 2129 // The ProgId is registered unsuffixed in HKCU, also register the app with | |
| 2130 // Windows in HKCU (this was not done in the old registration style and | |
| 2131 // thus needs to be done after the above check for the unsuffixed | |
| 2132 // registration). | |
| 2133 entries.clear(); | 2135 entries.clear(); |
| 2134 GetChromeAppRegistrationEntries(chrome_exe, base::string16(), &entries); | 2136 GetChromeProgIdEntries(dist, chrome_exe, suffix, &entries); |
| 2135 result = AddRegistryEntries(HKEY_CURRENT_USER, entries); | 2137 GetChromeAppRegistrationEntries(chrome_exe, suffix, &entries); |
| 2136 } | 2138 } |
| 2139 return AddRegistryEntries(HKEY_CURRENT_USER, entries); |
| 2137 } | 2140 } |
| 2138 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); | 2141 // The ProgId is registered unsuffixed in HKCU, also register the app with |
| 2139 return result; | 2142 // Windows in HKCU (this was not done in the old registration style and thus |
| 2143 // needs to be done after the above check for the unsuffixed registration). |
| 2144 entries.clear(); |
| 2145 GetChromeAppRegistrationEntries(chrome_exe, base::string16(), &entries); |
| 2146 return AddRegistryEntries(HKEY_CURRENT_USER, entries); |
| 2140 } | 2147 } |
| 2141 | 2148 |
| 2142 bool ShellUtil::RegisterChromeForProtocol(BrowserDistribution* dist, | 2149 bool ShellUtil::RegisterChromeForProtocol(BrowserDistribution* dist, |
| 2143 const base::FilePath& chrome_exe, | 2150 const base::FilePath& chrome_exe, |
| 2144 const base::string16& unique_suffix, | 2151 const base::string16& unique_suffix, |
| 2145 const base::string16& protocol, | 2152 const base::string16& protocol, |
| 2146 bool elevate_if_not_admin) { | 2153 bool elevate_if_not_admin) { |
| 2147 // Assert that this is only called with the one relevant distribution. | 2154 // Assert that this is only called with the one relevant distribution. |
| 2148 // TODO(grt): Remove this when BrowserDistribution goes away. | 2155 // TODO(grt): Remove this when BrowserDistribution goes away. |
| 2149 DCHECK_EQ(BrowserDistribution::GetDistribution(), dist); | 2156 DCHECK_EQ(BrowserDistribution::GetDistribution(), dist); |
| (...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2343 for (const auto& entry : entries) | 2350 for (const auto& entry : entries) |
| 2344 entry->AddToWorkItemList(root, items.get()); | 2351 entry->AddToWorkItemList(root, items.get()); |
| 2345 | 2352 |
| 2346 // Apply all the registry changes and if there is a problem, rollback | 2353 // Apply all the registry changes and if there is a problem, rollback |
| 2347 if (!items->Do()) { | 2354 if (!items->Do()) { |
| 2348 items->Rollback(); | 2355 items->Rollback(); |
| 2349 return false; | 2356 return false; |
| 2350 } | 2357 } |
| 2351 return true; | 2358 return true; |
| 2352 } | 2359 } |
| OLD | NEW |