blob: 47cf902ec659b4646b21d35934eacc98f41ab4ce [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]b967a1b2011-08-17 14:39:5810#include "base/memory/scoped_handle.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]1d5e58b2013-01-31 08:41:4019#include "chrome/common/extensions/extension.h"
[email protected]c38831a12011-10-28 12:44:4920#include "content/public/browser/browser_thread.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
29// Registry value of of that key that defines the path to the .crx file.
30const wchar_t kRegistryExtensionPath[] = L"path";
31
32// Registry value of that key that defines the current version of the .crx file.
33const wchar_t kRegistryExtensionVersion[] = L"version";
34
[email protected]650b2d52013-02-10 03:41:4535bool CanOpenFileForReading(const base::FilePath& path) {
[email protected]b967a1b2011-08-17 14:39:5836 ScopedStdioHandle file_handle(file_util::OpenFile(path, "rb"));
37 return file_handle.get() != NULL;
38}
39
[email protected]8e4560b62011-01-14 10:09:1440} // namespace
41
[email protected]5df038b2012-07-16 19:03:2742namespace extensions {
43
44void ExternalRegistryLoader::StartLoading() {
[email protected]8e4560b62011-01-14 10:09:1445 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
46 BrowserThread::PostTask(
47 BrowserThread::FILE, FROM_HERE,
[email protected]5df038b2012-07-16 19:03:2748 base::Bind(&ExternalRegistryLoader::LoadOnFileThread, this));
[email protected]8e4560b62011-01-14 10:09:1449}
50
[email protected]5df038b2012-07-16 19:03:2751void ExternalRegistryLoader::LoadOnFileThread() {
[email protected]8e4560b62011-01-14 10:09:1452 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
[email protected]f4091a32012-06-05 22:21:5753 base::TimeTicks start_time = base::TimeTicks::Now();
[email protected]8e4560b62011-01-14 10:09:1454 scoped_ptr<DictionaryValue> prefs(new DictionaryValue);
55
[email protected]1358b282011-09-15 15:35:1456 // A map of IDs, to weed out duplicates between HKCU and HKLM.
57 std::set<string16> keys;
58 base::win::RegistryKeyIterator iterator_machine_key(
[email protected]47e870b2013-02-24 21:14:5359 HKEY_LOCAL_MACHINE, ASCIIToWide(kRegistryExtensions).c_str());
[email protected]1358b282011-09-15 15:35:1460 for (; iterator_machine_key.Valid(); ++iterator_machine_key)
61 keys.insert(iterator_machine_key.Name());
62 base::win::RegistryKeyIterator iterator_user_key(
[email protected]47e870b2013-02-24 21:14:5363 HKEY_CURRENT_USER, ASCIIToWide(kRegistryExtensions).c_str());
[email protected]1358b282011-09-15 15:35:1464 for (; iterator_user_key.Valid(); ++iterator_user_key)
65 keys.insert(iterator_user_key.Name());
66
67 // Iterate over the keys found, first trying HKLM, then HKCU, as per Windows
68 // policy conventions. We only fall back to HKCU if the HKLM key cannot be
69 // opened, not if the data within the key is invalid, for example.
70 for (std::set<string16>::const_iterator it = keys.begin();
71 it != keys.end(); ++it) {
[email protected]8e4560b62011-01-14 10:09:1472 base::win::RegKey key;
[email protected]47e870b2013-02-24 21:14:5373 string16 key_path = ASCIIToWide(kRegistryExtensions);
[email protected]8e4560b62011-01-14 10:09:1474 key_path.append(L"\\");
[email protected]1358b282011-09-15 15:35:1475 key_path.append(*it);
76 if (key.Open(HKEY_LOCAL_MACHINE,
77 key_path.c_str(), KEY_READ) != ERROR_SUCCESS) {
78 if (key.Open(HKEY_CURRENT_USER,
79 key_path.c_str(), KEY_READ) != ERROR_SUCCESS) {
80 LOG(ERROR) << "Unable to read registry key at path (HKLM & HKCU): "
81 << key_path << ".";
82 continue;
83 }
[email protected]8e4560b62011-01-14 10:09:1484 }
[email protected]b967a1b2011-08-17 14:39:5885
[email protected]1358b282011-09-15 15:35:1486 string16 extension_path_str;
[email protected]b967a1b2011-08-17 14:39:5887 if (key.ReadValue(kRegistryExtensionPath, &extension_path_str)
88 != ERROR_SUCCESS) {
89 // TODO(erikkay): find a way to get this into about:extensions
90 LOG(ERROR) << "Missing value " << kRegistryExtensionPath
91 << " for key " << key_path << ".";
92 continue;
93 }
94
[email protected]650b2d52013-02-10 03:41:4595 base::FilePath extension_path(extension_path_str);
[email protected]b967a1b2011-08-17 14:39:5896 if (!extension_path.IsAbsolute()) {
97 LOG(ERROR) << "File path " << extension_path_str
98 << " needs to be absolute in key "
99 << key_path;
100 continue;
101 }
102
103 if (!file_util::PathExists(extension_path)) {
104 LOG(ERROR) << "File " << extension_path_str
105 << " for key " << key_path
106 << " does not exist or is not readable.";
107 continue;
108 }
109
110 if (!CanOpenFileForReading(extension_path)) {
111 LOG(ERROR) << "File " << extension_path_str
112 << " for key " << key_path << " can not be read. "
113 << "Check that users who should have the extension "
114 << "installed have permission to read it.";
115 continue;
116 }
117
[email protected]1358b282011-09-15 15:35:14118 string16 extension_version;
[email protected]b967a1b2011-08-17 14:39:58119 if (key.ReadValue(kRegistryExtensionVersion, &extension_version)
120 != ERROR_SUCCESS) {
121 // TODO(erikkay): find a way to get this into about:extensions
122 LOG(ERROR) << "Missing value " << kRegistryExtensionVersion
123 << " for key " << key_path << ".";
124 continue;
125 }
126
[email protected]47e870b2013-02-24 21:14:53127 std::string id = WideToASCII(*it);
[email protected]b967a1b2011-08-17 14:39:58128 StringToLowerASCII(&id);
[email protected]5df038b2012-07-16 19:03:27129 if (!Extension::IdIsValid(id)) {
[email protected]b967a1b2011-08-17 14:39:58130 LOG(ERROR) << "Invalid id value " << id
131 << " for key " << key_path << ".";
132 continue;
133 }
134
[email protected]47e870b2013-02-24 21:14:53135 Version version(WideToASCII(extension_version));
[email protected]12126d372012-07-11 18:40:53136 if (!version.IsValid()) {
[email protected]b967a1b2011-08-17 14:39:58137 LOG(ERROR) << "Invalid version value " << extension_version
138 << " for key " << key_path << ".";
139 continue;
140 }
141
142 prefs->SetString(
[email protected]5df038b2012-07-16 19:03:27143 id + "." + ExternalProviderImpl::kExternalVersion,
[email protected]47e870b2013-02-24 21:14:53144 WideToASCII(extension_version));
[email protected]b967a1b2011-08-17 14:39:58145 prefs->SetString(
[email protected]5df038b2012-07-16 19:03:27146 id + "." + ExternalProviderImpl::kExternalCrx,
[email protected]b967a1b2011-08-17 14:39:58147 extension_path_str);
[email protected]8e4560b62011-01-14 10:09:14148 }
149
150 prefs_.reset(prefs.release());
[email protected]f4091a32012-06-05 22:21:57151 HISTOGRAM_TIMES("Extensions.ExternalRegistryLoaderWin",
152 base::TimeTicks::Now() - start_time);
[email protected]8e4560b62011-01-14 10:09:14153 BrowserThread::PostTask(
154 BrowserThread::UI, FROM_HERE,
[email protected]5df038b2012-07-16 19:03:27155 base::Bind(&ExternalRegistryLoader::LoadFinished, this));
[email protected]8e4560b62011-01-14 10:09:14156}
[email protected]5df038b2012-07-16 19:03:27157
158} // namespace extensions