blob: ce44ae75dcf4603b35de9c73dda36d0784505509 [file] [log] [blame]
[email protected]f4091a32012-06-05 22:21:571// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]8e4560b62011-01-14 10:09:142// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]5df038b2012-07-16 19:03:275#include "chrome/browser/extensions/external_registry_loader_win.h"
[email protected]8e4560b62011-01-14 10:09:146
[email protected]8e6ac4b2011-10-17 19:04:317#include "base/bind.h"
[email protected]57999812013-02-24 05:40:528#include "base/files/file_path.h"
thestig18dfb7a52014-08-26 10:44:049#include "base/files/file_util.h"
[email protected]0910bae2014-06-10 17:53:2110#include "base/files/scoped_file.h"
[email protected]f4091a32012-06-05 22:21:5711#include "base/metrics/histogram.h"
[email protected]46acbf12013-06-10 18:43:4212#include "base/strings/string_util.h"
[email protected]2b6a5802014-08-16 07:58:0813#include "base/strings/stringprintf.h"
[email protected]112158af2013-06-07 23:46:1814#include "base/strings/utf_string_conversions.h"
[email protected]41a17c52013-06-28 00:27:5315#include "base/time/time.h"
[email protected]8e4560b62011-01-14 10:09:1416#include "base/values.h"
17#include "base/version.h"
18#include "base/win/registry.h"
[email protected]5df038b2012-07-16 19:03:2719#include "chrome/browser/extensions/external_provider_impl.h"
[email protected]fdd28372014-08-21 02:27:2620#include "components/crx_file/id_util.h"
[email protected]c38831a12011-10-28 12:44:4921#include "content/public/browser/browser_thread.h"
[email protected]8e4560b62011-01-14 10:09:1422
[email protected]631bb742011-11-02 11:29:3923using content::BrowserThread;
24
[email protected]8e4560b62011-01-14 10:09:1425namespace {
26
[email protected]8e4560b62011-01-14 10:09:1427// The Registry subkey that contains information about external extensions.
28const char kRegistryExtensions[] = "Software\\Google\\Chrome\\Extensions";
29
[email protected]d8fd0fd2014-03-24 13:16:0630// Registry value of the key that defines the installation parameter.
31const wchar_t kRegistryExtensionInstallParam[] = L"install_parameter";
32
[email protected]5873a5a2013-12-16 19:53:0033// Registry value of the key that defines the path to the .crx file.
[email protected]8e4560b62011-01-14 10:09:1434const wchar_t kRegistryExtensionPath[] = L"path";
35
36// Registry value of that key that defines the current version of the .crx file.
37const wchar_t kRegistryExtensionVersion[] = L"version";
38
[email protected]5873a5a2013-12-16 19:53:0039// Registry value of the key that defines an external update URL.
40const wchar_t kRegistryExtensionUpdateUrl[] = L"update_url";
41
[email protected]650b2d52013-02-10 03:41:4542bool CanOpenFileForReading(const base::FilePath& path) {
[email protected]0910bae2014-06-10 17:53:2143 base::ScopedFILE file_handle(base::OpenFile(path, "rb"));
[email protected]b967a1b2011-08-17 14:39:5844 return file_handle.get() != NULL;
45}
46
[email protected]2b6a5802014-08-16 07:58:0847std::string MakePrefName(const std::string& extension_id,
48 const std::string& pref_name) {
49 return base::StringPrintf("%s.%s", extension_id.c_str(), pref_name.c_str());
50}
51
[email protected]8e4560b62011-01-14 10:09:1452} // namespace
53
[email protected]5df038b2012-07-16 19:03:2754namespace extensions {
55
56void ExternalRegistryLoader::StartLoading() {
[email protected]8e4560b62011-01-14 10:09:1457 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
58 BrowserThread::PostTask(
59 BrowserThread::FILE, FROM_HERE,
[email protected]5df038b2012-07-16 19:03:2760 base::Bind(&ExternalRegistryLoader::LoadOnFileThread, this));
[email protected]8e4560b62011-01-14 10:09:1461}
62
[email protected]5df038b2012-07-16 19:03:2763void ExternalRegistryLoader::LoadOnFileThread() {
[email protected]8e4560b62011-01-14 10:09:1464 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
[email protected]f4091a32012-06-05 22:21:5765 base::TimeTicks start_time = base::TimeTicks::Now();
[email protected]cb1078de2013-12-23 20:04:2266 scoped_ptr<base::DictionaryValue> prefs(new base::DictionaryValue);
[email protected]8e4560b62011-01-14 10:09:1467
[email protected]1358b282011-09-15 15:35:1468 // A map of IDs, to weed out duplicates between HKCU and HKLM.
[email protected]d2065e062013-12-12 23:49:5269 std::set<base::string16> keys;
[email protected]1358b282011-09-15 15:35:1470 base::win::RegistryKeyIterator iterator_machine_key(
[email protected]04338722013-12-24 23:18:0571 HKEY_LOCAL_MACHINE, base::ASCIIToWide(kRegistryExtensions).c_str());
[email protected]1358b282011-09-15 15:35:1472 for (; iterator_machine_key.Valid(); ++iterator_machine_key)
73 keys.insert(iterator_machine_key.Name());
74 base::win::RegistryKeyIterator iterator_user_key(
[email protected]04338722013-12-24 23:18:0575 HKEY_CURRENT_USER, base::ASCIIToWide(kRegistryExtensions).c_str());
[email protected]1358b282011-09-15 15:35:1476 for (; iterator_user_key.Valid(); ++iterator_user_key)
77 keys.insert(iterator_user_key.Name());
78
79 // Iterate over the keys found, first trying HKLM, then HKCU, as per Windows
80 // policy conventions. We only fall back to HKCU if the HKLM key cannot be
81 // opened, not if the data within the key is invalid, for example.
[email protected]d2065e062013-12-12 23:49:5282 for (std::set<base::string16>::const_iterator it = keys.begin();
[email protected]1358b282011-09-15 15:35:1483 it != keys.end(); ++it) {
[email protected]8e4560b62011-01-14 10:09:1484 base::win::RegKey key;
[email protected]04338722013-12-24 23:18:0585 base::string16 key_path = base::ASCIIToWide(kRegistryExtensions);
[email protected]8e4560b62011-01-14 10:09:1486 key_path.append(L"\\");
[email protected]1358b282011-09-15 15:35:1487 key_path.append(*it);
88 if (key.Open(HKEY_LOCAL_MACHINE,
89 key_path.c_str(), KEY_READ) != ERROR_SUCCESS) {
90 if (key.Open(HKEY_CURRENT_USER,
91 key_path.c_str(), KEY_READ) != ERROR_SUCCESS) {
92 LOG(ERROR) << "Unable to read registry key at path (HKLM & HKCU): "
93 << key_path << ".";
94 continue;
95 }
[email protected]8e4560b62011-01-14 10:09:1496 }
[email protected]b967a1b2011-08-17 14:39:5897
[email protected]74f778e2014-03-14 21:11:4698 std::string id = base::UTF16ToASCII(*it);
[email protected]cb1f4ac2014-08-07 16:55:4299 base::StringToLowerASCII(&id);
[email protected]fdd28372014-08-21 02:27:26100 if (!crx_file::id_util::IdIsValid(id)) {
[email protected]5873a5a2013-12-16 19:53:00101 LOG(ERROR) << "Invalid id value " << id
102 << " for key " << key_path << ".";
103 continue;
104 }
105
[email protected]d8fd0fd2014-03-24 13:16:06106 base::string16 extension_dist_id;
107 if (key.ReadValue(kRegistryExtensionInstallParam, &extension_dist_id) ==
108 ERROR_SUCCESS) {
[email protected]2b6a5802014-08-16 07:58:08109 prefs->SetString(MakePrefName(id, ExternalProviderImpl::kInstallParam),
[email protected]d8fd0fd2014-03-24 13:16:06110 base::UTF16ToASCII(extension_dist_id));
111 }
112
[email protected]5873a5a2013-12-16 19:53:00113 // If there is an update URL present, copy it to prefs and ignore
114 // path and version keys for this entry.
115 base::string16 extension_update_url;
116 if (key.ReadValue(kRegistryExtensionUpdateUrl, &extension_update_url)
117 == ERROR_SUCCESS) {
118 prefs->SetString(
[email protected]2b6a5802014-08-16 07:58:08119 MakePrefName(id, ExternalProviderImpl::kExternalUpdateUrl),
[email protected]74f778e2014-03-14 21:11:46120 base::UTF16ToASCII(extension_update_url));
[email protected]5873a5a2013-12-16 19:53:00121 continue;
122 }
123
[email protected]439f1e32013-12-09 20:09:09124 base::string16 extension_path_str;
[email protected]b967a1b2011-08-17 14:39:58125 if (key.ReadValue(kRegistryExtensionPath, &extension_path_str)
126 != ERROR_SUCCESS) {
127 // TODO(erikkay): find a way to get this into about:extensions
128 LOG(ERROR) << "Missing value " << kRegistryExtensionPath
129 << " for key " << key_path << ".";
130 continue;
131 }
132
[email protected]650b2d52013-02-10 03:41:45133 base::FilePath extension_path(extension_path_str);
[email protected]b967a1b2011-08-17 14:39:58134 if (!extension_path.IsAbsolute()) {
135 LOG(ERROR) << "File path " << extension_path_str
136 << " needs to be absolute in key "
137 << key_path;
138 continue;
139 }
140
[email protected]7567484142013-07-11 17:36:07141 if (!base::PathExists(extension_path)) {
[email protected]b967a1b2011-08-17 14:39:58142 LOG(ERROR) << "File " << extension_path_str
143 << " for key " << key_path
144 << " does not exist or is not readable.";
145 continue;
146 }
147
148 if (!CanOpenFileForReading(extension_path)) {
149 LOG(ERROR) << "File " << extension_path_str
150 << " for key " << key_path << " can not be read. "
151 << "Check that users who should have the extension "
152 << "installed have permission to read it.";
153 continue;
154 }
155
[email protected]439f1e32013-12-09 20:09:09156 base::string16 extension_version;
[email protected]b967a1b2011-08-17 14:39:58157 if (key.ReadValue(kRegistryExtensionVersion, &extension_version)
158 != ERROR_SUCCESS) {
159 // TODO(erikkay): find a way to get this into about:extensions
160 LOG(ERROR) << "Missing value " << kRegistryExtensionVersion
161 << " for key " << key_path << ".";
162 continue;
163 }
164
[email protected]74f778e2014-03-14 21:11:46165 Version version(base::UTF16ToASCII(extension_version));
[email protected]12126d372012-07-11 18:40:53166 if (!version.IsValid()) {
[email protected]b967a1b2011-08-17 14:39:58167 LOG(ERROR) << "Invalid version value " << extension_version
168 << " for key " << key_path << ".";
169 continue;
170 }
171
172 prefs->SetString(
[email protected]2b6a5802014-08-16 07:58:08173 MakePrefName(id, ExternalProviderImpl::kExternalVersion),
[email protected]74f778e2014-03-14 21:11:46174 base::UTF16ToASCII(extension_version));
[email protected]b967a1b2011-08-17 14:39:58175 prefs->SetString(
[email protected]2b6a5802014-08-16 07:58:08176 MakePrefName(id, ExternalProviderImpl::kExternalCrx),
[email protected]b967a1b2011-08-17 14:39:58177 extension_path_str);
[email protected]2b6a5802014-08-16 07:58:08178 prefs->SetBoolean(
179 MakePrefName(id, ExternalProviderImpl::kMayBeUntrusted),
180 true);
[email protected]8e4560b62011-01-14 10:09:14181 }
182
183 prefs_.reset(prefs.release());
asvitkinec0fb8022014-08-26 04:39:35184 LOCAL_HISTOGRAM_TIMES("Extensions.ExternalRegistryLoaderWin",
185 base::TimeTicks::Now() - start_time);
[email protected]8e4560b62011-01-14 10:09:14186 BrowserThread::PostTask(
187 BrowserThread::UI, FROM_HERE,
[email protected]5df038b2012-07-16 19:03:27188 base::Bind(&ExternalRegistryLoader::LoadFinished, this));
[email protected]8e4560b62011-01-14 10:09:14189}
[email protected]5df038b2012-07-16 19:03:27190
191} // namespace extensions