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