| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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 #include "chrome/browser/extensions/extensions_service.h" | 5 #include "chrome/browser/extensions/extensions_service.h" |
| 6 | 6 |
| 7 #include "app/l10n_util.h" | 7 #include "app/l10n_util.h" |
| 8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
| 9 #include "base/crypto/signature_verifier.h" |
| 9 #include "base/file_util.h" | 10 #include "base/file_util.h" |
| 10 #include "base/gfx/png_encoder.h" | 11 #include "base/gfx/png_encoder.h" |
| 11 #include "base/scoped_handle.h" | 12 #include "base/scoped_handle.h" |
| 12 #include "base/scoped_temp_dir.h" | 13 #include "base/scoped_temp_dir.h" |
| 13 #include "base/string_util.h" | 14 #include "base/string_util.h" |
| 14 #include "base/third_party/nss/blapi.h" | 15 #include "base/third_party/nss/blapi.h" |
| 15 #include "base/third_party/nss/sha256.h" | 16 #include "base/third_party/nss/sha256.h" |
| 16 #include "base/thread.h" | 17 #include "base/thread.h" |
| 17 #include "base/values.h" | 18 #include "base/values.h" |
| 18 #include "net/base/file_stream.h" | 19 #include "net/base/file_stream.h" |
| 19 #include "chrome/browser/browser.h" | 20 #include "chrome/browser/browser.h" |
| 20 #include "chrome/browser/browser_list.h" | 21 #include "chrome/browser/browser_list.h" |
| 21 #include "chrome/browser/browser_process.h" | 22 #include "chrome/browser/browser_process.h" |
| 22 #include "chrome/browser/chrome_thread.h" | 23 #include "chrome/browser/chrome_thread.h" |
| 24 #include "chrome/browser/extensions/extension_creator.h" |
| 23 #include "chrome/browser/extensions/extension_browser_event_router.h" | 25 #include "chrome/browser/extensions/extension_browser_event_router.h" |
| 24 #include "chrome/browser/extensions/extension_process_manager.h" | 26 #include "chrome/browser/extensions/extension_process_manager.h" |
| 25 #include "chrome/browser/profile.h" | 27 #include "chrome/browser/profile.h" |
| 26 #include "chrome/browser/utility_process_host.h" | 28 #include "chrome/browser/utility_process_host.h" |
| 27 #include "chrome/common/chrome_switches.h" | 29 #include "chrome/common/chrome_switches.h" |
| 28 #include "chrome/common/extensions/extension.h" | 30 #include "chrome/common/extensions/extension.h" |
| 29 #include "chrome/common/extensions/extension_error_reporter.h" | 31 #include "chrome/common/extensions/extension_error_reporter.h" |
| 30 #include "chrome/common/extensions/extension_unpacker.h" | 32 #include "chrome/common/extensions/extension_unpacker.h" |
| 31 #include "chrome/common/json_value_serializer.h" | 33 #include "chrome/common/json_value_serializer.h" |
| 32 #include "chrome/common/notification_service.h" | 34 #include "chrome/common/notification_service.h" |
| 33 #include "chrome/common/pref_names.h" | 35 #include "chrome/common/pref_names.h" |
| 34 #include "chrome/common/pref_service.h" | 36 #include "chrome/common/pref_service.h" |
| 35 #include "chrome/common/zip.h" | 37 #include "chrome/common/zip.h" |
| 36 #include "chrome/common/url_constants.h" | 38 #include "chrome/common/url_constants.h" |
| 37 #include "grit/chromium_strings.h" | 39 #include "grit/chromium_strings.h" |
| 38 #include "grit/generated_resources.h" | 40 #include "grit/generated_resources.h" |
| 41 #include "net/base/base64.h" |
| 39 #include "third_party/skia/include/core/SkBitmap.h" | 42 #include "third_party/skia/include/core/SkBitmap.h" |
| 40 | 43 |
| 41 #if defined(OS_WIN) | 44 #if defined(OS_WIN) |
| 42 #include "app/win_util.h" | 45 #include "app/win_util.h" |
| 43 #include "base/registry.h" | 46 #include "base/registry.h" |
| 44 #include "base/win_util.h" | 47 #include "base/win_util.h" |
| 45 #endif | 48 #endif |
| 46 | 49 |
| 47 // ExtensionsService. | 50 // ExtensionsService. |
| 48 | 51 |
| 52 const char ExtensionsService::kExtensionHeaderMagic[] = "Cr24"; |
| 53 |
| 49 const char* ExtensionsService::kInstallDirectoryName = "Extensions"; | 54 const char* ExtensionsService::kInstallDirectoryName = "Extensions"; |
| 50 const char* ExtensionsService::kCurrentVersionFileName = "Current Version"; | 55 const char* ExtensionsService::kCurrentVersionFileName = "Current Version"; |
| 51 const char* ExtensionsServiceBackend::kTempExtensionName = "TEMP_INSTALL"; | 56 const char* ExtensionsServiceBackend::kTempExtensionName = "TEMP_INSTALL"; |
| 52 | 57 |
| 53 namespace { | 58 namespace { |
| 54 | 59 |
| 55 // A preference that keeps track of extension settings. This is a dictionary | 60 // A preference that keeps track of extension settings. This is a dictionary |
| 56 // object read from the Preferences file, keyed off of extension id's. | 61 // object read from the Preferences file, keyed off of extension id's. |
| 57 const wchar_t kExternalExtensionsPref[] = L"extensions.settings"; | 62 const wchar_t kExternalExtensionsPref[] = L"extensions.settings"; |
| 58 | 63 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 75 | 80 |
| 76 #endif | 81 #endif |
| 77 | 82 |
| 78 // A marker file to indicate that an extension was installed from an external | 83 // A marker file to indicate that an extension was installed from an external |
| 79 // source. | 84 // source. |
| 80 const char kExternalInstallFile[] = "EXTERNAL_INSTALL"; | 85 const char kExternalInstallFile[] = "EXTERNAL_INSTALL"; |
| 81 | 86 |
| 82 // A temporary subdirectory where we unpack extensions. | 87 // A temporary subdirectory where we unpack extensions. |
| 83 const char* kUnpackExtensionDir = "TEMP_UNPACK"; | 88 const char* kUnpackExtensionDir = "TEMP_UNPACK"; |
| 84 | 89 |
| 85 // The version of the extension package that this code understands. | 90 // Unpacking errors |
| 86 const uint32 kExpectedVersion = 1; | 91 const char* kBadMagicNumberError = "Bad magic number"; |
| 92 const char* kBadHeaderSizeError = "Excessively large key or signature"; |
| 93 const char* kBadVersionNumberError = "Bad version number"; |
| 94 const char* kInvalidExtensionHeaderError = "Invalid extension header"; |
| 95 const char* kInvalidPublicKeyError = "Invalid public key"; |
| 96 const char* kInvalidSignatureError = "Invalid signature"; |
| 97 const char* kSignatureVerificationFailed = "Signature verification failed"; |
| 98 const char* kSignatureVerificationInitFailed = |
| 99 "Signature verification initialization failed. This is most likely " |
| 100 "caused by a public key in the wrong format (should encode algorithm)."; |
| 87 } | 101 } |
| 88 | 102 |
| 89 // This class coordinates an extension unpack task which is run in a separate | 103 // This class coordinates an extension unpack task which is run in a separate |
| 90 // process. Results are sent back to this class, which we route to the | 104 // process. Results are sent back to this class, which we route to the |
| 91 // ExtensionServiceBackend. | 105 // ExtensionServiceBackend. |
| 92 class ExtensionsServiceBackend::UnpackerClient | 106 class ExtensionsServiceBackend::UnpackerClient |
| 93 : public UtilityProcessHost::Client { | 107 : public UtilityProcessHost::Client { |
| 94 public: | 108 public: |
| 95 UnpackerClient(ExtensionsServiceBackend* backend, | 109 UnpackerClient(ExtensionsServiceBackend* backend, |
| 96 const FilePath& extension_path, | 110 const FilePath& extension_path, |
| 111 const std::string& public_key, |
| 97 const std::string& expected_id, | 112 const std::string& expected_id, |
| 98 bool from_external) | 113 bool from_external) |
| 99 : backend_(backend), extension_path_(extension_path), | 114 : backend_(backend), extension_path_(extension_path), |
| 100 expected_id_(expected_id), from_external_(from_external), | 115 public_key_(public_key), expected_id_(expected_id), |
| 101 got_response_(false) { | 116 from_external_(from_external), got_response_(false) { |
| 102 } | 117 } |
| 103 | 118 |
| 104 // Starts the unpack task. We call back to the backend when the task is done, | 119 // Starts the unpack task. We call back to the backend when the task is done, |
| 105 // or a problem occurs. | 120 // or a problem occurs. |
| 106 void Start() { | 121 void Start() { |
| 107 AddRef(); // balanced in OnUnpackExtensionReply() | 122 AddRef(); // balanced in OnUnpackExtensionReply() |
| 108 | 123 |
| 109 // TODO(mpcomplete): handle multiple installs | 124 // TODO(mpcomplete): handle multiple installs |
| 110 FilePath temp_dir = backend_->install_directory_.AppendASCII( | 125 FilePath temp_dir = backend_->install_directory_.AppendASCII( |
| 111 kUnpackExtensionDir); | 126 kUnpackExtensionDir); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 156 &images)) { | 171 &images)) { |
| 157 OnUnpackExtensionFailed("Couldn't read image data from disk."); | 172 OnUnpackExtensionFailed("Couldn't read image data from disk."); |
| 158 } else { | 173 } else { |
| 159 OnUnpackExtensionSucceededImpl(manifest, images); | 174 OnUnpackExtensionSucceededImpl(manifest, images); |
| 160 } | 175 } |
| 161 } | 176 } |
| 162 | 177 |
| 163 void OnUnpackExtensionSucceededImpl( | 178 void OnUnpackExtensionSucceededImpl( |
| 164 const DictionaryValue& manifest, | 179 const DictionaryValue& manifest, |
| 165 const ExtensionUnpacker::DecodedImages& images) { | 180 const ExtensionUnpacker::DecodedImages& images) { |
| 181 // Add our public key into the parsed manifest. We want it to be saved so |
| 182 // that we can later refer to it (eg for generating ids, validating |
| 183 // signatures, etc). |
| 184 // The const_cast is hacky, but seems like the right thing here, rather than |
| 185 // making a full copy just to make this change. |
| 186 const_cast<DictionaryValue*>(&manifest)->SetString( |
| 187 Extension::kPublicKeyKey, public_key_); |
| 188 |
| 166 // The extension was unpacked to the temp dir inside our unpacking dir. | 189 // The extension was unpacked to the temp dir inside our unpacking dir. |
| 167 FilePath extension_dir = temp_extension_path_.DirName().AppendASCII( | 190 FilePath extension_dir = temp_extension_path_.DirName().AppendASCII( |
| 168 ExtensionsServiceBackend::kTempExtensionName); | 191 ExtensionsServiceBackend::kTempExtensionName); |
| 169 backend_->OnExtensionUnpacked(extension_path_, extension_dir, | 192 backend_->OnExtensionUnpacked(extension_path_, extension_dir, |
| 170 expected_id_, from_external_, | 193 expected_id_, from_external_, |
| 171 manifest, images); | 194 manifest, images); |
| 172 Cleanup(); | 195 Cleanup(); |
| 173 } | 196 } |
| 174 | 197 |
| 175 virtual void OnUnpackExtensionFailed(const std::string& error_message) { | 198 virtual void OnUnpackExtensionFailed(const std::string& error_message) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 192 MessageLoop* file_loop) { | 215 MessageLoop* file_loop) { |
| 193 UtilityProcessHost* host = new UtilityProcessHost(rdh, this, file_loop); | 216 UtilityProcessHost* host = new UtilityProcessHost(rdh, this, file_loop); |
| 194 host->StartExtensionUnpacker(temp_extension_path_); | 217 host->StartExtensionUnpacker(temp_extension_path_); |
| 195 } | 218 } |
| 196 | 219 |
| 197 scoped_refptr<ExtensionsServiceBackend> backend_; | 220 scoped_refptr<ExtensionsServiceBackend> backend_; |
| 198 | 221 |
| 199 // The path to the crx file that we're installing. | 222 // The path to the crx file that we're installing. |
| 200 FilePath extension_path_; | 223 FilePath extension_path_; |
| 201 | 224 |
| 225 // The public key of the extension we're installing. |
| 226 std::string public_key_; |
| 227 |
| 202 // The path to the copy of the crx file in the temporary directory where we're | 228 // The path to the copy of the crx file in the temporary directory where we're |
| 203 // unpacking it. | 229 // unpacking it. |
| 204 FilePath temp_extension_path_; | 230 FilePath temp_extension_path_; |
| 205 | 231 |
| 206 // The ID we expect this extension to have, if any. | 232 // The ID we expect this extension to have, if any. |
| 207 std::string expected_id_; | 233 std::string expected_id_; |
| 208 | 234 |
| 209 // True if this is being installed from an external source. | 235 // True if this is being installed from an external source. |
| 210 bool from_external_; | 236 bool from_external_; |
| 211 | 237 |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 366 | 392 |
| 367 NotificationService::current()->Notify( | 393 NotificationService::current()->Notify( |
| 368 NotificationType::EXTENSIONS_LOADED, | 394 NotificationType::EXTENSIONS_LOADED, |
| 369 NotificationService::AllSources(), | 395 NotificationService::AllSources(), |
| 370 Details<ExtensionList>(&enabled_extensions)); | 396 Details<ExtensionList>(&enabled_extensions)); |
| 371 | 397 |
| 372 delete new_extensions; | 398 delete new_extensions; |
| 373 } | 399 } |
| 374 | 400 |
| 375 void ExtensionsService::OnExtensionInstalled(Extension* extension, | 401 void ExtensionsService::OnExtensionInstalled(Extension* extension, |
| 376 bool update) { | 402 Extension::InstallType install_type) { |
| 377 UpdateExtensionPref(ASCIIToWide(extension->id()), kState, | 403 UpdateExtensionPref(ASCIIToWide(extension->id()), kState, |
| 378 Value::CreateIntegerValue(Extension::ENABLED), false); | 404 Value::CreateIntegerValue(Extension::ENABLED), false); |
| 379 UpdateExtensionPref(ASCIIToWide(extension->id()), kLocation, | 405 UpdateExtensionPref(ASCIIToWide(extension->id()), kLocation, |
| 380 Value::CreateIntegerValue(Extension::INTERNAL), true); | 406 Value::CreateIntegerValue(Extension::INTERNAL), true); |
| 381 | 407 |
| 382 // If the extension is a theme, tell the profile (and therefore ThemeProvider) | 408 // If the extension is a theme, tell the profile (and therefore ThemeProvider) |
| 383 // to apply it. | 409 // to apply it. |
| 384 if (extension->IsTheme()) { | 410 if (extension->IsTheme()) { |
| 385 NotificationService::current()->Notify( | 411 NotificationService::current()->Notify( |
| 386 NotificationType::THEME_INSTALLED, | 412 NotificationType::THEME_INSTALLED, |
| 387 NotificationService::AllSources(), | 413 NotificationService::AllSources(), |
| 388 Details<Extension>(extension)); | 414 Details<Extension>(extension)); |
| 389 } else { | 415 } else { |
| 390 NotificationService::current()->Notify( | 416 NotificationService::current()->Notify( |
| 391 NotificationType::EXTENSION_INSTALLED, | 417 NotificationType::EXTENSION_INSTALLED, |
| 392 NotificationService::AllSources(), | 418 NotificationService::AllSources(), |
| 393 Details<Extension>(extension)); | 419 Details<Extension>(extension)); |
| 394 } | 420 } |
| 395 } | 421 } |
| 396 | 422 |
| 397 void ExtensionsService::OnExternalExtensionInstalled( | 423 void ExtensionsService::OnExternalExtensionInstalled( |
| 398 const std::string& id, Extension::Location location) { | 424 const std::string& id, Extension::Location location) { |
| 399 DCHECK(Extension::IsExternalLocation(location)); | 425 DCHECK(Extension::IsExternalLocation(location)); |
| 400 UpdateExtensionPref(ASCIIToWide(id), kState, | 426 UpdateExtensionPref(ASCIIToWide(id), kState, |
| 401 Value::CreateIntegerValue(Extension::ENABLED), false); | 427 Value::CreateIntegerValue(Extension::ENABLED), false); |
| 402 UpdateExtensionPref(ASCIIToWide(id), kLocation, | 428 UpdateExtensionPref(ASCIIToWide(id), kLocation, |
| 403 Value::CreateIntegerValue(location), true); | 429 Value::CreateIntegerValue(location), true); |
| 404 } | 430 } |
| 405 | 431 |
| 406 void ExtensionsService::OnExtensionVersionReinstalled(const std::string& id) { | 432 void ExtensionsService::OnExtensionOverinstallAttempted(const std::string& id) { |
| 407 Extension* extension = GetExtensionByID(id); | 433 Extension* extension = GetExtensionByID(id); |
| 408 if (extension && extension->IsTheme()) { | 434 if (extension && extension->IsTheme()) { |
| 409 NotificationService::current()->Notify( | 435 NotificationService::current()->Notify( |
| 410 NotificationType::THEME_INSTALLED, | 436 NotificationType::THEME_INSTALLED, |
| 411 NotificationService::AllSources(), | 437 NotificationService::AllSources(), |
| 412 Details<Extension>(extension)); | 438 Details<Extension>(extension)); |
| 413 } | 439 } |
| 414 } | 440 } |
| 415 | 441 |
| 416 Extension* ExtensionsService::GetExtensionByID(std::string id) { | 442 Extension* ExtensionsService::GetExtensionByID(std::string id) { |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 617 Extension* extension = LoadExtension(extension_path, | 643 Extension* extension = LoadExtension(extension_path, |
| 618 false); // don't require ID | 644 false); // don't require ID |
| 619 if (extension) { | 645 if (extension) { |
| 620 extension->set_location(Extension::LOAD); | 646 extension->set_location(Extension::LOAD); |
| 621 ExtensionList* extensions = new ExtensionList; | 647 ExtensionList* extensions = new ExtensionList; |
| 622 extensions->push_back(extension); | 648 extensions->push_back(extension); |
| 623 ReportExtensionsLoaded(extensions); | 649 ReportExtensionsLoaded(extensions); |
| 624 } | 650 } |
| 625 } | 651 } |
| 626 | 652 |
| 653 DictionaryValue* ExtensionsServiceBackend::ReadManifest(FilePath manifest_path, |
| 654 std::string* error) { |
| 655 JSONFileValueSerializer serializer(manifest_path); |
| 656 scoped_ptr<Value> root(serializer.Deserialize(error)); |
| 657 if (!root.get()) |
| 658 return NULL; |
| 659 |
| 660 if (!root->IsType(Value::TYPE_DICTIONARY)) { |
| 661 *error = Extension::kInvalidManifestError; |
| 662 return NULL; |
| 663 } |
| 664 |
| 665 return static_cast<DictionaryValue*>(root.release()); |
| 666 } |
| 667 |
| 627 Extension* ExtensionsServiceBackend::LoadExtension( | 668 Extension* ExtensionsServiceBackend::LoadExtension( |
| 628 const FilePath& extension_path, bool require_id) { | 669 const FilePath& extension_path, bool require_id) { |
| 629 FilePath manifest_path = | 670 FilePath manifest_path = |
| 630 extension_path.AppendASCII(Extension::kManifestFilename); | 671 extension_path.AppendASCII(Extension::kManifestFilename); |
| 631 if (!file_util::PathExists(manifest_path)) { | 672 if (!file_util::PathExists(manifest_path)) { |
| 632 ReportExtensionLoadError(extension_path, Extension::kInvalidManifestError); | 673 ReportExtensionLoadError(extension_path, Extension::kInvalidManifestError); |
| 633 return NULL; | 674 return NULL; |
| 634 } | 675 } |
| 635 | 676 |
| 636 JSONFileValueSerializer serializer(manifest_path); | |
| 637 std::string error; | 677 std::string error; |
| 638 scoped_ptr<Value> root(serializer.Deserialize(&error)); | 678 scoped_ptr<DictionaryValue> root(ReadManifest(manifest_path, &error)); |
| 639 if (!root.get()) { | 679 if (!root.get()) { |
| 640 ReportExtensionLoadError(extension_path, error); | 680 ReportExtensionLoadError(extension_path, error); |
| 641 return NULL; | 681 return NULL; |
| 642 } | 682 } |
| 643 | 683 |
| 644 if (!root->IsType(Value::TYPE_DICTIONARY)) { | |
| 645 ReportExtensionLoadError(extension_path, Extension::kInvalidManifestError); | |
| 646 return NULL; | |
| 647 } | |
| 648 | |
| 649 scoped_ptr<Extension> extension(new Extension(extension_path)); | 684 scoped_ptr<Extension> extension(new Extension(extension_path)); |
| 650 if (!extension->InitFromValue(*static_cast<DictionaryValue*>(root.get()), | 685 if (!extension->InitFromValue(*root.get(), require_id, &error)) { |
| 651 require_id, &error)) { | |
| 652 ReportExtensionLoadError(extension_path, error); | 686 ReportExtensionLoadError(extension_path, error); |
| 653 return NULL; | 687 return NULL; |
| 654 } | 688 } |
| 655 | 689 |
| 656 FilePath external_marker = extension_path.AppendASCII(kExternalInstallFile); | 690 FilePath external_marker = extension_path.AppendASCII(kExternalInstallFile); |
| 657 if (file_util::PathExists(external_marker)) { | 691 if (file_util::PathExists(external_marker)) { |
| 658 extension->set_location( | 692 extension->set_location( |
| 659 extension->ExternalExtensionInstallType(registry_path_)); | 693 extension->ExternalExtensionInstallType(registry_path_)); |
| 660 } else { | 694 } else { |
| 661 extension->set_location(Extension::INTERNAL); | 695 extension->set_location(Extension::INTERNAL); |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 756 dir.AppendASCII(ExtensionsService::kCurrentVersionFileName); | 790 dir.AppendASCII(ExtensionsService::kCurrentVersionFileName); |
| 757 if (file_util::PathExists(current_version)) { | 791 if (file_util::PathExists(current_version)) { |
| 758 if (file_util::ReadFileToString(current_version, version_string)) { | 792 if (file_util::ReadFileToString(current_version, version_string)) { |
| 759 TrimWhitespace(*version_string, TRIM_ALL, version_string); | 793 TrimWhitespace(*version_string, TRIM_ALL, version_string); |
| 760 return true; | 794 return true; |
| 761 } | 795 } |
| 762 } | 796 } |
| 763 return false; | 797 return false; |
| 764 } | 798 } |
| 765 | 799 |
| 766 bool ExtensionsServiceBackend::CheckCurrentVersion( | 800 Extension::InstallType ExtensionsServiceBackend::CompareToInstalledVersion( |
| 801 const std::string& id, |
| 767 const std::string& new_version_str, | 802 const std::string& new_version_str, |
| 768 const std::string& current_version_str, | 803 std::string *current_version_str) { |
| 769 const FilePath& dest_dir) { | 804 CHECK(current_version_str); |
| 805 FilePath dir(install_directory_.AppendASCII(id.c_str())); |
| 806 if (!ReadCurrentVersion(dir, current_version_str)) |
| 807 return Extension::NEW_INSTALL; |
| 808 |
| 770 scoped_ptr<Version> current_version( | 809 scoped_ptr<Version> current_version( |
| 771 Version::GetVersionFromString(current_version_str)); | 810 Version::GetVersionFromString(*current_version_str)); |
| 772 scoped_ptr<Version> new_version( | 811 scoped_ptr<Version> new_version( |
| 773 Version::GetVersionFromString(new_version_str)); | 812 Version::GetVersionFromString(new_version_str)); |
| 774 if (current_version->CompareTo(*new_version) >= 0) { | 813 int comp = new_version->CompareTo(*current_version); |
| 775 // Verify that the directory actually exists. If it doesn't we'll return | 814 if (comp > 0) |
| 776 // true so that the install code will repair the broken installation. | 815 return Extension::UPGRADE; |
| 777 // TODO(erikkay): A further step would be to verify that the extension | 816 else if (comp == 0) |
| 778 // has actually loaded successfully. | 817 return Extension::REINSTALL; |
| 779 FilePath version_dir = dest_dir.AppendASCII(current_version_str); | 818 else |
| 780 if (file_util::PathExists(version_dir)) { | 819 return Extension::DOWNGRADE; |
| 781 std::string id = WideToASCII(dest_dir.BaseName().ToWStringHack()); | 820 } |
| 782 StringToLowerASCII(&id); | 821 |
| 783 ReportExtensionVersionReinstalled(id); | 822 bool ExtensionsServiceBackend::NeedsReinstall(const std::string& id, |
| 784 return false; | 823 const std::string& current_version) { |
| 785 } | 824 // Verify that the directory actually exists. |
| 786 } | 825 // TODO(erikkay): A further step would be to verify that the extension |
| 787 return true; | 826 // has actually loaded successfully. |
| 827 FilePath dir(install_directory_.AppendASCII(id.c_str())); |
| 828 FilePath version_dir(dir.AppendASCII(current_version)); |
| 829 return !file_util::PathExists(version_dir); |
| 788 } | 830 } |
| 789 | 831 |
| 790 bool ExtensionsServiceBackend::InstallDirSafely(const FilePath& source_dir, | 832 bool ExtensionsServiceBackend::InstallDirSafely(const FilePath& source_dir, |
| 791 const FilePath& dest_dir) { | 833 const FilePath& dest_dir) { |
| 792 if (file_util::PathExists(dest_dir)) { | 834 if (file_util::PathExists(dest_dir)) { |
| 793 // By the time we get here, it should be safe to assume that this directory | 835 // By the time we get here, it should be safe to assume that this directory |
| 794 // is not currently in use (it's not the current active version). | 836 // is not currently in use (it's not the current active version). |
| 795 if (!file_util::Delete(dest_dir, true)) { | 837 if (!file_util::Delete(dest_dir, true)) { |
| 796 ReportExtensionInstallError(source_dir, | 838 ReportExtensionInstallError(source_dir, |
| 797 "Can't delete existing version directory."); | 839 "Can't delete existing version directory."); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 864 LOG(INFO) << "Installing extension " << extension_path.value(); | 906 LOG(INFO) << "Installing extension " << extension_path.value(); |
| 865 | 907 |
| 866 frontend_ = frontend; | 908 frontend_ = frontend; |
| 867 alert_on_error_ = true; | 909 alert_on_error_ = true; |
| 868 | 910 |
| 869 bool from_external = false; | 911 bool from_external = false; |
| 870 InstallOrUpdateExtension(extension_path, std::string(), from_external); | 912 InstallOrUpdateExtension(extension_path, std::string(), from_external); |
| 871 } | 913 } |
| 872 | 914 |
| 873 void ExtensionsServiceBackend::InstallOrUpdateExtension( | 915 void ExtensionsServiceBackend::InstallOrUpdateExtension( |
| 874 const FilePath& extension_path, const std::string& expected_id, | 916 const FilePath& extension_path, |
| 917 const std::string& expected_id, |
| 875 bool from_external) { | 918 bool from_external) { |
| 876 UnpackerClient* client = | 919 std::string actual_public_key; |
| 877 new UnpackerClient(this, extension_path, expected_id, from_external); | 920 if (!ValidateSignature(extension_path, &actual_public_key)) |
| 921 return; // Failures reported within ValidateSignature(). |
| 922 |
| 923 UnpackerClient* client = new UnpackerClient( |
| 924 this, extension_path, actual_public_key, expected_id, from_external); |
| 878 client->Start(); | 925 client->Start(); |
| 879 } | 926 } |
| 880 | 927 |
| 928 bool ExtensionsServiceBackend::ValidateSignature(const FilePath& extension_path, |
| 929 std::string* key_out) { |
| 930 ScopedStdioHandle file(file_util::OpenFile(extension_path, "rb")); |
| 931 if (!file.get()) { |
| 932 ReportExtensionInstallError(extension_path, "Could not open file."); |
| 933 return NULL; |
| 934 } |
| 935 |
| 936 // Read and verify the header. |
| 937 ExtensionsService::ExtensionHeader header; |
| 938 size_t len; |
| 939 |
| 940 // TODO(erikkay): Yuck. I'm not a big fan of this kind of code, but it |
| 941 // appears that we don't have any endian/alignment aware serialization |
| 942 // code in the code base. So for now, this assumes that we're running |
| 943 // on a little endian machine with 4 byte alignment. |
| 944 len = fread(&header, 1, sizeof(ExtensionsService::ExtensionHeader), |
| 945 file.get()); |
| 946 if (len < sizeof(ExtensionsService::ExtensionHeader)) { |
| 947 ReportExtensionInstallError(extension_path, kInvalidExtensionHeaderError); |
| 948 return false; |
| 949 } |
| 950 if (strncmp(ExtensionsService::kExtensionHeaderMagic, header.magic, |
| 951 sizeof(header.magic))) { |
| 952 ReportExtensionInstallError(extension_path, kBadMagicNumberError); |
| 953 return false; |
| 954 } |
| 955 if (header.version != ExtensionsService::kCurrentVersion) { |
| 956 ReportExtensionInstallError(extension_path, kBadVersionNumberError); |
| 957 return false; |
| 958 } |
| 959 if (header.key_size > ExtensionsService::kMaxPublicKeySize || |
| 960 header.signature_size > ExtensionsService::kMaxSignatureSize) { |
| 961 ReportExtensionInstallError(extension_path, kBadHeaderSizeError); |
| 962 return false; |
| 963 } |
| 964 |
| 965 std::vector<uint8> key; |
| 966 key.resize(header.key_size); |
| 967 len = fread(&key.front(), sizeof(uint8), header.key_size, file.get()); |
| 968 if (len < header.key_size) { |
| 969 ReportExtensionInstallError(extension_path, kInvalidPublicKeyError); |
| 970 return false; |
| 971 } |
| 972 |
| 973 std::vector<uint8> signature; |
| 974 signature.resize(header.signature_size); |
| 975 len = fread(&signature.front(), sizeof(uint8), header.signature_size, |
| 976 file.get()); |
| 977 if (len < header.signature_size) { |
| 978 ReportExtensionInstallError(extension_path, kInvalidSignatureError); |
| 979 return false; |
| 980 } |
| 981 |
| 982 // Note: this structure is an ASN.1 which encodes the algorithm used |
| 983 // with its parameters. This is defined in PKCS #1 v2.1 (RFC 3447). |
| 984 // It is encoding: { OID sha1WithRSAEncryption PARAMETERS NULL } |
| 985 // TODO(aa): This needs to be factored away someplace common. |
| 986 const uint8 signature_algorithm[15] = { |
| 987 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, |
| 988 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00 |
| 989 }; |
| 990 |
| 991 base::SignatureVerifier verifier; |
| 992 if (!verifier.VerifyInit(signature_algorithm, |
| 993 sizeof(signature_algorithm), |
| 994 &signature.front(), |
| 995 signature.size(), |
| 996 &key.front(), |
| 997 key.size())) { |
| 998 ReportExtensionInstallError(extension_path, |
| 999 kSignatureVerificationInitFailed); |
| 1000 return false; |
| 1001 } |
| 1002 |
| 1003 unsigned char buf[1 << 12]; |
| 1004 while ((len = fread(buf, 1, sizeof(buf), file.get())) > 0) |
| 1005 verifier.VerifyUpdate(buf, len); |
| 1006 |
| 1007 if (!verifier.VerifyFinal()) { |
| 1008 ReportExtensionInstallError(extension_path, kSignatureVerificationFailed); |
| 1009 return false; |
| 1010 } |
| 1011 |
| 1012 net::Base64Encode(std::string(reinterpret_cast<char*>(&key.front()), |
| 1013 key.size()), key_out); |
| 1014 return true; |
| 1015 } |
| 1016 |
| 881 void ExtensionsServiceBackend::OnExtensionUnpacked( | 1017 void ExtensionsServiceBackend::OnExtensionUnpacked( |
| 882 const FilePath& extension_path, | 1018 const FilePath& extension_path, |
| 883 const FilePath& temp_extension_dir, | 1019 const FilePath& temp_extension_dir, |
| 884 const std::string expected_id, | 1020 const std::string expected_id, |
| 885 bool from_external, | 1021 bool from_external, |
| 886 const DictionaryValue& manifest, | 1022 const DictionaryValue& manifest, |
| 887 const std::vector< Tuple2<SkBitmap, FilePath> >& images) { | 1023 const std::vector< Tuple2<SkBitmap, FilePath> >& images) { |
| 888 Extension extension; | 1024 Extension extension; |
| 889 std::string error; | 1025 std::string error; |
| 890 if (!extension.InitFromValue(manifest, | 1026 if (!extension.InitFromValue(manifest, |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 933 error_msg += expected_id; | 1069 error_msg += expected_id; |
| 934 error_msg += ")"; | 1070 error_msg += ")"; |
| 935 ReportExtensionInstallError(extension_path, error_msg); | 1071 ReportExtensionInstallError(extension_path, error_msg); |
| 936 return; | 1072 return; |
| 937 } | 1073 } |
| 938 | 1074 |
| 939 // <profile>/Extensions/<id> | 1075 // <profile>/Extensions/<id> |
| 940 FilePath dest_dir = install_directory_.AppendASCII(extension.id()); | 1076 FilePath dest_dir = install_directory_.AppendASCII(extension.id()); |
| 941 std::string version = extension.VersionString(); | 1077 std::string version = extension.VersionString(); |
| 942 std::string current_version; | 1078 std::string current_version; |
| 943 bool was_update = false; | 1079 Extension::InstallType install_type = |
| 944 if (ReadCurrentVersion(dest_dir, ¤t_version)) { | 1080 CompareToInstalledVersion(extension.id(), version, ¤t_version); |
| 945 if (!CheckCurrentVersion(version, current_version, dest_dir)) | 1081 |
| 1082 // Do not allow downgrade. |
| 1083 if (install_type == Extension::DOWNGRADE) { |
| 1084 ReportExtensionInstallError(extension_path, |
| 1085 "Error: Attempt to downgrade extension from more recent version."); |
| 1086 return; |
| 1087 } |
| 1088 |
| 1089 if (install_type == Extension::REINSTALL) { |
| 1090 if (NeedsReinstall(extension.id(), current_version)) { |
| 1091 // Treat corrupted existing installation as new install case. |
| 1092 install_type = Extension::NEW_INSTALL; |
| 1093 } else { |
| 1094 // The client may use this as a signal (to switch themes, for instance). |
| 1095 ReportExtensionOverinstallAttempted(extension.id()); |
| 946 return; | 1096 return; |
| 947 was_update = true; | 1097 } |
| 948 } | 1098 } |
| 949 | 1099 |
| 950 // Write our parsed manifest back to disk, to ensure it doesn't contain an | 1100 // Write our parsed manifest back to disk, to ensure it doesn't contain an |
| 951 // exploitable bug that can be used to compromise the browser. | 1101 // exploitable bug that can be used to compromise the browser. |
| 952 std::string manifest_json; | 1102 std::string manifest_json; |
| 953 JSONStringValueSerializer serializer(&manifest_json); | 1103 JSONStringValueSerializer serializer(&manifest_json); |
| 954 serializer.set_pretty_print(true); | 1104 serializer.set_pretty_print(true); |
| 955 if (!serializer.Serialize(manifest)) { | 1105 if (!serializer.Serialize(manifest)) { |
| 956 ReportExtensionInstallError(extension_path, | 1106 ReportExtensionInstallError(extension_path, |
| 957 "Error serializing manifest.json."); | 1107 "Error serializing manifest.json."); |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1036 // occurs before the normal startup so we just let startup pick them up. We | 1186 // occurs before the normal startup so we just let startup pick them up. We |
| 1037 // notify on installation of external extensions because we need to update | 1187 // notify on installation of external extensions because we need to update |
| 1038 // the preferences for these extensions to reflect that they've just been | 1188 // the preferences for these extensions to reflect that they've just been |
| 1039 // installed. | 1189 // installed. |
| 1040 if (!from_external) { | 1190 if (!from_external) { |
| 1041 Extension* extension = LoadExtension(version_dir, true); // require id | 1191 Extension* extension = LoadExtension(version_dir, true); // require id |
| 1042 CHECK(extension); | 1192 CHECK(extension); |
| 1043 | 1193 |
| 1044 frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod( | 1194 frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod( |
| 1045 frontend_, &ExtensionsService::OnExtensionInstalled, extension, | 1195 frontend_, &ExtensionsService::OnExtensionInstalled, extension, |
| 1046 was_update)); | 1196 install_type)); |
| 1047 | 1197 |
| 1048 // Only one extension, but ReportExtensionsLoaded can handle multiple, | 1198 // Only one extension, but ReportExtensionsLoaded can handle multiple, |
| 1049 // so we need to construct a list. | 1199 // so we need to construct a list. |
| 1050 scoped_ptr<ExtensionList> extensions(new ExtensionList); | 1200 scoped_ptr<ExtensionList> extensions(new ExtensionList); |
| 1051 extensions->push_back(extension); | 1201 extensions->push_back(extension); |
| 1052 LOG(INFO) << "Done."; | 1202 LOG(INFO) << "Done."; |
| 1053 // Hand off ownership of the loaded extensions to the frontend. | 1203 // Hand off ownership of the loaded extensions to the frontend. |
| 1054 ReportExtensionsLoaded(extensions.release()); | 1204 ReportExtensionsLoaded(extensions.release()); |
| 1055 } else { | 1205 } else { |
| 1056 frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod( | 1206 frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod( |
| 1057 frontend_, &ExtensionsService::OnExternalExtensionInstalled, | 1207 frontend_, &ExtensionsService::OnExternalExtensionInstalled, |
| 1058 extension.id(), | 1208 extension.id(), |
| 1059 extension.ExternalExtensionInstallType(registry_path_))); | 1209 extension.ExternalExtensionInstallType(registry_path_))); |
| 1060 } | 1210 } |
| 1061 | 1211 |
| 1062 scoped_version_dir.Take(); | 1212 scoped_version_dir.Take(); |
| 1063 } | 1213 } |
| 1064 | 1214 |
| 1065 void ExtensionsServiceBackend::ReportExtensionInstallError( | 1215 void ExtensionsServiceBackend::ReportExtensionInstallError( |
| 1066 const FilePath& extension_path, const std::string &error) { | 1216 const FilePath& extension_path, const std::string &error) { |
| 1067 | 1217 |
| 1068 // TODO(erikkay): note that this isn't guaranteed to work properly on Linux. | 1218 // TODO(erikkay): note that this isn't guaranteed to work properly on Linux. |
| 1069 std::string path_str = WideToASCII(extension_path.ToWStringHack()); | 1219 std::string path_str = WideToASCII(extension_path.ToWStringHack()); |
| 1070 std::string message = | 1220 std::string message = |
| 1071 StringPrintf("Could not install extension from '%s'. %s", | 1221 StringPrintf("Could not install extension from '%s'. %s", |
| 1072 path_str.c_str(), error.c_str()); | 1222 path_str.c_str(), error.c_str()); |
| 1073 ExtensionErrorReporter::GetInstance()->ReportError(message, alert_on_error_); | 1223 ExtensionErrorReporter::GetInstance()->ReportError(message, alert_on_error_); |
| 1074 } | 1224 } |
| 1075 | 1225 |
| 1076 void ExtensionsServiceBackend::ReportExtensionVersionReinstalled( | 1226 void ExtensionsServiceBackend::ReportExtensionOverinstallAttempted( |
| 1077 const std::string& id) { | 1227 const std::string& id) { |
| 1078 frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod( | 1228 frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod( |
| 1079 frontend_, &ExtensionsService::OnExtensionVersionReinstalled, id)); | 1229 frontend_, &ExtensionsService::OnExtensionOverinstallAttempted, id)); |
| 1080 } | 1230 } |
| 1081 | 1231 |
| 1082 bool ExtensionsServiceBackend::ShouldSkipInstallingExtension( | 1232 bool ExtensionsServiceBackend::ShouldSkipInstallingExtension( |
| 1083 const std::set<std::string>& ids_to_ignore, | 1233 const std::set<std::string>& ids_to_ignore, |
| 1084 const std::string& id) { | 1234 const std::string& id) { |
| 1085 if (ids_to_ignore.find(id) != ids_to_ignore.end()) { | 1235 if (ids_to_ignore.find(id) != ids_to_ignore.end()) { |
| 1086 LOG(INFO) << "Skipping uninstalled external extension " << id; | 1236 LOG(INFO) << "Skipping uninstalled external extension " << id; |
| 1087 return true; | 1237 return true; |
| 1088 } | 1238 } |
| 1089 return false; | 1239 return false; |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1255 // not a big deal though, because we'll notice next time we startup that the | 1405 // not a big deal though, because we'll notice next time we startup that the |
| 1256 // Current Version file is gone and finish the delete then. | 1406 // Current Version file is gone and finish the delete then. |
| 1257 if (!file_util::Delete(extension_directory, true)) { | 1407 if (!file_util::Delete(extension_directory, true)) { |
| 1258 LOG(WARNING) << "Could not delete directory for extension " | 1408 LOG(WARNING) << "Could not delete directory for extension " |
| 1259 << extension_id; | 1409 << extension_id; |
| 1260 } | 1410 } |
| 1261 } | 1411 } |
| 1262 | 1412 |
| 1263 bool ExtensionsServiceBackend::ShouldInstall(const std::string& id, | 1413 bool ExtensionsServiceBackend::ShouldInstall(const std::string& id, |
| 1264 const std::string& version) { | 1414 const std::string& version) { |
| 1265 FilePath dir(install_directory_.AppendASCII(id.c_str())); | |
| 1266 std::string current_version; | 1415 std::string current_version; |
| 1267 if (ReadCurrentVersion(dir, ¤t_version)) { | 1416 Extension::InstallType install_type = CompareToInstalledVersion(id, version, |
| 1268 return CheckCurrentVersion(version, current_version, dir); | 1417 ¤t_version); |
| 1269 } | 1418 |
| 1270 return true; | 1419 if (install_type == Extension::DOWNGRADE) |
| 1420 return false; |
| 1421 |
| 1422 return (install_type == Extension::UPGRADE || |
| 1423 install_type == Extension::NEW_INSTALL || |
| 1424 NeedsReinstall(id, current_version)); |
| 1271 } | 1425 } |
| OLD | NEW |