15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/external_registry_loader_win.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h" 91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h" 10f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "base/files/scoped_file.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h" 12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h" 1303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "base/strings/stringprintf.h" 14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/version.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/registry.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/external_provider_impl.h" 2003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "components/crx_file/id_util.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread; 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The Registry subkey that contains information about external extensions. 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kRegistryExtensions[] = "Software\\Google\\Chrome\\Extensions"; 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 30effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Registry value of the key that defines the installation parameter. 31effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochconst wchar_t kRegistryExtensionInstallParam[] = L"install_parameter"; 32effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Registry value of the key that defines the path to the .crx file. 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kRegistryExtensionPath[] = L"path"; 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Registry value of that key that defines the current version of the .crx file. 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kRegistryExtensionVersion[] = L"version"; 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Registry value of the key that defines an external update URL. 405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const wchar_t kRegistryExtensionUpdateUrl[] = L"update_url"; 415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool CanOpenFileForReading(const base::FilePath& path) { 43f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::ScopedFILE file_handle(base::OpenFile(path, "rb")); 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return file_handle.get() != NULL; 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)std::string MakePrefName(const std::string& extension_id, 4803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) const std::string& pref_name) { 4903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return base::StringPrintf("%s.%s", extension_id.c_str(), pref_name.c_str()); 5003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)} 5103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace extensions { 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExternalRegistryLoader::StartLoading() { 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::PostTask( 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::FILE, FROM_HERE, 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&ExternalRegistryLoader::LoadOnFileThread, this)); 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExternalRegistryLoader::LoadOnFileThread() { 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::TimeTicks start_time = base::TimeTicks::Now(); 665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) scoped_ptr<base::DictionaryValue> prefs(new base::DictionaryValue); 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // A map of IDs, to weed out duplicates between HKCU and HKLM. 695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::set<base::string16> keys; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::RegistryKeyIterator iterator_machine_key( 715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) HKEY_LOCAL_MACHINE, base::ASCIIToWide(kRegistryExtensions).c_str()); 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; iterator_machine_key.Valid(); ++iterator_machine_key) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keys.insert(iterator_machine_key.Name()); 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::RegistryKeyIterator iterator_user_key( 755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) HKEY_CURRENT_USER, base::ASCIIToWide(kRegistryExtensions).c_str()); 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; iterator_user_key.Valid(); ++iterator_user_key) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keys.insert(iterator_user_key.Name()); 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Iterate over the keys found, first trying HKLM, then HKCU, as per Windows 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // policy conventions. We only fall back to HKCU if the HKLM key cannot be 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // opened, not if the data within the key is invalid, for example. 825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (std::set<base::string16>::const_iterator it = keys.begin(); 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != keys.end(); ++it) { 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::RegKey key; 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16 key_path = base::ASCIIToWide(kRegistryExtensions); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key_path.append(L"\\"); 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key_path.append(*it); 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (key.Open(HKEY_LOCAL_MACHINE, 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key_path.c_str(), KEY_READ) != ERROR_SUCCESS) { 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (key.Open(HKEY_CURRENT_USER, 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key_path.c_str(), KEY_READ) != ERROR_SUCCESS) { 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Unable to read registry key at path (HKLM & HKCU): " 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << key_path << "."; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) std::string id = base::UTF16ToASCII(*it); 996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) base::StringToLowerASCII(&id); 10003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (!crx_file::id_util::IdIsValid(id)) { 1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) LOG(ERROR) << "Invalid id value " << id 1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) << " for key " << key_path << "."; 1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) continue; 1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 106effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch base::string16 extension_dist_id; 107effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (key.ReadValue(kRegistryExtensionInstallParam, &extension_dist_id) == 108effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch ERROR_SUCCESS) { 10903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) prefs->SetString(MakePrefName(id, ExternalProviderImpl::kInstallParam), 110effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch base::UTF16ToASCII(extension_dist_id)); 111effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 112effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // If there is an update URL present, copy it to prefs and ignore 1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // path and version keys for this entry. 1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16 extension_update_url; 1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (key.ReadValue(kRegistryExtensionUpdateUrl, &extension_update_url) 1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) == ERROR_SUCCESS) { 1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) prefs->SetString( 11903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) MakePrefName(id, ExternalProviderImpl::kExternalUpdateUrl), 120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::UTF16ToASCII(extension_update_url)); 1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) continue; 1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 124a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 extension_path_str; 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (key.ReadValue(kRegistryExtensionPath, &extension_path_str) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) != ERROR_SUCCESS) { 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(erikkay): find a way to get this into about:extensions 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Missing value " << kRegistryExtensionPath 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << " for key " << key_path << "."; 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath extension_path(extension_path_str); 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!extension_path.IsAbsolute()) { 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "File path " << extension_path_str 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << " needs to be absolute in key " 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << key_path; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (!base::PathExists(extension_path)) { 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "File " << extension_path_str 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << " for key " << key_path 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << " does not exist or is not readable."; 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!CanOpenFileForReading(extension_path)) { 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "File " << extension_path_str 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << " for key " << key_path << " can not be read. " 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Check that users who should have the extension " 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "installed have permission to read it."; 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 156a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 extension_version; 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (key.ReadValue(kRegistryExtensionVersion, &extension_version) 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) != ERROR_SUCCESS) { 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(erikkay): find a way to get this into about:extensions 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Missing value " << kRegistryExtensionVersion 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << " for key " << key_path << "."; 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) Version version(base::UTF16ToASCII(extension_version)); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!version.IsValid()) { 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Invalid version value " << extension_version 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << " for key " << key_path << "."; 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prefs->SetString( 17303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) MakePrefName(id, ExternalProviderImpl::kExternalVersion), 174a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::UTF16ToASCII(extension_version)); 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prefs->SetString( 17603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) MakePrefName(id, ExternalProviderImpl::kExternalCrx), 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_path_str); 17803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) prefs->SetBoolean( 17903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) MakePrefName(id, ExternalProviderImpl::kMayBeUntrusted), 18003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) true); 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prefs_.reset(prefs.release()); 1841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci LOCAL_HISTOGRAM_TIMES("Extensions.ExternalRegistryLoaderWin", 1851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci base::TimeTicks::Now() - start_time); 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::PostTask( 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::UI, FROM_HERE, 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&ExternalRegistryLoader::LoadFinished, this)); 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace extensions 192