OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 "webkit/glue/plugins/plugin_list.h" | 5 #include "webkit/glue/plugins/plugin_list.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
10 #include "base/lazy_instance.h" | 10 #include "base/lazy_instance.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/string_split.h" | 12 #include "base/string_split.h" |
13 #include "base/string_util.h" | 13 #include "base/string_util.h" |
14 #include "base/sys_string_conversions.h" | 14 #include "base/sys_string_conversions.h" |
15 #include "base/utf_string_conversions.h" | 15 #include "base/utf_string_conversions.h" |
16 #include "googleurl/src/gurl.h" | 16 #include "googleurl/src/gurl.h" |
17 #include "net/base/mime_util.h" | 17 #include "net/base/mime_util.h" |
18 #include "webkit/glue/plugins/plugin_constants_win.h" | 18 #include "webkit/glue/plugins/plugin_constants_win.h" |
19 #include "webkit/glue/plugins/plugin_lib.h" | 19 #include "webkit/glue/plugins/plugin_lib.h" |
20 #include "webkit/glue/plugins/plugin_switches.h" | 20 #include "webkit/glue/plugins/plugin_switches.h" |
21 #include "webkit/glue/webkit_glue.h" | 21 #include "webkit/glue/webkit_glue.h" |
22 | 22 |
23 namespace NPAPI { | 23 namespace NPAPI { |
24 | 24 |
| 25 #if defined(OS_MACOSX) |
| 26 // Plugin Groups for Mac. |
| 27 // Plugins are listed here as soon as vulnerabilities and solutions |
| 28 // (new versions) are published. |
| 29 // TODO(panayiotis): Get the Real Player version on Mac, somehow. |
| 30 static const PluginGroupDefinition kGroupDefinitions[] = { |
| 31 { "apple-quicktime", "Quicktime", "QuickTime Plug-in", "", "", "7.6.6", |
| 32 "http://www.apple.com/quicktime/download/" }, |
| 33 { "java-runtime-environment", "Java", "Java", "", "", "", |
| 34 "http://support.apple.com/kb/HT1338" }, |
| 35 { "adobe-flash-player", "Flash", "Shockwave Flash", "", "", "10.1.102", |
| 36 "http://get.adobe.com/flashplayer/" }, |
| 37 { "silverlight-3", "Silverlight 3", "Silverlight", "0", "4", "3.0.50106.0", |
| 38 "http://www.microsoft.com/getsilverlight/" }, |
| 39 { "silverlight-4", "Silverlight 4", "Silverlight", "4", "5", "", |
| 40 "http://www.microsoft.com/getsilverlight/" }, |
| 41 { "flip4mac", "Flip4Mac", "Flip4Mac", "", "", "2.2.1", |
| 42 "http://www.telestream.net/flip4mac-wmv/overview.htm" }, |
| 43 { "shockwave", "Shockwave", "Shockwave for Director", "", "", "11.5.9.615", |
| 44 "http://www.adobe.com/shockwave/download/" } |
| 45 }; |
| 46 |
| 47 #elif defined(OS_WIN) |
| 48 // TODO(panayiotis): We should group "RealJukebox NS Plugin" with the rest of |
| 49 // the RealPlayer files. |
| 50 static const PluginGroupDefinition kGroupDefinitions[] = { |
| 51 { "apple-quicktime", "Quicktime", "QuickTime Plug-in", "", "", "7.6.8", |
| 52 "http://www.apple.com/quicktime/download/" }, |
| 53 { "java-runtime-environment", "Java 6", "Java", "", "6", "6.0.220", |
| 54 "http://www.java.com/" }, |
| 55 { "adobe-reader", PluginGroup::kAdobeReader9GroupName, "Adobe Acrobat", "9", |
| 56 "10", "9.4.1", "http://get.adobe.com/reader/" }, |
| 57 { "adobe-reader-8", PluginGroup::kAdobeReader8GroupName, "Adobe Acrobat", "0", |
| 58 "9", "8.2.5", "http://get.adobe.com/reader/" }, |
| 59 { "adobe-flash-player", "Flash", "Shockwave Flash", "", "", "10.1.102", |
| 60 "http://get.adobe.com/flashplayer/" }, |
| 61 { "silverlight-3", "Silverlight 3", "Silverlight", "0", "4", "3.0.50106.0", |
| 62 "http://www.microsoft.com/getsilverlight/" }, |
| 63 { "silverlight-4", "Silverlight 4", "Silverlight", "4", "5", "", |
| 64 "http://www.microsoft.com/getsilverlight/" }, |
| 65 { "shockwave", "Shockwave", "Shockwave for Director", "", "", "11.5.9.615", |
| 66 "http://www.adobe.com/shockwave/download/" }, |
| 67 { "divx-player", "DivX Player", "DivX Web Player", "", "", "1.4.3.4", |
| 68 "http://download.divx.com/divx/autoupdate/player/" |
| 69 "DivXWebPlayerInstaller.exe" }, |
| 70 // These are here for grouping, no vulnerabilies known. |
| 71 { "windows-media-player", "Windows Media Player", "Windows Media Player", |
| 72 "", "", "", "" }, |
| 73 { "microsoft-office", "Microsoft Office", "Microsoft Office", |
| 74 "", "", "", "" }, |
| 75 // TODO(panayiotis): The vulnerable versions are |
| 76 // (v >= 6.0.12.1040 && v <= 6.0.12.1663) |
| 77 // || v == 6.0.12.1698 || v == 6.0.12.1741 |
| 78 { "realplayer", "RealPlayer", "RealPlayer", "", "", "", |
| 79 "http://www.adobe.com/shockwave/download/" }, |
| 80 }; |
| 81 |
| 82 #else |
| 83 static const PluginGroupDefinition kGroupDefinitions[] = {}; |
| 84 #endif |
| 85 |
| 86 // static |
| 87 const PluginGroupDefinition* PluginList::GetPluginGroupDefinitions() { |
| 88 return kGroupDefinitions; |
| 89 } |
| 90 |
| 91 // static |
| 92 size_t PluginList::GetPluginGroupDefinitionsSize() { |
| 93 // TODO(viettrungluu): |arraysize()| doesn't work with zero-size arrays. |
| 94 return ARRAYSIZE_UNSAFE(kGroupDefinitions); |
| 95 } |
| 96 |
25 base::LazyInstance<PluginList> g_singleton(base::LINKER_INITIALIZED); | 97 base::LazyInstance<PluginList> g_singleton(base::LINKER_INITIALIZED); |
26 | 98 |
27 // static | 99 // static |
28 PluginList* PluginList::Singleton() { | 100 PluginList* PluginList::Singleton() { |
29 return g_singleton.Pointer(); | 101 return g_singleton.Pointer(); |
30 } | 102 } |
31 | 103 |
32 // static | 104 // static |
33 bool PluginList::DebugPluginLoading() { | 105 bool PluginList::DebugPluginLoading() { |
34 return CommandLine::ForCurrentProcess()->HasSwitch( | 106 return CommandLine::ForCurrentProcess()->HasSwitch( |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
150 | 222 |
151 info->mime_types.push_back(mime_type); | 223 info->mime_types.push_back(mime_type); |
152 } | 224 } |
153 | 225 |
154 return true; | 226 return true; |
155 } | 227 } |
156 | 228 |
157 PluginList::PluginList() | 229 PluginList::PluginList() |
158 : plugins_loaded_(false), | 230 : plugins_loaded_(false), |
159 plugins_need_refresh_(false), | 231 plugins_need_refresh_(false), |
160 disable_outdated_plugins_(false) { | 232 disable_outdated_plugins_(false), |
| 233 next_priority_(0) { |
161 PlatformInit(); | 234 PlatformInit(); |
| 235 AddHardcodedPluginGroups(); |
162 } | 236 } |
163 | 237 |
164 bool PluginList::ShouldDisableGroup(const string16& group_name) { | 238 bool PluginList::ShouldDisableGroup(const string16& group_name) { |
165 AutoLock lock(lock_); | 239 AutoLock lock(lock_); |
166 if (PluginGroup::IsPluginNameDisabledByPolicy(group_name)) { | 240 if (PluginGroup::IsPluginNameDisabledByPolicy(group_name)) { |
167 disabled_groups_.insert(group_name); | 241 disabled_groups_.insert(group_name); |
168 return true; | 242 return true; |
169 } | 243 } |
170 return disabled_groups_.count(group_name) > 0; | 244 return disabled_groups_.count(group_name) > 0; |
171 } | 245 } |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
226 | 300 |
227 // Load the default plugin last. | 301 // Load the default plugin last. |
228 if (webkit_glue::IsDefaultPluginEnabled()) | 302 if (webkit_glue::IsDefaultPluginEnabled()) |
229 LoadPlugin(FilePath(kDefaultPluginLibraryName), &new_plugins); | 303 LoadPlugin(FilePath(kDefaultPluginLibraryName), &new_plugins); |
230 | 304 |
231 // Disable all of the plugins and plugin groups that are disabled by policy. | 305 // Disable all of the plugins and plugin groups that are disabled by policy. |
232 // There's currenly a bug that makes it impossible to correctly re-enable | 306 // There's currenly a bug that makes it impossible to correctly re-enable |
233 // plugins or plugin-groups to their original, "pre-policy" state, so | 307 // plugins or plugin-groups to their original, "pre-policy" state, so |
234 // plugins and groups are only changed to a more "safe" state after a policy | 308 // plugins and groups are only changed to a more "safe" state after a policy |
235 // change, i.e. from enabled to disabled. See bug 54681. | 309 // change, i.e. from enabled to disabled. See bug 54681. |
236 PluginMap plugin_groups; | 310 for (PluginGroup::PluginMap::iterator it = plugin_groups_.begin(); |
237 GetPluginGroups(&new_plugins, &plugin_groups); | 311 it != plugin_groups_.end(); ++it) { |
238 for (PluginMap::const_iterator it = plugin_groups.begin(); | 312 PluginGroup* group = it->second; |
239 it != plugin_groups.end(); ++it) { | |
240 PluginGroup* group = it->second.get(); | |
241 string16 group_name = group->GetGroupName(); | 313 string16 group_name = group->GetGroupName(); |
242 if (ShouldDisableGroup(group_name)) { | 314 if (ShouldDisableGroup(group_name)) { |
243 it->second->Enable(false); | 315 group->Enable(false); |
244 } | 316 } |
245 | 317 |
246 if (disable_outdated_plugins_) { | 318 if (disable_outdated_plugins_) { |
247 group->DisableOutdatedPlugins(); | 319 group->DisableOutdatedPlugins(); |
248 if (!group->Enabled()) { | 320 } |
249 AutoLock lock(lock_); | 321 if (!group->Enabled()) { |
250 disabled_groups_.insert(group_name); | 322 AutoLock lock(lock_); |
251 } | 323 disabled_groups_.insert(group_name); |
252 } | 324 } |
253 } | 325 } |
254 | 326 |
255 // Only update the data now since loading plugins can take a while. | 327 // Only update the data now since loading plugins can take a while. |
256 AutoLock lock(lock_); | 328 AutoLock lock(lock_); |
257 | 329 |
258 // Mark disabled plugins as such. | |
259 for (size_t i = 0; i < new_plugins.size(); ++i) { | |
260 if (disabled_plugins_.count(new_plugins[i].path)) | |
261 new_plugins[i].enabled = false; | |
262 } | |
263 | |
264 plugins_ = new_plugins; | 330 plugins_ = new_plugins; |
265 plugins_loaded_ = true; | 331 plugins_loaded_ = true; |
266 } | 332 } |
267 | 333 |
268 void PluginList::LoadPlugin(const FilePath& path, | 334 void PluginList::LoadPlugin(const FilePath& path, |
269 std::vector<WebPluginInfo>* plugins) { | 335 std::vector<WebPluginInfo>* plugins) { |
270 LOG_IF(ERROR, PluginList::DebugPluginLoading()) | 336 LOG_IF(ERROR, PluginList::DebugPluginLoading()) |
271 << "Loading plugin " << path.value(); | 337 << "Loading plugin " << path.value(); |
272 | 338 |
273 WebPluginInfo plugin_info; | 339 WebPluginInfo plugin_info; |
(...skipping 13 matching lines...) Expand all Loading... |
287 for (size_t i = 0; i < plugin_info.mime_types.size(); ++i) { | 353 for (size_t i = 0; i < plugin_info.mime_types.size(); ++i) { |
288 // TODO: don't load global handlers for now. | 354 // TODO: don't load global handlers for now. |
289 // WebKit hands to the Plugin before it tries | 355 // WebKit hands to the Plugin before it tries |
290 // to handle mimeTypes on its own. | 356 // to handle mimeTypes on its own. |
291 const std::string &mime_type = plugin_info.mime_types[i].mime_type; | 357 const std::string &mime_type = plugin_info.mime_types[i].mime_type; |
292 if (mime_type == "*" ) | 358 if (mime_type == "*" ) |
293 return; | 359 return; |
294 } | 360 } |
295 } | 361 } |
296 | 362 |
| 363 // Mark disabled plugins as such. (This has to happen before calling |
| 364 // |AddToPluginGroups(plugin_info)|.) |
| 365 if (disabled_plugins_.count(plugin_info.path)) { |
| 366 plugin_info.enabled = false; |
| 367 } else { |
| 368 plugin_info.enabled = true; |
| 369 } |
| 370 |
| 371 AutoLock lock(lock_); |
297 plugins->push_back(plugin_info); | 372 plugins->push_back(plugin_info); |
| 373 AddToPluginGroups(plugin_info); |
298 } | 374 } |
299 | 375 |
300 bool PluginList::SupportsType(const WebPluginInfo& info, | 376 bool PluginList::SupportsType(const WebPluginInfo& info, |
301 const std::string &mime_type, | 377 const std::string &mime_type, |
302 bool allow_wildcard) { | 378 bool allow_wildcard) { |
303 // Webkit will ask for a plugin to handle empty mime types. | 379 // Webkit will ask for a plugin to handle empty mime types. |
304 if (mime_type.empty()) | 380 if (mime_type.empty()) |
305 return false; | 381 return false; |
306 | 382 |
307 for (size_t i = 0; i < info.mime_types.size(); ++i) { | 383 for (size_t i = 0; i < info.mime_types.size(); ++i) { |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
469 for (size_t i = 0; i < plugins_.size(); ++i) { | 545 for (size_t i = 0; i < plugins_.size(); ++i) { |
470 if (plugins_[i].path == plugin_path) { | 546 if (plugins_[i].path == plugin_path) { |
471 *info = plugins_[i]; | 547 *info = plugins_[i]; |
472 return true; | 548 return true; |
473 } | 549 } |
474 } | 550 } |
475 | 551 |
476 return false; | 552 return false; |
477 } | 553 } |
478 | 554 |
479 void PluginList::GetPluginGroups(bool load_if_necessary, | 555 void PluginList::GetPluginGroups( |
480 PluginMap* plugin_groups) { | 556 bool load_if_necessary, |
| 557 std::vector<PluginGroup>* plugin_groups) { |
481 if (load_if_necessary) | 558 if (load_if_necessary) |
482 LoadPlugins(false); | 559 LoadPlugins(false); |
483 | |
484 AutoLock lock(lock_); | |
485 GetPluginGroups(&plugins_, plugin_groups); | |
486 } | |
487 | |
488 // static | |
489 void PluginList::GetPluginGroups(const std::vector<WebPluginInfo>* plugins, | |
490 PluginMap* plugin_groups) { | |
491 plugin_groups->clear(); | 560 plugin_groups->clear(); |
492 // We first search for an existing group that matches our name, | 561 for (PluginGroup::PluginMap::const_iterator it = plugin_groups_.begin(); |
493 // and only create a new group if we can't find any. | 562 it != plugin_groups_.end(); ++it) { |
494 for (size_t i = 0; i < plugins->size(); ++i) { | 563 plugin_groups->push_back(*it->second); |
495 const WebPluginInfo& web_plugin = (*plugins)[i]; | |
496 PluginGroup* group = PluginGroup::FindGroupMatchingPlugin( | |
497 *plugin_groups, web_plugin); | |
498 if (!group) { | |
499 group = PluginGroup::CopyOrCreatePluginGroup(web_plugin); | |
500 std::string identifier = group->identifier(); | |
501 // If the identifier is not unique, use the full path. This means that we | |
502 // probably won't be able to search for this group by identifier, but at | |
503 // least it's going to be in the set of plugin groups, and if there | |
504 // is already a plug-in with the same filename, it's probably going to | |
505 // handle the same MIME types (and it has a higher priority), so this one | |
506 // is not going to run anyway. | |
507 if (plugin_groups->find(identifier) != plugin_groups->end()) | |
508 #if defined(OS_POSIX) | |
509 identifier = web_plugin.path.value(); | |
510 #elif defined(OS_WIN) | |
511 identifier = base::SysWideToUTF8(web_plugin.path.value()); | |
512 #endif | |
513 DCHECK(plugin_groups->find(identifier) == plugin_groups->end()); | |
514 (*plugin_groups)[identifier] = linked_ptr<PluginGroup>(group); | |
515 } | |
516 group->AddPlugin(web_plugin, i); | |
517 } | 564 } |
518 } | 565 } |
519 | 566 |
| 567 const PluginGroup* PluginList::GetPluginGroup( |
| 568 const WebPluginInfo& web_plugin_info) { |
| 569 AutoLock lock(lock_); |
| 570 return AddToPluginGroups(web_plugin_info); |
| 571 } |
| 572 |
| 573 string16 PluginList::GetPluginGroupName(std::string identifier) { |
| 574 PluginGroup::PluginMap::iterator it = plugin_groups_.find(identifier); |
| 575 if (it == plugin_groups_.end()) { |
| 576 return string16(); |
| 577 } |
| 578 return it->second->GetGroupName(); |
| 579 } |
| 580 |
| 581 std::string PluginList::GetPluginGroupIdentifier( |
| 582 const WebPluginInfo& web_plugin_info) { |
| 583 AutoLock lock(lock_); |
| 584 PluginGroup* group = AddToPluginGroups(web_plugin_info); |
| 585 return group->identifier(); |
| 586 } |
| 587 |
| 588 void PluginList::AddHardcodedPluginGroups() { |
| 589 AutoLock lock(lock_); |
| 590 const PluginGroupDefinition* definitions = GetPluginGroupDefinitions(); |
| 591 for (size_t i = 0; i < GetPluginGroupDefinitionsSize(); ++i) { |
| 592 PluginGroup* definition_group = PluginGroup::FromPluginGroupDefinition( |
| 593 definitions[i]); |
| 594 std::string identifier = definition_group->identifier(); |
| 595 DCHECK(plugin_groups_.find(identifier) == plugin_groups_.end()); |
| 596 plugin_groups_.insert(std::make_pair(identifier, definition_group)); |
| 597 } |
| 598 } |
| 599 |
| 600 PluginGroup* PluginList::AddToPluginGroups( |
| 601 const WebPluginInfo& web_plugin_info) { |
| 602 PluginGroup* group = NULL; |
| 603 for (PluginGroup::PluginMap::iterator it = plugin_groups_.begin(); |
| 604 it != plugin_groups_.end(); ++it) { |
| 605 if (it->second->Match(web_plugin_info)) |
| 606 group = it->second; |
| 607 } |
| 608 if (!group) { |
| 609 group = PluginGroup::FromWebPluginInfo(web_plugin_info); |
| 610 std::string identifier = group->identifier(); |
| 611 // If the identifier is not unique, use the full path. This means that we |
| 612 // probably won't be able to search for this group by identifier, but at |
| 613 // least it's going to be in the set of plugin groups, and if there |
| 614 // is already a plug-in with the same filename, it's probably going to |
| 615 // handle the same MIME types (and it has a higher priority), so this one |
| 616 // is not going to run anyway. |
| 617 if (plugin_groups_.find(identifier) != plugin_groups_.end()) |
| 618 identifier = PluginGroup::GetLongIdentifier(web_plugin_info); |
| 619 DCHECK(plugin_groups_.find(identifier) == plugin_groups_.end()); |
| 620 plugin_groups_.insert(std::make_pair(identifier, group)); |
| 621 } |
| 622 group->AddPlugin(web_plugin_info, next_priority_++); |
| 623 return group; |
| 624 } |
| 625 |
520 bool PluginList::EnablePlugin(const FilePath& filename) { | 626 bool PluginList::EnablePlugin(const FilePath& filename) { |
521 AutoLock lock(lock_); | 627 AutoLock lock(lock_); |
522 | 628 |
523 bool did_enable = false; | 629 bool did_enable = false; |
524 | 630 |
525 std::set<FilePath>::iterator entry = disabled_plugins_.find(filename); | 631 std::set<FilePath>::iterator entry = disabled_plugins_.find(filename); |
526 if (entry == disabled_plugins_.end()) | 632 if (entry == disabled_plugins_.end()) |
527 return did_enable; // Early exit if plugin not in disabled list. | 633 return did_enable; // Early exit if plugin not in disabled list. |
528 | 634 |
529 disabled_plugins_.erase(entry); // Remove from disabled list. | 635 disabled_plugins_.erase(entry); // Remove from disabled list. |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
576 if (entry == disabled_groups_.end()) | 682 if (entry == disabled_groups_.end()) |
577 return did_change; // Early exit if group not in disabled list. | 683 return did_change; // Early exit if group not in disabled list. |
578 disabled_groups_.erase(entry); // Remove from disabled list. | 684 disabled_groups_.erase(entry); // Remove from disabled list. |
579 } else { | 685 } else { |
580 if (entry != disabled_groups_.end()) | 686 if (entry != disabled_groups_.end()) |
581 return did_change; // Early exit if group already in disabled list. | 687 return did_change; // Early exit if group already in disabled list. |
582 disabled_groups_.insert(group_name); | 688 disabled_groups_.insert(group_name); |
583 } | 689 } |
584 } | 690 } |
585 | 691 |
586 PluginMap plugin_groups; | 692 for (PluginGroup::PluginMap::iterator it = plugin_groups_.begin(); |
587 GetPluginGroups(false, &plugin_groups); | 693 it != plugin_groups_.end(); ++it) { |
588 for (PluginMap::const_iterator it = plugin_groups.begin(); | |
589 it != plugin_groups.end(); ++it) { | |
590 if (it->second->GetGroupName() == group_name) { | 694 if (it->second->GetGroupName() == group_name) { |
591 if (it->second->Enabled() != enable) { | 695 if (it->second->Enabled() != enable) { |
592 it->second->Enable(enable); | 696 it->second->Enable(enable); |
593 did_change = true; | 697 did_change = true; |
594 break; | 698 break; |
595 } | 699 } |
596 } | 700 } |
597 } | 701 } |
598 | 702 |
599 return did_change; | 703 return did_change; |
600 } | 704 } |
601 | 705 |
602 void PluginList::DisableOutdatedPluginGroups() { | 706 void PluginList::DisableOutdatedPluginGroups() { |
603 disable_outdated_plugins_ = true; | 707 disable_outdated_plugins_ = true; |
604 } | 708 } |
605 | 709 |
606 PluginList::~PluginList() { | 710 PluginList::~PluginList() { |
607 } | 711 } |
608 | 712 |
609 void PluginList::Shutdown() { | 713 void PluginList::Shutdown() { |
610 // TODO | 714 // TODO |
| 715 // Note: plugin_groups_ contains simple pointers of type PluginGroup*, but |
| 716 // since this singleton lives until the process is destroyed, no explicit |
| 717 // cleanup is necessary. |
611 } | 718 } |
612 | 719 |
613 } // namespace NPAPI | 720 } // namespace NPAPI |
OLD | NEW |