blob: c2d94d2cb779be4b3b5a4a1feb0c47312f19efb4 [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]b967a1b2011-08-17 14:39:588#include "base/file_util.h"
[email protected]57999812013-02-24 05:40:529#include "base/files/file_path.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]112158af2013-06-07 23:46:1813#include "base/strings/utf_string_conversions.h"
[email protected]41a17c52013-06-28 00:27:5314#include "base/time/time.h"
[email protected]8e4560b62011-01-14 10:09:1415#include "base/values.h"
16#include "base/version.h"
17#include "base/win/registry.h"
[email protected]5df038b2012-07-16 19:03:2718#include "chrome/browser/extensions/external_provider_impl.h"
[email protected]c38831a12011-10-28 12:44:4919#include "content/public/browser/browser_thread.h"
[email protected]e4452d32013-11-15 23:07:4120#include "extensions/common/extension.h"
[email protected]8e4560b62011-01-14 10:09:1421
[email protected]631bb742011-11-02 11:29:3922using content::BrowserThread;
23
[email protected]8e4560b62011-01-14 10:09:1424namespace {
25
[email protected]8e4560b62011-01-14 10:09:1426// The Registry subkey that contains information about external extensions.
27const char kRegistryExtensions[] = "Software\\Google\\Chrome\\Extensions";
28
[email protected]d8fd0fd2014-03-24 13:16:0629// Registry value of the key that defines the installation parameter.
30const wchar_t kRegistryExtensionInstallParam[] = L"install_parameter";
31
[email protected]5873a5a2013-12-16 19:53:0032// Registry value of the key that defines the path to the .crx file.
[email protected]8e4560b62011-01-14 10:09:1433const wchar_t kRegistryExtensionPath[] = L"path";
34
35// Registry value of that key that defines the current version of the .crx file.
36const wchar_t kRegistryExtensionVersion[] = L"version";
37
[email protected]5873a5a2013-12-16 19:53:0038// Registry value of the key that defines an external update URL.
39const wchar_t kRegistryExtensionUpdateUrl[] = L"update_url";
40
[email protected]650b2d52013-02-10 03:41:4541bool CanOpenFileForReading(const base::FilePath& path) {
[email protected]0910bae2014-06-10 17:53:2142 base::ScopedFILE file_handle(base::OpenFile(path, "rb"));
[email protected]b967a1b2011-08-17 14:39:5843 return file_handle.get() != NULL;
44}
45
[email protected]8e4560b62011-01-14 10:09:1446} // namespace
47
[email protected]5df038b2012-07-16 19:03:2748namespace extensions {
49
50void ExternalRegistryLoader::StartLoading() {
[email protected]8e4560b62011-01-14 10:09:1451 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
52 BrowserThread::PostTask(
53 BrowserThread::FILE, FROM_HERE,
[email protected]5df038b2012-07-16 19:03:2754 base::Bind(&ExternalRegistryLoader::LoadOnFileThread, this));
[email protected]8e4560b62011-01-14 10:09:1455}
56
[email protected]5df038b2012-07-16 19:03:2757void ExternalRegistryLoader::LoadOnFileThread() {
[email protected]8e4560b62011-01-14 10:09:1458 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
[email protected]f4091a32012-06-05 22:21:5759 base::TimeTicks start_time = base::TimeTicks::Now();
[email protected]cb1078de2013-12-23 20:04:2260 scoped_ptr<base::DictionaryValue> prefs(new base::DictionaryValue);
[email protected]8e4560b62011-01-14 10:09:1461
[email protected]1358b282011-09-15 15:35:1462 // A map of IDs, to weed out duplicates between HKCU and HKLM.
[email protected]d2065e062013-12-12 23:49:5263 std::set<base::string16> keys;
[email protected]1358b282011-09-15 15:35:1464 base::win::RegistryKeyIterator iterator_machine_key(
[email protected]04338722013-12-24 23:18:0565 HKEY_LOCAL_MACHINE, base::ASCIIToWide(kRegistryExtensions).c_str());
[email protected]1358b282011-09-15 15:35:1466 for (; iterator_machine_key.Valid(); ++iterator_machine_key)
67 keys.insert(iterator_machine_key.Name());
68 base::win::RegistryKeyIterator iterator_user_key(
[email protected]04338722013-12-24 23:18:0569 HKEY_CURRENT_USER, base::ASCIIToWide(kRegistryExtensions).c_str());
[email protected]1358b282011-09-15 15:35:1470 for (; iterator_user_key.Valid(); ++iterator_user_key)
71 keys.insert(iterator_user_key.Name());
72
73 // Iterate over the keys found, first trying HKLM, then HKCU, as per Windows
74 // policy conventions. We only fall back to HKCU if the HKLM key cannot be
75 // opened, not if the data within the key is invalid, for example.
[email protected]d2065e062013-12-12 23:49:5276 for (std::set<base::string16>::const_iterator it = keys.begin();
[email protected]1358b282011-09-15 15:35:1477 it != keys.end(); ++it) {
[email protected]8e4560b62011-01-14 10:09:1478 base::win::RegKey key;
[email protected]04338722013-12-24 23:18:0579 base::string16 key_path = base::ASCIIToWide(kRegistryExtensions);
[email protected]8e4560b62011-01-14 10:09:1480 key_path.append(L"\\");
[email protected]1358b282011-09-15 15:35:1481 key_path.append(*it);
82 if (key.Open(HKEY_LOCAL_MACHINE,
83 key_path.c_str(), KEY_READ) != ERROR_SUCCESS) {
84 if (key.Open(HKEY_CURRENT_USER,
85 key_path.c_str(), KEY_READ) != ERROR_SUCCESS) {
86 LOG(ERROR) << "Unable to read registry key at path (HKLM & HKCU): "
87 << key_path << ".";
88 continue;
89 }
[email protected]8e4560b62011-01-14 10:09:1490 }
[email protected]b967a1b2011-08-17 14:39:5891
[email protected]74f778e2014-03-14 21:11:4692 std::string id = base::UTF16ToASCII(*it);
[email protected]5873a5a2013-12-16 19:53:0093 StringToLowerASCII(&id);
94 if (!Extension::IdIsValid(id)) {
95 LOG(ERROR) << "Invalid id value " << id
96 << " for key " << key_path << ".";
97 continue;
98 }
99
[email protected]d8fd0fd2014-03-24 13:16:06100 base::string16 extension_dist_id;
101 if (key.ReadValue(kRegistryExtensionInstallParam, &extension_dist_id) ==
102 ERROR_SUCCESS) {
103 prefs->SetString(id + "." + ExternalProviderImpl::kInstallParam,
104 base::UTF16ToASCII(extension_dist_id));
105 }
106
[email protected]5873a5a2013-12-16 19:53:00107 // If there is an update URL present, copy it to prefs and ignore
108 // path and version keys for this entry.
109 base::string16 extension_update_url;
110 if (key.ReadValue(kRegistryExtensionUpdateUrl, &extension_update_url)
111 == ERROR_SUCCESS) {
112 prefs->SetString(
113 id + "." + ExternalProviderImpl::kExternalUpdateUrl,
[email protected]74f778e2014-03-14 21:11:46114 base::UTF16ToASCII(extension_update_url));
[email protected]5873a5a2013-12-16 19:53:00115 continue;
116 }
117
[email protected]439f1e32013-12-09 20:09:09118 base::string16 extension_path_str;
[email protected]b967a1b2011-08-17 14:39:58119 if (key.ReadValue(kRegistryExtensionPath, &extension_path_str)
120 != ERROR_SUCCESS) {
121 // TODO(erikkay): find a way to get this into about:extensions
122 LOG(ERROR) << "Missing value " << kRegistryExtensionPath
123 << " for key " << key_path << ".";
124 continue;
125 }
126
[email protected]650b2d52013-02-10 03:41:45127 base::FilePath extension_path(extension_path_str);
[email protected]b967a1b2011-08-17 14:39:58128 if (!extension_path.IsAbsolute()) {
129 LOG(ERROR) << "File path " << extension_path_str
130 << " needs to be absolute in key "
131 << key_path;
132 continue;
133 }
134
[email protected]7567484142013-07-11 17:36:07135 if (!base::PathExists(extension_path)) {
[email protected]b967a1b2011-08-17 14:39:58136 LOG(ERROR) << "File " << extension_path_str
137 << " for key " << key_path
138 << " does not exist or is not readable.";
139 continue;
140 }
141
142 if (!CanOpenFileForReading(extension_path)) {
143 LOG(ERROR) << "File " << extension_path_str
144 << " for key " << key_path << " can not be read. "
145 << "Check that users who should have the extension "
146 << "installed have permission to read it.";
147 continue;
148 }
149
[email protected]439f1e32013-12-09 20:09:09150 base::string16 extension_version;
[email protected]b967a1b2011-08-17 14:39:58151 if (key.ReadValue(kRegistryExtensionVersion, &extension_version)
152 != ERROR_SUCCESS) {
153 // TODO(erikkay): find a way to get this into about:extensions
154 LOG(ERROR) << "Missing value " << kRegistryExtensionVersion
155 << " for key " << key_path << ".";
156 continue;
157 }
158
[email protected]74f778e2014-03-14 21:11:46159 Version version(base::UTF16ToASCII(extension_version));
[email protected]12126d372012-07-11 18:40:53160 if (!version.IsValid()) {
[email protected]b967a1b2011-08-17 14:39:58161 LOG(ERROR) << "Invalid version value " << extension_version
162 << " for key " << key_path << ".";
163 continue;
164 }
165
166 prefs->SetString(
[email protected]5df038b2012-07-16 19:03:27167 id + "." + ExternalProviderImpl::kExternalVersion,
[email protected]74f778e2014-03-14 21:11:46168 base::UTF16ToASCII(extension_version));
[email protected]b967a1b2011-08-17 14:39:58169 prefs->SetString(
[email protected]5df038b2012-07-16 19:03:27170 id + "." + ExternalProviderImpl::kExternalCrx,
[email protected]b967a1b2011-08-17 14:39:58171 extension_path_str);
[email protected]8e4560b62011-01-14 10:09:14172 }
173
174 prefs_.reset(prefs.release());
[email protected]f4091a32012-06-05 22:21:57175 HISTOGRAM_TIMES("Extensions.ExternalRegistryLoaderWin",
176 base::TimeTicks::Now() - start_time);
[email protected]8e4560b62011-01-14 10:09:14177 BrowserThread::PostTask(
178 BrowserThread::UI, FROM_HERE,
[email protected]5df038b2012-07-16 19:03:27179 base::Bind(&ExternalRegistryLoader::LoadFinished, this));
[email protected]8e4560b62011-01-14 10:09:14180}
[email protected]5df038b2012-07-16 19:03:27181
182} // namespace extensions