diff options
author | bauerb@chromium.org <bauerb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-15 09:42:23 +0000 |
---|---|---|
committer | bauerb@chromium.org <bauerb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-15 09:42:23 +0000 |
commit | 3eff9e2e46c00ec5c0316fef6c44355793f1906d (patch) | |
tree | b4a346aefc756be26707cfa00952d906df8c95ba /webkit | |
parent | 682ef685be471686d07513f4e44e59c9a71cf356 (diff) | |
download | chromium_src-3eff9e2e46c00ec5c0316fef6c44355793f1906d.zip chromium_src-3eff9e2e46c00ec5c0316fef6c44355793f1906d.tar.gz chromium_src-3eff9e2e46c00ec5c0316fef6c44355793f1906d.tar.bz2 |
Revert 101269 - Store plug-in enabled/disabled state in PluginPrefs instead of WebPluginInfo, to allow different sets of enabled/disabled plug-ins to be specified per profile.
BUG=80794
TEST=Open two profiles, disable different plugins in them.
Review URL: http://codereview.chromium.org/7848025
TBR=bauerb@chromium.org
Review URL: http://codereview.chromium.org/7901015
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@101272 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit')
-rw-r--r-- | webkit/plugins/npapi/plugin_group.cc | 366 | ||||
-rw-r--r-- | webkit/plugins/npapi/plugin_group.h | 102 | ||||
-rw-r--r-- | webkit/plugins/npapi/plugin_group_unittest.cc | 220 | ||||
-rw-r--r-- | webkit/plugins/npapi/plugin_lib_mac.mm | 1 | ||||
-rw-r--r-- | webkit/plugins/npapi/plugin_lib_posix.cc | 1 | ||||
-rw-r--r-- | webkit/plugins/npapi/plugin_lib_win.cc | 3 | ||||
-rw-r--r-- | webkit/plugins/npapi/plugin_list.cc | 113 | ||||
-rw-r--r-- | webkit/plugins/npapi/plugin_list.h | 50 | ||||
-rw-r--r-- | webkit/plugins/npapi/plugin_list_mac.mm | 2 | ||||
-rw-r--r-- | webkit/plugins/npapi/plugin_list_posix.cc | 4 | ||||
-rw-r--r-- | webkit/plugins/npapi/plugin_list_unittest.cc | 72 | ||||
-rw-r--r-- | webkit/plugins/npapi/plugin_list_win.cc | 6 | ||||
-rw-r--r-- | webkit/plugins/webplugininfo.cc | 11 | ||||
-rw-r--r-- | webkit/plugins/webplugininfo.h | 32 | ||||
-rw-r--r-- | webkit/support/webkit_support_glue.cc | 1 | ||||
-rw-r--r-- | webkit/tools/test_shell/test_shell.cc | 1 |
16 files changed, 932 insertions, 53 deletions
diff --git a/webkit/plugins/npapi/plugin_group.cc b/webkit/plugins/npapi/plugin_group.cc index b0c89f4..1f5745e 100644 --- a/webkit/plugins/npapi/plugin_group.cc +++ b/webkit/plugins/npapi/plugin_group.cc @@ -27,6 +27,83 @@ const char* PluginGroup::kRealPlayerGroupName = "RealPlayer"; const char* PluginGroup::kSilverlightGroupName = "Silverlight"; const char* PluginGroup::kWindowsMediaPlayerGroupName = "Windows Media Player"; +/*static*/ +std::set<string16>* PluginGroup::policy_disabled_plugin_patterns_; +/*static*/ +std::set<string16>* PluginGroup::policy_disabled_plugin_exception_patterns_; +/*static*/ +std::set<string16>* PluginGroup::policy_enabled_plugin_patterns_; + +/*static*/ +void PluginGroup::SetPolicyEnforcedPluginPatterns( + const std::set<string16>& plugins_disabled, + const std::set<string16>& plugins_disabled_exceptions, + const std::set<string16>& plugins_enabled) { + if (!policy_disabled_plugin_patterns_) + policy_disabled_plugin_patterns_ = new std::set<string16>(plugins_disabled); + else + *policy_disabled_plugin_patterns_ = plugins_disabled; + + if (!policy_disabled_plugin_exception_patterns_) + policy_disabled_plugin_exception_patterns_ = + new std::set<string16>(plugins_disabled_exceptions); + else + *policy_disabled_plugin_exception_patterns_ = plugins_disabled_exceptions; + + if (!policy_enabled_plugin_patterns_) + policy_enabled_plugin_patterns_ = new std::set<string16>(plugins_enabled); + else + *policy_enabled_plugin_patterns_ = plugins_enabled; +} + +/*static*/ +bool PluginGroup::IsStringMatchedInSet(const string16& name, + const std::set<string16>* pattern_set) { + if (!pattern_set) + return false; + + std::set<string16>::const_iterator pattern(pattern_set->begin()); + while (pattern != pattern_set->end()) { + if (MatchPattern(name, *pattern)) + return true; + ++pattern; + } + + return false; +} + +/*static*/ +bool PluginGroup::IsPluginNameDisabledByPolicy(const string16& plugin_name) { + // A plugin that matches some "disabled" pattern but also matches an "enabled" + // pattern will be enabled. Example: disable "*", enable "Flash, Java". + // Same for matching an "exception" pattern. + return IsStringMatchedInSet(plugin_name, policy_disabled_plugin_patterns_) && + !IsStringMatchedInSet(plugin_name, policy_enabled_plugin_patterns_) && + !IsStringMatchedInSet(plugin_name, + policy_disabled_plugin_exception_patterns_); +} + +/*static*/ +bool PluginGroup::IsPluginFileNameDisabledByPolicy(const string16& plugin_name, + const string16& group_name) { + // This handles a specific plugin within a group that is allowed, + // but whose name matches a disabled pattern. + // Example: disable "*", exception "Java". + bool group_has_exception = IsStringMatchedInSet( + group_name, + policy_disabled_plugin_exception_patterns_); + + return !IsPluginNameEnabledByPolicy(plugin_name) && + !group_has_exception && + IsPluginNameDisabledByPolicy(plugin_name); +} + +/*static*/ +bool PluginGroup::IsPluginNameEnabledByPolicy(const string16& plugin_name) { + // There are no exceptions to enabled plugins. + return IsStringMatchedInSet(plugin_name, policy_enabled_plugin_patterns_); +} + VersionRange::VersionRange(const VersionRangeDefinition& definition) : low_str(definition.version_matcher_low), high_str(definition.version_matcher_high), @@ -68,15 +145,20 @@ PluginGroup::PluginGroup(const string16& group_name, : identifier_(identifier), group_name_(group_name), name_matcher_(name_matcher), - update_url_(update_url) { + update_url_(update_url), + enabled_(false), + version_(Version::GetVersionFromString("0")) { } void PluginGroup::InitFrom(const PluginGroup& other) { identifier_ = other.identifier_; group_name_ = other.group_name_; name_matcher_ = other.name_matcher_; + description_ = other.description_; update_url_ = other.update_url_; + enabled_ = other.enabled_; version_ranges_ = other.version_ranges_; + version_.reset(other.version_->Clone()); web_plugin_infos_ = other.web_plugin_infos_; } @@ -174,6 +256,33 @@ Version* PluginGroup::CreateVersionFromString(const string16& version_string) { return Version::GetVersionFromString(version); } +void PluginGroup::UpdateActivePlugin(const WebPluginInfo& plugin) { + // A group is enabled if any of the files are enabled. + if (IsPluginEnabled(plugin)) { + // The description of the group needs update either when it's state is + // about to change to enabled or if has never been set. + if (!enabled_ || description_.empty()) + UpdateDescriptionAndVersion(plugin); + // In case an enabled plugin has been added to a group that is currently + // disabled then we should enable the group. + if (!enabled_) + enabled_ = true; + } else { + // If this is the first plugin and it's disabled, + // use its description for now. + if (description_.empty()) + UpdateDescriptionAndVersion(plugin); + } +} + +void PluginGroup::UpdateDescriptionAndVersion(const WebPluginInfo& plugin) { + description_ = plugin.desc; + if (Version* new_version = CreateVersionFromString(plugin.version)) + version_.reset(new_version); + else + version_.reset(Version::GetVersionFromString("0")); +} + void PluginGroup::AddPlugin(const WebPluginInfo& plugin) { // Check if this group already contains this plugin. for (size_t i = 0; i < web_plugin_infos_.size(); ++i) { @@ -183,21 +292,58 @@ void PluginGroup::AddPlugin(const WebPluginInfo& plugin) { } } web_plugin_infos_.push_back(plugin); + UpdateActivePlugin(web_plugin_infos_.back()); } bool PluginGroup::RemovePlugin(const FilePath& filename) { bool did_remove = false; + ResetGroupState(); for (size_t i = 0; i < web_plugin_infos_.size();) { if (web_plugin_infos_[i].path == filename) { web_plugin_infos_.erase(web_plugin_infos_.begin() + i); did_remove = true; } else { + UpdateActivePlugin(web_plugin_infos_[i]); i++; } } return did_remove; } +bool PluginGroup::EnablePlugin(const FilePath& filename) { + bool did_enable = false; + ResetGroupState(); + for (size_t i = 0; i < web_plugin_infos_.size(); ++i) { + if (web_plugin_infos_[i].path == filename) { + did_enable = Enable( + &web_plugin_infos_[i], + IsPluginNameEnabledByPolicy(web_plugin_infos_[i].name) ? + WebPluginInfo::USER_ENABLED_POLICY_ENABLED : + WebPluginInfo::USER_ENABLED); + } + UpdateActivePlugin(web_plugin_infos_[i]); + } + return did_enable; +} + +bool PluginGroup::DisablePlugin(const FilePath& filename) { + bool did_disable = false; + ResetGroupState(); + for (size_t i = 0; i < web_plugin_infos_.size(); ++i) { + if (web_plugin_infos_[i].path == filename) { + // We are only called for user intervention however we should respect a + // policy that might as well be active on this plugin. + did_disable = Disable( + &web_plugin_infos_[i], + IsPluginNameDisabledByPolicy(web_plugin_infos_[i].name) ? + WebPluginInfo::USER_DISABLED_POLICY_DISABLED : + WebPluginInfo::USER_DISABLED); + } + UpdateActivePlugin(web_plugin_infos_[i]); + } + return did_disable; +} + string16 PluginGroup::GetGroupName() const { if (!group_name_.empty()) return group_name_; @@ -219,6 +365,91 @@ bool PluginGroup::ContainsPlugin(const FilePath& path) const { return false; } + +DictionaryValue* PluginGroup::GetSummary() const { + DictionaryValue* result = new DictionaryValue(); + result->SetString("name", GetGroupName()); + result->SetBoolean("enabled", enabled_); + return result; +} + +DictionaryValue* PluginGroup::GetDataForUI() const { + string16 name = GetGroupName(); + DictionaryValue* result = new DictionaryValue(); + result->SetString("name", name); + result->SetString("description", description_); + result->SetString("version", version_->GetString()); + result->SetString("update_url", update_url_); + result->SetBoolean("critical", IsVulnerable()); + + bool group_disabled_by_policy = IsPluginNameDisabledByPolicy(name); + bool group_enabled_by_policy = IsPluginNameEnabledByPolicy(name); + ListValue* plugin_files = new ListValue(); + bool all_plugins_disabled_by_policy = true; + bool all_plugins_enabled_by_policy = true; + for (size_t i = 0; i < web_plugin_infos_.size(); ++i) { + DictionaryValue* plugin_file = new DictionaryValue(); + plugin_file->SetString("name", web_plugin_infos_[i].name); + plugin_file->SetString("description", web_plugin_infos_[i].desc); + plugin_file->SetString("path", web_plugin_infos_[i].path.value()); + plugin_file->SetString("version", web_plugin_infos_[i].version); + + bool plugin_disabled_by_policy = group_disabled_by_policy || + ((web_plugin_infos_[i].enabled & WebPluginInfo::POLICY_DISABLED) != 0); + bool plugin_enabled_by_policy = group_enabled_by_policy || + ((web_plugin_infos_[i].enabled & WebPluginInfo::POLICY_ENABLED) != 0); + + if (!plugin_disabled_by_policy) + all_plugins_disabled_by_policy = false; + if (!plugin_enabled_by_policy) + all_plugins_enabled_by_policy = false; + + if (plugin_disabled_by_policy) { + plugin_file->SetString("enabledMode", "disabledByPolicy"); + } else if (plugin_enabled_by_policy) { + plugin_file->SetString("enabledMode", "enabledByPolicy"); + } else { + plugin_file->SetString( + "enabledMode", IsPluginEnabled(web_plugin_infos_[i]) ? + "enabledByUser" : "disabledByUser"); + } + + ListValue* mime_types = new ListValue(); + const std::vector<WebPluginMimeType>& plugin_mime_types = + web_plugin_infos_[i].mime_types; + for (size_t j = 0; j < plugin_mime_types.size(); ++j) { + DictionaryValue* mime_type = new DictionaryValue(); + mime_type->SetString("mimeType", plugin_mime_types[j].mime_type); + mime_type->SetString("description", plugin_mime_types[j].description); + + ListValue* file_extensions = new ListValue(); + const std::vector<std::string>& mime_file_extensions = + plugin_mime_types[j].file_extensions; + for (size_t k = 0; k < mime_file_extensions.size(); ++k) + file_extensions->Append(new StringValue(mime_file_extensions[k])); + mime_type->Set("fileExtensions", file_extensions); + + mime_types->Append(mime_type); + } + plugin_file->Set("mimeTypes", mime_types); + + plugin_files->Append(plugin_file); + } + + if (group_disabled_by_policy || all_plugins_disabled_by_policy) { + result->SetString("enabledMode", "disabledByPolicy"); + } else if (group_enabled_by_policy || all_plugins_enabled_by_policy) { + result->SetString("enabledMode", "enabledByPolicy"); + } else { + result->SetString("enabledMode", enabled_ ? + "enabledByUser" : + "disabledByUser"); + } + result->Set("plugin_files", plugin_files); + + return result; +} + /*static*/ bool PluginGroup::IsVersionInRange(const Version& version, const VersionRange& range) { @@ -241,26 +472,34 @@ bool PluginGroup::IsPluginOutdated(const Version& plugin_version, return false; } +bool PluginGroup::IsWhitelisted() const { + for (size_t i = 0; i < web_plugin_infos_.size(); ++i) { + if (web_plugin_infos_[i].enabled & WebPluginInfo::POLICY_ENABLED) + return true; + } + return false; +} + // Returns true if the latest version of this plugin group is vulnerable. -bool PluginGroup::IsVulnerable(const WebPluginInfo& plugin) const { - scoped_ptr<Version> version(CreateVersionFromString(plugin.version)); - if (!version.get()) +bool PluginGroup::IsVulnerable() const { + // A plugin isn't considered vulnerable if it's explicitly whitelisted. + if (IsWhitelisted()) return false; for (size_t i = 0; i < version_ranges_.size(); ++i) { - if (IsPluginOutdated(*version, version_ranges_[i])) + if (IsPluginOutdated(*version_, version_ranges_[i])) return true; } return false; } -bool PluginGroup::RequiresAuthorization(const WebPluginInfo& plugin) const { - scoped_ptr<Version> version(CreateVersionFromString(plugin.version)); - if (!version.get()) +bool PluginGroup::RequiresAuthorization() const { + // A plugin doesn't require authorization if it's explicitly whitelisted. + if (IsWhitelisted()) return false; for (size_t i = 0; i < version_ranges_.size(); ++i) { - if (IsVersionInRange(*version, version_ranges_[i]) && + if (IsVersionInRange(*version_, version_ranges_[i]) && version_ranges_[i].requires_authorization) return true; } @@ -271,5 +510,114 @@ bool PluginGroup::IsEmpty() const { return web_plugin_infos_.empty(); } +bool PluginGroup::EnableGroup(bool enable) { + bool group_disabled_by_policy = IsPluginNameDisabledByPolicy(group_name_); + bool group_enabled_by_policy = IsPluginNameEnabledByPolicy(group_name_); + + // We can't enable nor disable groups controlled by policy. + if ((group_disabled_by_policy && enable) || + (group_enabled_by_policy && !enable)) + return false; + + ResetGroupState(); + for (size_t i = 0; i < web_plugin_infos_.size(); ++i) { + bool policy_enabled = + IsPluginNameEnabledByPolicy(web_plugin_infos_[i].name); + bool policy_disabled = + IsPluginFileNameDisabledByPolicy(web_plugin_infos_[i].name, + group_name_); + if (policy_disabled) { + Disable(&web_plugin_infos_[i], WebPluginInfo::POLICY_DISABLED); + } else if (policy_enabled) { + Enable(&web_plugin_infos_[i], WebPluginInfo::POLICY_ENABLED); + } else if (enable) { + Enable(&web_plugin_infos_[i], WebPluginInfo::USER_ENABLED); + } else { + Disable(&web_plugin_infos_[i], WebPluginInfo::USER_DISABLED); + } + UpdateActivePlugin(web_plugin_infos_[i]); + } + return enabled_ == enable; +} + +void PluginGroup::EnforceGroupPolicy() { + bool group_disabled_by_policy = IsPluginNameDisabledByPolicy(group_name_); + bool group_enabled_by_policy = IsPluginNameEnabledByPolicy(group_name_); + + ResetGroupState(); + for (size_t i = 0; i < web_plugin_infos_.size(); ++i) { + bool policy_enabled = + group_enabled_by_policy || + IsPluginNameEnabledByPolicy(web_plugin_infos_[i].name); + bool policy_disabled = + !policy_enabled && + (group_disabled_by_policy || + IsPluginFileNameDisabledByPolicy(web_plugin_infos_[i].name, + group_name_)); + if (policy_disabled) { + Disable(&web_plugin_infos_[i], WebPluginInfo::POLICY_DISABLED); + } else if (policy_enabled) { + Enable(&web_plugin_infos_[i], WebPluginInfo::POLICY_ENABLED); + } else { + // If not managed, use the user's preference. + if ((web_plugin_infos_[i].enabled & WebPluginInfo::USER_MASK) == + WebPluginInfo::USER_ENABLED) { + Enable(&web_plugin_infos_[i], WebPluginInfo::POLICY_UNMANAGED); + } else { + Disable(&web_plugin_infos_[i], WebPluginInfo::POLICY_UNMANAGED); + } + } + UpdateActivePlugin(web_plugin_infos_[i]); + } +} + +void PluginGroup::ResetGroupState() { + enabled_ = false; + description_.clear(); + version_.reset(Version::GetVersionFromString("0")); +} + +/*static*/ +bool PluginGroup::SetPluginState(WebPluginInfo* plugin, + int new_reason, + bool state_changes) { + // If we are only stripping the policy then mask the policy bits. + if (new_reason == WebPluginInfo::POLICY_UNMANAGED) { + plugin->enabled &= WebPluginInfo::USER_MASK; + return true; + } + if (new_reason & WebPluginInfo::MANAGED_MASK) { + // Policy-enforced change: preserve the user's preference, and override + // a possible previous policy flag. + plugin->enabled = (plugin->enabled & WebPluginInfo::USER_MASK) | new_reason; + } else if (state_changes && (plugin->enabled & WebPluginInfo::MANAGED_MASK)) { + // Refuse change when managed. + return false; + } else { + // Accept the user update, but keep the policy flag if present. + plugin->enabled = (plugin->enabled & WebPluginInfo::MANAGED_MASK) | + new_reason; + } + return true; +} + +/*static*/ +bool PluginGroup::Enable(WebPluginInfo* plugin, int new_reason) { + DCHECK(new_reason == WebPluginInfo::USER_ENABLED || + new_reason == WebPluginInfo::POLICY_ENABLED || + new_reason == WebPluginInfo::USER_ENABLED_POLICY_ENABLED || + new_reason == WebPluginInfo::POLICY_UNMANAGED); + return SetPluginState(plugin, new_reason, !IsPluginEnabled(*plugin)); +} + +/*static*/ +bool PluginGroup::Disable(WebPluginInfo* plugin, int new_reason) { + DCHECK(new_reason == WebPluginInfo::USER_DISABLED || + new_reason == WebPluginInfo::POLICY_DISABLED || + new_reason == WebPluginInfo::USER_DISABLED_POLICY_DISABLED || + new_reason == WebPluginInfo::POLICY_UNMANAGED); + return SetPluginState(plugin, new_reason, IsPluginEnabled(*plugin)); +} + } // namespace npapi } // namespace webkit diff --git a/webkit/plugins/npapi/plugin_group.h b/webkit/plugins/npapi/plugin_group.h index e721b3b..da80db8 100644 --- a/webkit/plugins/npapi/plugin_group.h +++ b/webkit/plugins/npapi/plugin_group.h @@ -6,6 +6,8 @@ #define WEBKIT_PLUGINS_NPAPI_PLUGIN_GROUP_H_ #pragma once +#include <map> +#include <set> #include <string> #include <vector> @@ -95,6 +97,24 @@ class PluginGroup { PluginGroup& operator=(const PluginGroup& other); + // Configures the set of plugin name patterns for enabling and disabling + // plugins via enterprise configuration management. + static void SetPolicyEnforcedPluginPatterns( + const std::set<string16>& plugins_disabled, + const std::set<string16>& plugins_disabled_exceptions, + const std::set<string16>& plugins_enabled); + + // Tests whether |plugin_name| is disabled by policy. + static bool IsPluginNameDisabledByPolicy(const string16& plugin_name); + + // Tests whether |plugin_name| within the plugin group |group_name| is + // disabled by policy. + static bool IsPluginFileNameDisabledByPolicy(const string16& plugin_name, + const string16& group_name); + + // Tests whether |plugin_name| is enabled by policy. + static bool IsPluginNameEnabledByPolicy(const string16& plugin_name); + // Returns true if the given plugin matches this group. bool Match(const webkit::WebPluginInfo& plugin) const; @@ -104,6 +124,24 @@ class PluginGroup { // Removes a plugin from the group by its path. bool RemovePlugin(const FilePath& filename); + // The two following functions enable/disable a plugin given its filename. The + // function returns true if the plugin could be enabled/disabled. Plugins + // might not get enabled/disabled if they are controlled by policy or are + // already in the wanted state. + bool EnablePlugin(const FilePath& filename); + bool DisablePlugin(const FilePath& filename); + + // Enables/disables this group. This enables/disables all plugins in the + // group. + bool EnableGroup(bool enable); + + // Checks whether the group should be disabled/enabled by a policy and puts + // it in the needed state. Updates all contained plugins too. + void EnforceGroupPolicy(); + + // Returns whether the plugin group is enabled or not. + bool Enabled() const { return enabled_; } + // Returns a unique identifier for this group, if one is defined, or the empty // string otherwise. const std::string& identifier() const { return identifier_; } @@ -117,21 +155,36 @@ class PluginGroup { // is empty. string16 GetGroupName() const; + // Returns all plugins added to the group. + const std::vector<webkit::WebPluginInfo>& web_plugins_info() const { + return web_plugin_infos_; + } + // Checks whether a plugin exists in the group with the given path. bool ContainsPlugin(const FilePath& path) const; + // Returns the description of the highest-priority plug-in in the group. + const string16& description() const { return description_; } + + // Returns a DictionaryValue with data to display in the UI. + base::DictionaryValue* GetDataForUI() const; + + // Returns a DictionaryValue with data to save in the preferences. + base::DictionaryValue* GetSummary() const; + // Returns the update URL. std::string GetUpdateURL() const { return update_url_; } // Returns true if this plugin group is whitelisted. bool IsWhitelisted() const; - // Returns true if |plugin| in this group has known security problems. - bool IsVulnerable(const WebPluginInfo& plugin) const; + // Returns true if the highest-priority plugin in this group has known + // security problems. + bool IsVulnerable() const; - // Returns true if |plugin| in this plug-in group always requires user - // authorization to run. - bool RequiresAuthorization(const WebPluginInfo& plugin) const; + // Returns true if this plug-in group always requires user authorization + // to run. + bool RequiresAuthorization() const; // Check if the group has no plugins. Could happen after a reload if the plug- // in has disappeared from the pc (or in the process of updating). @@ -141,7 +194,7 @@ class PluginGroup { // in accepting weird version strings than Version::GetFromString(). static Version* CreateVersionFromString(const string16& version_string); - const std::vector<webkit::WebPluginInfo>& web_plugin_infos() const { + std::vector<webkit::WebPluginInfo> web_plugin_infos() { return web_plugin_infos_; } @@ -184,17 +237,54 @@ class PluginGroup { void InitFrom(const PluginGroup& other); + // Set the description and version for this plugin group from the + // given plug-in. + void UpdateDescriptionAndVersion(const webkit::WebPluginInfo& plugin); + + // Updates the active plugin in the group. The active plugin is the first + // enabled one, or if all plugins are disabled, simply the first one. + void UpdateActivePlugin(const webkit::WebPluginInfo& plugin); + + // Resets the group state to its default value (as if the group was empty). + // After calling this method, calling |UpdateActivePlugin| with all plugins + // in a row will correctly set the group state. + void ResetGroupState(); + + // Enables the plugin if not already enabled and if policy allows it to. + // Returns true on success. Does not update the group state. + static bool Enable(webkit::WebPluginInfo* plugin, int reason); + + // Disables the plugin if not already disabled and if policy allows it to. + // Returns true on success. Does not update the group state. + static bool Disable(webkit::WebPluginInfo* plugin, int reason); + + // Helper function to implement the functions above. + static bool SetPluginState(webkit::WebPluginInfo* plugin, + int new_reason, + bool state_changes); + // Returns a non-const vector of all plugins in the group. This is only used // by PluginList. std::vector<webkit::WebPluginInfo>& GetPluginsContainer() { return web_plugin_infos_; } + // Checks if |name| matches any of the patterns in |pattern_set|. + static bool IsStringMatchedInSet(const string16& name, + const std::set<string16>* pattern_set); + + static std::set<string16>* policy_disabled_plugin_patterns_; + static std::set<string16>* policy_disabled_plugin_exception_patterns_; + static std::set<string16>* policy_enabled_plugin_patterns_; + std::string identifier_; string16 group_name_; string16 name_matcher_; + string16 description_; std::string update_url_; + bool enabled_; std::vector<VersionRange> version_ranges_; + scoped_ptr<Version> version_; std::vector<webkit::WebPluginInfo> web_plugin_infos_; }; diff --git a/webkit/plugins/npapi/plugin_group_unittest.cc b/webkit/plugins/npapi/plugin_group_unittest.cc index a9e1c1c..8f9bf50 100644 --- a/webkit/plugins/npapi/plugin_group_unittest.cc +++ b/webkit/plugins/npapi/plugin_group_unittest.cc @@ -87,6 +87,12 @@ class PluginGroupTest : public testing::Test { static PluginGroup* CreatePluginGroup(const WebPluginInfo& wpi) { return PluginGroup::FromWebPluginInfo(wpi); } + protected: + virtual void TearDown() { + PluginGroup::SetPolicyEnforcedPluginPatterns(std::set<string16>(), + std::set<string16>(), + std::set<string16>()); + } }; TEST_F(PluginGroupTest, PluginGroupMatch) { @@ -96,7 +102,7 @@ TEST_F(PluginGroupTest, PluginGroupMatch) { EXPECT_TRUE(group->Match(kPlugin3045r)); EXPECT_FALSE(group->Match(kPluginNoVersion)); group->AddPlugin(kPlugin3045); - EXPECT_FALSE(group->IsVulnerable(kPlugin3045)); + EXPECT_FALSE(group->IsVulnerable()); group.reset(PluginGroupTest::CreatePluginGroup(kPluginDef)); EXPECT_FALSE(group->Match(kPluginNoVersion)); @@ -120,6 +126,45 @@ TEST_F(PluginGroupTest, PluginGroupMatchCorrectVersion) { EXPECT_TRUE(group->Match(kPlugin4043)); } +TEST_F(PluginGroupTest, PluginGroupDescription) { + string16 desc3043(ASCIIToUTF16("MyPlugin version 3.0.43")); + string16 desc3045(ASCIIToUTF16("MyPlugin version 3.0.45")); + + PluginGroupDefinition plugindefs[] = + { kPluginDef, kPluginDef3, kPluginDef34 }; + for (size_t i = 0; i < arraysize(plugindefs); ++i) { + WebPluginInfo plugin3043(kPlugin3043); + WebPluginInfo plugin3045(kPlugin3045); + { + scoped_ptr<PluginGroup> group(PluginGroupTest::CreatePluginGroup( + plugindefs[i])); + EXPECT_TRUE(group->Match(plugin3043)); + group->AddPlugin(plugin3043); + EXPECT_EQ(desc3043, group->description()); + EXPECT_TRUE(group->IsVulnerable()); + EXPECT_TRUE(group->Match(plugin3045)); + group->AddPlugin(plugin3045); + EXPECT_EQ(desc3043, group->description()); + EXPECT_TRUE(group->IsVulnerable()); + } + { + // Disable the second plugin. + plugin3045.enabled = + webkit::WebPluginInfo::USER_DISABLED_POLICY_UNMANAGED; + scoped_ptr<PluginGroup> group(PluginGroupTest::CreatePluginGroup( + plugindefs[i])); + EXPECT_TRUE(group->Match(plugin3043)); + group->AddPlugin(plugin3043); + EXPECT_EQ(desc3043, group->description()); + EXPECT_TRUE(group->IsVulnerable()); + EXPECT_TRUE(group->Match(plugin3045)); + group->AddPlugin(plugin3045); + EXPECT_EQ(desc3043, group->description()); + EXPECT_TRUE(group->IsVulnerable()); + } + } +} + TEST_F(PluginGroupTest, PluginGroupDefinition) { for (size_t i = 0; i < arraysize(kPluginDefinitions); ++i) { scoped_ptr<PluginGroup> def_group( @@ -143,12 +188,117 @@ TEST_F(PluginGroupTest, VersionExtraction) { }; for (size_t i = 0; i < arraysize(versions); i++) { - scoped_ptr<Version> version(PluginGroup::CreateVersionFromString( - ASCIIToUTF16(versions[i][0]))); - EXPECT_STREQ(versions[i][1], version->GetString().c_str()); + const WebPluginInfo plugin = WebPluginInfo( + ASCIIToUTF16("Blah Plugin"), FilePath(FILE_PATH_LITERAL("blahfile")), + ASCIIToUTF16(versions[i][0]), string16()); + scoped_ptr<PluginGroup> group(PluginGroupTest::CreatePluginGroup(plugin)); + EXPECT_TRUE(group->Match(plugin)); + group->AddPlugin(plugin); + scoped_ptr<DictionaryValue> data(group->GetDataForUI()); + std::string version; + data->GetString("version", &version); + EXPECT_EQ(versions[i][1], version); } } +TEST_F(PluginGroupTest, DisabledByPolicy) { + std::set<string16> disabled_plugins; + disabled_plugins.insert(ASCIIToUTF16("Disable this!")); + disabled_plugins.insert(ASCIIToUTF16("*Google*")); + PluginGroup::SetPolicyEnforcedPluginPatterns(disabled_plugins, + std::set<string16>(), + std::set<string16>()); + + EXPECT_FALSE(PluginGroup::IsPluginNameDisabledByPolicy(ASCIIToUTF16("42"))); + EXPECT_TRUE(PluginGroup::IsPluginNameDisabledByPolicy( + ASCIIToUTF16("Disable this!"))); + EXPECT_TRUE(PluginGroup::IsPluginNameDisabledByPolicy( + ASCIIToUTF16("Google Earth"))); +} + +TEST_F(PluginGroupTest, EnabledByPolicy) { + std::set<string16> enabled_plugins; + enabled_plugins.insert(ASCIIToUTF16("Enable that!")); + enabled_plugins.insert(ASCIIToUTF16("PDF*")); + PluginGroup::SetPolicyEnforcedPluginPatterns(std::set<string16>(), + std::set<string16>(), + enabled_plugins); + + EXPECT_FALSE(PluginGroup::IsPluginNameEnabledByPolicy(ASCIIToUTF16("42"))); + EXPECT_TRUE(PluginGroup::IsPluginNameEnabledByPolicy( + ASCIIToUTF16("Enable that!"))); + EXPECT_TRUE(PluginGroup::IsPluginNameEnabledByPolicy( + ASCIIToUTF16("PDF Reader"))); +} + +TEST_F(PluginGroupTest, EnabledAndDisabledByPolicy) { + const string16 k42(ASCIIToUTF16("42")); + const string16 kEnabled(ASCIIToUTF16("Enabled")); + const string16 kEnabled2(ASCIIToUTF16("Enabled 2")); + const string16 kEnabled3(ASCIIToUTF16("Enabled 3")); + const string16 kException(ASCIIToUTF16("Exception")); + const string16 kException2(ASCIIToUTF16("Exception 2")); + const string16 kGoogleMars(ASCIIToUTF16("Google Mars")); + const string16 kGoogleEarth(ASCIIToUTF16("Google Earth")); + + std::set<string16> disabled_plugins; + std::set<string16> disabled_plugins_exceptions; + std::set<string16> enabled_plugins; + + disabled_plugins.insert(kEnabled); + disabled_plugins_exceptions.insert(kEnabled); + enabled_plugins.insert(kEnabled); + + disabled_plugins_exceptions.insert(kException); + + disabled_plugins.insert(kEnabled2); + enabled_plugins.insert(kEnabled2); + + disabled_plugins.insert(kException2); + disabled_plugins_exceptions.insert(kException2); + + disabled_plugins_exceptions.insert(kEnabled3); + enabled_plugins.insert(kEnabled3); + + PluginGroup::SetPolicyEnforcedPluginPatterns(disabled_plugins, + disabled_plugins_exceptions, + enabled_plugins); + + EXPECT_FALSE(PluginGroup::IsPluginNameEnabledByPolicy(k42)); + EXPECT_FALSE(PluginGroup::IsPluginNameDisabledByPolicy(k42)); + + EXPECT_TRUE(PluginGroup::IsPluginNameEnabledByPolicy(kEnabled)); + EXPECT_FALSE(PluginGroup::IsPluginNameDisabledByPolicy(kEnabled)); + EXPECT_TRUE(PluginGroup::IsPluginNameEnabledByPolicy(kEnabled2)); + EXPECT_FALSE(PluginGroup::IsPluginNameDisabledByPolicy(kEnabled2)); + EXPECT_TRUE(PluginGroup::IsPluginNameEnabledByPolicy(kEnabled3)); + EXPECT_FALSE(PluginGroup::IsPluginNameDisabledByPolicy(kEnabled3)); + + EXPECT_FALSE(PluginGroup::IsPluginNameEnabledByPolicy(kException)); + EXPECT_FALSE(PluginGroup::IsPluginNameDisabledByPolicy(kException)); + EXPECT_FALSE(PluginGroup::IsPluginNameEnabledByPolicy(kException2)); + EXPECT_FALSE(PluginGroup::IsPluginNameDisabledByPolicy(kException2)); + + disabled_plugins.clear(); + disabled_plugins_exceptions.clear(); + enabled_plugins.clear(); + + disabled_plugins.insert(ASCIIToUTF16("*")); + disabled_plugins_exceptions.insert(ASCIIToUTF16("*Google*")); + enabled_plugins.insert(kGoogleEarth); + + PluginGroup::SetPolicyEnforcedPluginPatterns(disabled_plugins, + disabled_plugins_exceptions, + enabled_plugins); + + EXPECT_TRUE(PluginGroup::IsPluginNameEnabledByPolicy(kGoogleEarth)); + EXPECT_FALSE(PluginGroup::IsPluginNameDisabledByPolicy(kGoogleEarth)); + EXPECT_FALSE(PluginGroup::IsPluginNameEnabledByPolicy(kGoogleMars)); + EXPECT_FALSE(PluginGroup::IsPluginNameDisabledByPolicy(kGoogleMars)); + EXPECT_FALSE(PluginGroup::IsPluginNameEnabledByPolicy(k42)); + EXPECT_TRUE(PluginGroup::IsPluginNameDisabledByPolicy(k42)); +} + TEST_F(PluginGroupTest, IsVulnerable) { // Adobe Reader 10 VersionRangeDefinition adobe_reader_version_range[] = { @@ -168,8 +318,8 @@ TEST_F(PluginGroupTest, IsVulnerable) { adobe_reader_plugin_def)); group->AddPlugin(adobe_reader_plugin); PluginGroup group_copy(*group); // Exercise the copy constructor. - EXPECT_FALSE(group_copy.IsVulnerable(adobe_reader_plugin)); - EXPECT_FALSE(group_copy.RequiresAuthorization(adobe_reader_plugin)); + EXPECT_FALSE(group_copy.IsVulnerable()); + EXPECT_FALSE(group_copy.RequiresAuthorization()); // Silverlight 4 VersionRangeDefinition silverlight_version_range[] = { @@ -186,8 +336,62 @@ TEST_F(PluginGroupTest, IsVulnerable) { ASCIIToUTF16("silverlight 4")); group.reset(PluginGroupTest::CreatePluginGroup(silverlight_plugin_def)); group->AddPlugin(silverlight_plugin); - EXPECT_FALSE(PluginGroup(*group).IsVulnerable(silverlight_plugin)); - EXPECT_TRUE(PluginGroup(*group).RequiresAuthorization(silverlight_plugin)); + EXPECT_FALSE(PluginGroup(*group).IsVulnerable()); + EXPECT_TRUE(PluginGroup(*group).RequiresAuthorization()); +} + +TEST_F(PluginGroupTest, WhitelistedIsNotVulnerable) { + VersionRangeDefinition version_range[] = { + { "0", "6", "5.0", true } + }; + PluginGroupDefinition plugin_def = { + "nativehtml5", "NativeHTML5", "NativeHTML5", version_range, + arraysize(version_range), + "http://bugzilla.mozilla.org/show_bug.cgi?id=649408" }; + WebPluginInfo plugin(ASCIIToUTF16("NativeHTML5"), + FilePath(FILE_PATH_LITERAL("/native.so")), + ASCIIToUTF16("4.0"), + ASCIIToUTF16("NativeHTML5")); + scoped_ptr<PluginGroup> group(PluginGroupTest::CreatePluginGroup(plugin_def)); + group->AddPlugin(plugin); + + EXPECT_TRUE(group->IsVulnerable()); + EXPECT_TRUE(group->RequiresAuthorization()); + + std::set<string16> enabled_plugins; + enabled_plugins.insert(ASCIIToUTF16("NativeHTML5")); + PluginGroup::SetPolicyEnforcedPluginPatterns(std::set<string16>(), + std::set<string16>(), + enabled_plugins); + group->EnforceGroupPolicy(); + + EXPECT_FALSE(group->IsVulnerable()); + EXPECT_FALSE(group->RequiresAuthorization()); +} + +TEST_F(PluginGroupTest, MultipleVersions) { + scoped_ptr<PluginGroup> group( + PluginGroupTest::CreatePluginGroup(kPluginDef3)); + group->AddPlugin(kPlugin3044); + group->AddPlugin(kPlugin3043); + EXPECT_EQ(kPlugin3044.desc, group->description()); + EXPECT_FALSE(group->IsVulnerable()); + + group->DisablePlugin(kPlugin3044.path); + EXPECT_EQ(kPlugin3043.desc, group->description()); + EXPECT_TRUE(group->IsVulnerable()); + + EXPECT_TRUE(group->EnableGroup(false)); + EXPECT_EQ(kPlugin3044.desc, group->description()); + EXPECT_FALSE(group->IsVulnerable()); + + EXPECT_TRUE(group->RemovePlugin(kPlugin3044.path)); + EXPECT_EQ(kPlugin3043.desc, group->description()); + EXPECT_TRUE(group->IsVulnerable()); + + EXPECT_TRUE(group->RemovePlugin(kPlugin3043.path)); + EXPECT_TRUE(group->IsEmpty()); + EXPECT_EQ(string16(), group->description()); } } // namespace npapi diff --git a/webkit/plugins/npapi/plugin_lib_mac.mm b/webkit/plugins/npapi/plugin_lib_mac.mm index 542b43d..fe11197 100644 --- a/webkit/plugins/npapi/plugin_lib_mac.mm +++ b/webkit/plugins/npapi/plugin_lib_mac.mm @@ -125,6 +125,7 @@ bool ReadPlistPluginInfo(const FilePath& filename, CFBundleRef bundle, info->desc = base::SysNSStringToUTF16(plugin_desc); else info->desc = UTF8ToUTF16(filename.BaseName().value()); + info->enabled = WebPluginInfo::USER_ENABLED; return true; } diff --git a/webkit/plugins/npapi/plugin_lib_posix.cc b/webkit/plugins/npapi/plugin_lib_posix.cc index 64afcd2..641b6cd 100644 --- a/webkit/plugins/npapi/plugin_lib_posix.cc +++ b/webkit/plugins/npapi/plugin_lib_posix.cc @@ -162,6 +162,7 @@ bool PluginLib::ReadWebPluginInfo(const FilePath& filename, } info->path = filename; + info->enabled = WebPluginInfo::USER_ENABLED; // Attempt to swap in the wrapped plugin if this is nspluginwrapper. UnwrapNSPluginWrapper(&dl, &info->path); diff --git a/webkit/plugins/npapi/plugin_lib_win.cc b/webkit/plugins/npapi/plugin_lib_win.cc index 224e1c3..ccdb4b6 100644 --- a/webkit/plugins/npapi/plugin_lib_win.cc +++ b/webkit/plugins/npapi/plugin_lib_win.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -38,6 +38,7 @@ bool PluginLib::ReadWebPluginInfo(const FilePath &filename, info->desc = version_info->file_description(); info->version = version_info->file_version(); info->path = filename; + info->enabled = WebPluginInfo::USER_ENABLED_POLICY_UNMANAGED; // TODO(evan): Move the ParseMimeTypes code inline once Pepper is updated. if (!PluginList::ParseMimeTypes( diff --git a/webkit/plugins/npapi/plugin_list.cc b/webkit/plugins/npapi/plugin_list.cc index a7f6dd4..45160fc 100644 --- a/webkit/plugins/npapi/plugin_list.cc +++ b/webkit/plugins/npapi/plugin_list.cc @@ -230,6 +230,7 @@ void PluginList::RegisterInternalPlugin(const FilePath& filename, plugin.info.name = ASCIIToUTF16(name); plugin.info.version = ASCIIToUTF16("1"); plugin.info.desc = ASCIIToUTF16(description); + plugin.info.enabled = webkit::WebPluginInfo::USER_ENABLED_POLICY_UNMANAGED; webkit::WebPluginMimeType mime_type; mime_type.mime_type = mime_type_str; @@ -407,6 +408,51 @@ void PluginList::LoadPlugins() { LoadPluginsInternal(&new_plugin_groups); base::AutoLock lock(lock_); + // Grab all plugins that were found before to copy enabled statuses. + std::vector<webkit::WebPluginInfo> old_plugins; + for (size_t i = 0; i < plugin_groups_.size(); ++i) { + const std::vector<webkit::WebPluginInfo>& gr_plugins = + plugin_groups_[i]->web_plugins_info(); + old_plugins.insert(old_plugins.end(), gr_plugins.begin(), gr_plugins.end()); + } + // Disable all of the plugins and plugin groups that are disabled by policy. + for (size_t i = 0; i < new_plugin_groups.size(); ++i) { + PluginGroup* group = new_plugin_groups[i]; + string16 group_name = group->GetGroupName(); + + std::vector<webkit::WebPluginInfo>& gr_plugins = + group->GetPluginsContainer(); + for (size_t j = 0; j < gr_plugins.size(); ++j) { + int plugin_found = -1; + for (size_t k = 0; k < old_plugins.size(); ++k) { + if (gr_plugins[j].path == old_plugins[k].path) { + plugin_found = k; + break; + } + } + if (plugin_found >= 0) + gr_plugins[j].enabled = old_plugins[plugin_found].enabled; + // Set the disabled flag of all plugins scheduled for disabling. + if (plugins_to_disable_.find(gr_plugins[j].path) != + plugins_to_disable_.end()) { + group->DisablePlugin(gr_plugins[j].path); + } + } + + if (group->IsEmpty()) { + new_plugin_groups.erase(new_plugin_groups.begin() + i); + --i; + continue; + } + + group->EnforceGroupPolicy(); + } + // We flush the list of prematurely disabled plugins after the load has + // finished. If for some reason a plugin reappears on a second load it is + // going to be loaded normally. This is only true for non-policy controlled + // plugins though. + plugins_to_disable_.clear(); + plugin_groups_.swap(new_plugin_groups); } @@ -447,7 +493,7 @@ void PluginList::GetPlugins(std::vector<WebPluginInfo>* plugins) { base::AutoLock lock(lock_); for (size_t i = 0; i < plugin_groups_.size(); ++i) { const std::vector<webkit::WebPluginInfo>& gr_plugins = - plugin_groups_[i]->web_plugin_infos(); + plugin_groups_[i]->web_plugins_info(); plugins->insert(plugins->end(), gr_plugins.begin(), gr_plugins.end()); } } @@ -476,7 +522,7 @@ void PluginList::GetPluginInfoArray( // Add in plugins by mime type. for (size_t i = 0; i < plugin_groups_.size(); ++i) { const std::vector<webkit::WebPluginInfo>& plugins = - plugin_groups_[i]->web_plugin_infos(); + plugin_groups_[i]->web_plugins_info(); for (size_t i = 0; i < plugins.size(); ++i) { if (SupportsType(plugins[i], mime_type, allow_wildcard)) { FilePath path = plugins[i].path; @@ -498,7 +544,7 @@ void PluginList::GetPluginInfoArray( std::string actual_mime_type; for (size_t i = 0; i < plugin_groups_.size(); ++i) { const std::vector<webkit::WebPluginInfo>& plugins = - plugin_groups_[i]->web_plugin_infos(); + plugin_groups_[i]->web_plugins_info(); for (size_t i = 0; i < plugins.size(); ++i) { if (SupportsExtension(plugins[i], extension, &actual_mime_type)) { FilePath path = plugins[i].path; @@ -523,9 +569,9 @@ void PluginList::GetPluginInfoArray( if (plugin_groups_[i]->identifier().compare( kDefaultPluginLibraryName) == 0) { #endif - DCHECK_NE(0U, plugin_groups_[i]->web_plugin_infos().size()); + DCHECK_NE(0U, plugin_groups_[i]->web_plugins_info().size()); const webkit::WebPluginInfo& default_info = - plugin_groups_[i]->web_plugin_infos()[0]; + plugin_groups_[i]->web_plugins_info()[0]; if (SupportsType(default_info, mime_type, allow_wildcard)) { info->push_back(default_info); if (actual_mime_types) @@ -541,7 +587,7 @@ bool PluginList::GetPluginInfoByPath(const FilePath& plugin_path, base::AutoLock lock(lock_); for (size_t i = 0; i < plugin_groups_.size(); ++i) { const std::vector<webkit::WebPluginInfo>& plugins = - plugin_groups_[i]->web_plugin_infos(); + plugin_groups_[i]->web_plugins_info(); for (size_t i = 0; i < plugins.size(); ++i) { if (plugins[i].path == plugin_path) { *info = plugins[i]; @@ -568,10 +614,10 @@ void PluginList::GetPluginGroups( } } -PluginGroup* PluginList::GetPluginGroup( +const PluginGroup* PluginList::GetPluginGroup( const webkit::WebPluginInfo& web_plugin_info) { base::AutoLock lock(lock_); - return new PluginGroup(*AddToPluginGroups(web_plugin_info, &plugin_groups_)); + return AddToPluginGroups(web_plugin_info, &plugin_groups_); } string16 PluginList::GetPluginGroupName(const std::string& identifier) { @@ -624,9 +670,60 @@ PluginGroup* PluginList::AddToPluginGroups( plugin_groups->push_back(group); } group->AddPlugin(web_plugin_info); + // If group is scheduled for disabling do that now and remove it from the + // list. + if (groups_to_disable_.erase(group->GetGroupName())) + group->EnableGroup(false); return group; } +bool PluginList::EnablePlugin(const FilePath& filename) { + base::AutoLock lock(lock_); + for (size_t i = 0; i < plugin_groups_.size(); ++i) { + if (plugin_groups_[i]->ContainsPlugin(filename)) + return plugin_groups_[i]->EnablePlugin(filename); + } + // Non existing plugin is being enabled. Check if it has been disabled before + // and remove it. + return (plugins_to_disable_.erase(filename) != 0); +} + +bool PluginList::DisablePlugin(const FilePath& filename) { + base::AutoLock lock(lock_); + for (size_t i = 0; i < plugin_groups_.size(); ++i) { + if (plugin_groups_[i]->ContainsPlugin(filename)) + return plugin_groups_[i]->DisablePlugin(filename); + } + // Non existing plugin is being disabled. Queue the plugin so that on the next + // load plugins call they will be disabled. + plugins_to_disable_.insert(filename); + return true; +} + +bool PluginList::EnableGroup(bool enable, const string16& group_name) { + base::AutoLock lock(lock_); + PluginGroup* group = NULL; + for (size_t i = 0; i < plugin_groups_.size(); ++i) { + if (!plugin_groups_[i]->IsEmpty() && + plugin_groups_[i]->GetGroupName().find(group_name) != string16::npos) { + group = plugin_groups_[i]; + break; + } + } + if (!group) { + // Non existing group is being enabled. Queue the group so that on the next + // load plugins call they will be disabled. + if (!enable) { + groups_to_disable_.insert(group_name); + return true; + } else { + return (groups_to_disable_.erase(group_name) != 0); + } + } + + return group->EnableGroup(enable); +} + bool PluginList::SupportsType(const webkit::WebPluginInfo& plugin, const std::string& mime_type, bool allow_wildcard) { diff --git a/webkit/plugins/npapi/plugin_list.h b/webkit/plugins/npapi/plugin_list.h index 640ccbd..4f17bdb 100644 --- a/webkit/plugins/npapi/plugin_list.h +++ b/webkit/plugins/npapi/plugin_list.h @@ -150,10 +150,16 @@ class PluginList { void GetPluginGroups(bool load_if_necessary, std::vector<PluginGroup>* plugin_groups); - // Returns a copy of the PluginGroup corresponding to the given WebPluginInfo. - // If no such group exists, it is created and added to the cache. - // The caller takes ownership of the returned PluginGroup. - PluginGroup* GetPluginGroup(const webkit::WebPluginInfo& web_plugin_info); + // Returns the PluginGroup corresponding to the given WebPluginInfo. If no + // such group exists, it is created and added to the cache. + // Beware: when calling this from the Browser process, the group that the + // returned pointer points to might disappear suddenly. This happens when + // |RefreshPlugins()| is called and then |LoadPlugins()| is triggered by a + // call to |GetPlugins()|, |GetEnabledPlugins()|, |GetPluginInfoArray()|, + // |GetPluginInfoByPath()|, or |GetPluginGroups(true, _)|. It is the caller's + // responsibility to make sure this doesn't happen. + const PluginGroup* GetPluginGroup( + const webkit::WebPluginInfo& web_plugin_info); // Returns the name of the PluginGroup with the given identifier. // If no such group exists, an empty string is returned. @@ -169,6 +175,24 @@ class PluginList { void LoadPlugin(const FilePath& filename, ScopedVector<PluginGroup>* plugin_groups); + // Enable a specific plugin, specified by path. Returns |true| iff a plugin + // currently in the plugin list was actually enabled as a result; regardless + // of return value, if a plugin is found in the future with the given name, it + // will be enabled. + bool EnablePlugin(const FilePath& filename); + + // Disable a specific plugin, specified by path. Returns |true| iff a plugin + // currently in the plugin list was actually disabled as a result; regardless + // of return value, if a plugin is found in the future with the given name, it + // will be disabled. + bool DisablePlugin(const FilePath& filename); + + // Enable/disable a plugin group, specified by group_name. Returns |true| iff + // a plugin currently in the plugin list was actually enabled/disabled as a + // result; regardless of return value, if a plugin is found in the future with + // the given name, it will be enabled/disabled. + bool EnableGroup(bool enable, const string16& name); + virtual ~PluginList(); protected: @@ -216,6 +240,12 @@ class PluginList { bool ShouldLoadPlugin(const webkit::WebPluginInfo& info, ScopedVector<PluginGroup>* plugins); + // Return whether a plug-in group with the given name should be disabled, + // either because it already is on the list of disabled groups, or because it + // is blacklisted by a policy. In the latter case, add the plugin group to the + // list of disabled groups as well. + bool ShouldDisableGroup(const string16& group_name); + // Returns true if the plugin supports |mime_type|. |mime_type| should be all // lower case. bool SupportsType(const webkit::WebPluginInfo& plugin, @@ -278,6 +308,18 @@ class PluginList { // Holds the currently available plugin groups. ScopedVector<PluginGroup> plugin_groups_; + // The set of plugins that have been scheduled for disabling once they get + // loaded. This list is used in LoadPlugins and pruned after it. Contains + // plugins that were either disabled by the user (prefs are loaded before + // plugins) or disabled by a policy. + std::set<FilePath> plugins_to_disable_; + // Equivalent to the |plugins_to_disable_| this is the set of groups + // scheduled for disabling once they appear. This list is never completely + // pruned but all groups that do get created are removed from it. New groups + // might get added if they should be pruned because of plugins getting removed + // for example. + std::set<string16> groups_to_disable_; + // Need synchronization for the above members since this object can be // accessed on multiple threads. base::Lock lock_; diff --git a/webkit/plugins/npapi/plugin_list_mac.mm b/webkit/plugins/npapi/plugin_list_mac.mm index 361691a..b142b2c 100644 --- a/webkit/plugins/npapi/plugin_list_mac.mm +++ b/webkit/plugins/npapi/plugin_list_mac.mm @@ -107,7 +107,7 @@ bool PluginList::ShouldLoadPlugin(const WebPluginInfo& info, // encounter earlier must override plugins we encounter later) for (size_t i = 0; i < plugin_groups->size(); ++i) { const std::vector<WebPluginInfo>& plugins = - (*plugin_groups)[i]->web_plugin_infos(); + (*plugin_groups)[i]->web_plugins_info(); for (size_t j = 0; j < plugins.size(); ++j) { if (plugins[j].path.BaseName() == info.path.BaseName()) { return false; // Already have a loaded plugin higher in the hierarchy. diff --git a/webkit/plugins/npapi/plugin_list_posix.cc b/webkit/plugins/npapi/plugin_list_posix.cc index 246f859..9d35898 100644 --- a/webkit/plugins/npapi/plugin_list_posix.cc +++ b/webkit/plugins/npapi/plugin_list_posix.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -248,7 +248,7 @@ bool PluginList::ShouldLoadPlugin(const WebPluginInfo& info, // See if we have a better version of this plugin. for (size_t i = 0; i < plugin_groups->size(); ++i) { const std::vector<WebPluginInfo>& plugins = - (*plugin_groups)[i]->web_plugin_infos(); + (*plugin_groups)[i]->web_plugins_info(); for (size_t j = 0; j < plugins.size(); ++j) { if (plugins[j].name == info.name && !IsUndesirablePlugin(plugins[j])) { diff --git a/webkit/plugins/npapi/plugin_list_unittest.cc b/webkit/plugins/npapi/plugin_list_unittest.cc index 40a0c12..a86f699a 100644 --- a/webkit/plugins/npapi/plugin_list_unittest.cc +++ b/webkit/plugins/npapi/plugin_list_unittest.cc @@ -13,18 +13,21 @@ namespace npapi { namespace { -bool Equals(const WebPluginInfo& a, const WebPluginInfo& b) { +bool Equals(const WebPluginInfo& a, const WebPluginInfo& b, + bool care_about_enabled_status) { return (a.name == b.name && a.path == b.path && a.version == b.version && - a.desc == b.desc); + a.desc == b.desc && + (!care_about_enabled_status || a.enabled == b.enabled)); } bool Contains(const std::vector<WebPluginInfo>& list, - const WebPluginInfo& plugin) { + const WebPluginInfo& plugin, + bool care_about_enabled_status) { for (std::vector<WebPluginInfo>::const_iterator it = list.begin(); it != list.end(); ++it) { - if (Equals(*it, plugin)) + if (Equals(*it, plugin, care_about_enabled_status)) return true; } return false; @@ -57,6 +60,8 @@ class PluginListTest : public testing::Test { } virtual void SetUp() { + bar_plugin_.enabled = WebPluginInfo::USER_DISABLED_POLICY_UNMANAGED; + plugin_list_.DisablePlugin(bar_plugin_.path); plugin_list_.AddPluginToLoad(foo_plugin_); plugin_list_.AddPluginToLoad(bar_plugin_); } @@ -71,20 +76,26 @@ TEST_F(PluginListTest, GetPlugins) { std::vector<WebPluginInfo> plugins; plugin_list_.GetPlugins(&plugins); EXPECT_EQ(2u, plugins.size()); - EXPECT_TRUE(Contains(plugins, foo_plugin_)); - EXPECT_TRUE(Contains(plugins, bar_plugin_)); + EXPECT_TRUE(Contains(plugins, foo_plugin_, true)); + EXPECT_TRUE(Contains(plugins, bar_plugin_, true)); } TEST_F(PluginListTest, GetPluginGroup) { const PluginGroup* foo_group = plugin_list_.GetPluginGroup(foo_plugin_); EXPECT_EQ(ASCIIToUTF16(kFooGroupName), foo_group->GetGroupName()); + EXPECT_TRUE(foo_group->Enabled()); + // The second request should return a pointer to the same instance. + const PluginGroup* foo_group2 = plugin_list_.GetPluginGroup(foo_plugin_); + EXPECT_EQ(foo_group, foo_group2); + const PluginGroup* bar_group = plugin_list_.GetPluginGroup(bar_plugin_); + EXPECT_FALSE(bar_group->Enabled()); } TEST_F(PluginListTest, EmptyGroup) { std::vector<PluginGroup> groups; plugin_list_.GetPluginGroups(false, &groups); for (size_t i = 0; i < groups.size(); ++i) - EXPECT_GE(1U, groups[i].web_plugin_infos().size()); + EXPECT_GE(1U, groups[i].web_plugins_info().size()); } TEST_F(PluginListTest, BadPluginDescription) { @@ -99,20 +110,61 @@ TEST_F(PluginListTest, BadPluginDescription) { plugin_list_.RefreshPlugins(); std::vector<WebPluginInfo> plugins; plugin_list_.GetPlugins(&plugins); - ASSERT_TRUE(Contains(plugins, plugin_3043)); + ASSERT_TRUE(Contains(plugins, plugin_3043, true)); +} + +TEST_F(PluginListTest, DisableAndEnableBeforeLoad) { + WebPluginInfo plugin_3043(ASCIIToUTF16("MyPlugin"), + FilePath(FILE_PATH_LITERAL("/myplugin.3.0.43")), + ASCIIToUTF16("3.0.43"), + ASCIIToUTF16("MyPlugin version 3.0.43")); + WebPluginInfo plugin_3045(ASCIIToUTF16("MyPlugin"), + FilePath(FILE_PATH_LITERAL("/myplugin.3.0.45")), + ASCIIToUTF16("3.0.45"), + ASCIIToUTF16("MyPlugin version 3.0.45")); + // Disable the first one and disable and then enable the second one. + EXPECT_TRUE(plugin_list_.DisablePlugin(plugin_3043.path)); + EXPECT_TRUE(plugin_list_.DisablePlugin(plugin_3045.path)); + EXPECT_TRUE(plugin_list_.EnablePlugin(plugin_3045.path)); + // Simulate loading of the plugins. + plugin_list_.ClearPluginsToLoad(); + plugin_list_.AddPluginToLoad(plugin_3043); + plugin_list_.AddPluginToLoad(plugin_3045); + // Now we should have them in the state we specified above. + plugin_list_.RefreshPlugins(); + std::vector<WebPluginInfo> plugins; + plugin_list_.GetPlugins(&plugins); + plugin_3043.enabled = WebPluginInfo::USER_DISABLED_POLICY_UNMANAGED; + ASSERT_TRUE(Contains(plugins, plugin_3043, true)); + ASSERT_TRUE(Contains(plugins, plugin_3045, true)); } TEST_F(PluginListTest, HardcodedGroups) { std::vector<PluginGroup> groups; plugin_list_.GetPluginGroups(true, &groups); ASSERT_EQ(2u, groups.size()); - EXPECT_EQ(1u, groups[0].web_plugin_infos().size()); + EXPECT_TRUE(groups[0].Enabled()); + EXPECT_EQ(1u, groups[0].web_plugins_info().size()); EXPECT_TRUE(groups[0].ContainsPlugin(FilePath(kFooPath))); EXPECT_EQ(kFooIdentifier, groups[0].identifier()); - EXPECT_EQ(1u, groups[1].web_plugin_infos().size()); + EXPECT_FALSE(groups[1].Enabled()); + EXPECT_EQ(1u, groups[1].web_plugins_info().size()); EXPECT_TRUE(groups[1].ContainsPlugin(FilePath(kBarPath))); EXPECT_EQ("bar.plugin", groups[1].identifier()); } +TEST_F(PluginListTest, DisableBeforeLoad) { + // Test that a plugin group that was disabled before plugins are loaded stays + // disabled afterwards. + + EXPECT_TRUE(plugin_list_.EnableGroup(false, ASCIIToUTF16(kFooGroupName))); + + plugin_list_.RefreshPlugins(); + std::vector<WebPluginInfo> plugins; + plugin_list_.GetPlugins(&plugins); + ASSERT_EQ(2u, plugins.size()); + ASSERT_EQ(WebPluginInfo::USER_DISABLED_POLICY_UNMANAGED, plugins[0].enabled); +} + } // namespace npapi } // namespace webkit diff --git a/webkit/plugins/npapi/plugin_list_win.cc b/webkit/plugins/npapi/plugin_list_win.cc index 0f832e9..b739771 100644 --- a/webkit/plugins/npapi/plugin_list_win.cc +++ b/webkit/plugins/npapi/plugin_list_win.cc @@ -358,7 +358,7 @@ bool PluginList::ShouldLoadPlugin(const webkit::WebPluginInfo& info, for (size_t i = 0; i < plugin_groups->size(); ++i) { const std::vector<webkit::WebPluginInfo>& plugins = - (*plugin_groups)[i]->web_plugin_infos(); + (*plugin_groups)[i]->web_plugins_info(); for (size_t j = 0; j < plugins.size(); ++j) { std::wstring plugin1 = StringToLowerASCII(plugins[j].path.BaseName().value()); @@ -420,7 +420,7 @@ bool PluginList::ShouldLoadPlugin(const webkit::WebPluginInfo& info, for (size_t i = 0; i < plugin_groups->size(); ++i) { const std::vector<webkit::WebPluginInfo>& plugins = - (*plugin_groups)[i]->web_plugin_infos(); + (*plugin_groups)[i]->web_plugins_info(); for (size_t j = 0; j < plugins.size(); ++j) { if (plugins[j].path.BaseName().value() == kOldWMPPlugin) { (*plugin_groups)[i]->RemovePlugin(plugins[j].path); @@ -431,7 +431,7 @@ bool PluginList::ShouldLoadPlugin(const webkit::WebPluginInfo& info, } else if (filename == kOldWMPPlugin) { for (size_t i = 0; i < plugin_groups->size(); ++i) { const std::vector<webkit::WebPluginInfo>& plugins = - (*plugin_groups)[i]->web_plugin_infos(); + (*plugin_groups)[i]->web_plugins_info(); for (size_t j = 0; j < plugins.size(); ++j) { if (plugins[j].path.BaseName().value() == kNewWMPPlugin) return false; diff --git a/webkit/plugins/webplugininfo.cc b/webkit/plugins/webplugininfo.cc index 031dd40..0bdc255 100644 --- a/webkit/plugins/webplugininfo.cc +++ b/webkit/plugins/webplugininfo.cc @@ -22,7 +22,8 @@ WebPluginMimeType::WebPluginMimeType(const std::string& m, WebPluginMimeType::~WebPluginMimeType() {} -WebPluginInfo::WebPluginInfo() : type(PLUGIN_TYPE_NPAPI) { +WebPluginInfo::WebPluginInfo() + : enabled(USER_DISABLED_POLICY_UNMANAGED), type(PLUGIN_TYPE_NPAPI) { } WebPluginInfo::WebPluginInfo(const WebPluginInfo& rhs) @@ -31,6 +32,7 @@ WebPluginInfo::WebPluginInfo(const WebPluginInfo& rhs) version(rhs.version), desc(rhs.desc), mime_types(rhs.mime_types), + enabled(rhs.enabled), type(rhs.type) { } @@ -42,6 +44,7 @@ WebPluginInfo& WebPluginInfo::operator=(const WebPluginInfo& rhs) { version = rhs.version; desc = rhs.desc; mime_types = rhs.mime_types; + enabled = rhs.enabled; type = rhs.type; return *this; } @@ -55,9 +58,15 @@ WebPluginInfo::WebPluginInfo(const string16& fake_name, version(fake_version), desc(fake_desc), mime_types(), + enabled(USER_ENABLED_POLICY_UNMANAGED), type(PLUGIN_TYPE_NPAPI) { } +bool IsPluginEnabled(const WebPluginInfo& plugin) { + return ((plugin.enabled & WebPluginInfo::POLICY_ENABLED) || + plugin.enabled == WebPluginInfo::USER_ENABLED_POLICY_UNMANAGED); +} + bool IsPepperPlugin(const WebPluginInfo& plugin) { return ((plugin.type == WebPluginInfo::PLUGIN_TYPE_PEPPER_IN_PROCESS ) || plugin.type == WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS); diff --git a/webkit/plugins/webplugininfo.h b/webkit/plugins/webplugininfo.h index b7bb4d3..d39c4cd 100644 --- a/webkit/plugins/webplugininfo.h +++ b/webkit/plugins/webplugininfo.h @@ -38,6 +38,32 @@ struct WebPluginMimeType { // Describes an available NPAPI or Pepper plugin. struct WebPluginInfo { + // Defines the possible enabled state a plugin can have. + // The enum values actually represent a 3-bit bitfield : + // |PE|PD|U| - where |PE|PD| is policy state and U is user state. + // PE == 1 means the plugin is forced to enabled state by policy + // PD == 1 means the plugin is forced to disabled by policy + // PE and PD CAN'T be both 1 but can be both 0 which mean no policy is set. + // U == 1 means the user has disabled the plugin. + // Because the plugin user state might have been changed before a policy was + // introduced the user state might contradict the policy state in which case + // the policy has precedence. + enum EnabledStates { + USER_ENABLED = 0, + USER_DISABLED = 1 << 0, + POLICY_DISABLED = 1 << 1, + POLICY_ENABLED = 1 << 2, + USER_ENABLED_POLICY_UNMANAGED = USER_ENABLED, + USER_ENABLED_POLICY_DISABLED = USER_ENABLED| POLICY_DISABLED, + USER_ENABLED_POLICY_ENABLED = USER_ENABLED | POLICY_ENABLED, + USER_DISABLED_POLICY_UNMANAGED = USER_DISABLED, + USER_DISABLED_POLICY_DISABLED = USER_DISABLED | POLICY_DISABLED, + USER_DISABLED_POLICY_ENABLED = USER_DISABLED | POLICY_ENABLED, + USER_MASK = USER_DISABLED, + MANAGED_MASK = POLICY_DISABLED | POLICY_ENABLED, + POLICY_UNMANAGED = -1 + }; + enum PluginType { PLUGIN_TYPE_NPAPI, PLUGIN_TYPE_PEPPER_IN_PROCESS, @@ -70,10 +96,16 @@ struct WebPluginInfo { // A list of all the mime types that this plugin supports. std::vector<WebPluginMimeType> mime_types; + // Enabled state of the plugin. See the EnabledStates enum. + int enabled; + // Plugin type. See the PluginType enum. int type; }; +// Checks whether a plugin is enabled either by the user or by policy. +bool IsPluginEnabled(const WebPluginInfo& plugin); + // Checks whether a plugin is a Pepper plugin, enabled or disabled. bool IsPepperPlugin(const WebPluginInfo& plugin); diff --git a/webkit/support/webkit_support_glue.cc b/webkit/support/webkit_support_glue.cc index 0f85ff4..501356e 100644 --- a/webkit/support/webkit_support_glue.cc +++ b/webkit/support/webkit_support_glue.cc @@ -30,6 +30,7 @@ void GetPlugins(bool refresh, webkit::WebPluginInfo plugin_info = plugins->at(i); for (size_t j = 0; j < arraysize(kPluginBlackList); ++j) { if (plugin_info.path.BaseName() == FilePath(kPluginBlackList[j])) { + webkit::npapi::PluginList::Singleton()->DisablePlugin(plugin_info.path); plugins->erase(plugins->begin() + i); } } diff --git a/webkit/tools/test_shell/test_shell.cc b/webkit/tools/test_shell/test_shell.cc index 38e83ca..7c78dbc 100644 --- a/webkit/tools/test_shell/test_shell.cc +++ b/webkit/tools/test_shell/test_shell.cc @@ -675,6 +675,7 @@ void GetPlugins(bool refresh, webkit::WebPluginInfo plugin_info = plugins->at(i); for (size_t j = 0; j < arraysize(kPluginBlackList); ++j) { if (plugin_info.path.BaseName() == FilePath(kPluginBlackList[j])) { + webkit::npapi::PluginList::Singleton()->DisablePlugin(plugin_info.path); plugins->erase(plugins->begin() + i); } } |