• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/plugins/chrome_plugin_service_filter.h"
6 
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "chrome/browser/chrome_notification_types.h"
11 #include "chrome/browser/plugins/plugin_metadata.h"
12 #include "chrome/browser/plugins/plugin_prefs.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/common/render_messages.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "content/public/browser/notification_service.h"
17 #include "content/public/browser/plugin_service.h"
18 #include "content/public/browser/render_frame_host.h"
19 #include "content/public/browser/render_process_host.h"
20 #include "content/public/browser/resource_context.h"
21 #include "content/public/browser/web_contents.h"
22 
23 using content::BrowserThread;
24 using content::PluginService;
25 
26 namespace {
27 
AuthorizeRenderer(content::RenderFrameHost * render_frame_host)28 void AuthorizeRenderer(content::RenderFrameHost* render_frame_host) {
29   ChromePluginServiceFilter::GetInstance()->AuthorizePlugin(
30       render_frame_host->GetProcess()->GetID(), base::FilePath());
31 }
32 
33 }
34 
35 // static
GetInstance()36 ChromePluginServiceFilter* ChromePluginServiceFilter::GetInstance() {
37   return Singleton<ChromePluginServiceFilter>::get();
38 }
39 
RegisterResourceContext(PluginPrefs * plugin_prefs,const void * context)40 void ChromePluginServiceFilter::RegisterResourceContext(
41     PluginPrefs* plugin_prefs,
42     const void* context) {
43   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
44   base::AutoLock lock(lock_);
45   resource_context_map_[context] = plugin_prefs;
46 }
47 
UnregisterResourceContext(const void * context)48 void ChromePluginServiceFilter::UnregisterResourceContext(
49     const void* context) {
50   base::AutoLock lock(lock_);
51   resource_context_map_.erase(context);
52 }
53 
OverridePluginForFrame(int render_process_id,int render_frame_id,const GURL & url,const content::WebPluginInfo & plugin)54 void ChromePluginServiceFilter::OverridePluginForFrame(
55     int render_process_id,
56     int render_frame_id,
57     const GURL& url,
58     const content::WebPluginInfo& plugin) {
59   base::AutoLock auto_lock(lock_);
60   ProcessDetails* details = GetOrRegisterProcess(render_process_id);
61   OverriddenPlugin overridden_plugin;
62   overridden_plugin.render_frame_id = render_frame_id;
63   overridden_plugin.url = url;
64   overridden_plugin.plugin = plugin;
65   details->overridden_plugins.push_back(overridden_plugin);
66 }
67 
RestrictPluginToProfileAndOrigin(const base::FilePath & plugin_path,Profile * profile,const GURL & origin)68 void ChromePluginServiceFilter::RestrictPluginToProfileAndOrigin(
69     const base::FilePath& plugin_path,
70     Profile* profile,
71     const GURL& origin) {
72   base::AutoLock auto_lock(lock_);
73   restricted_plugins_[plugin_path] =
74       std::make_pair(PluginPrefs::GetForProfile(profile).get(), origin);
75 }
76 
UnrestrictPlugin(const base::FilePath & plugin_path)77 void ChromePluginServiceFilter::UnrestrictPlugin(
78     const base::FilePath& plugin_path) {
79   base::AutoLock auto_lock(lock_);
80   restricted_plugins_.erase(plugin_path);
81 }
82 
IsPluginRestricted(const base::FilePath & plugin_path)83 bool ChromePluginServiceFilter::IsPluginRestricted(
84     const base::FilePath& plugin_path) {
85   base::AutoLock auto_lock(lock_);
86   return restricted_plugins_.find(plugin_path) != restricted_plugins_.end();
87 }
88 
IsPluginAvailable(int render_process_id,int render_frame_id,const void * context,const GURL & url,const GURL & policy_url,content::WebPluginInfo * plugin)89 bool ChromePluginServiceFilter::IsPluginAvailable(
90     int render_process_id,
91     int render_frame_id,
92     const void* context,
93     const GURL& url,
94     const GURL& policy_url,
95     content::WebPluginInfo* plugin) {
96   base::AutoLock auto_lock(lock_);
97   const ProcessDetails* details = GetProcess(render_process_id);
98 
99   // Check whether the plugin is overridden.
100   if (details) {
101     for (size_t i = 0; i < details->overridden_plugins.size(); ++i) {
102       if (details->overridden_plugins[i].render_frame_id == render_frame_id &&
103           (details->overridden_plugins[i].url == url ||
104            details->overridden_plugins[i].url.is_empty())) {
105 
106         bool use = details->overridden_plugins[i].plugin.path == plugin->path;
107         if (use)
108           *plugin = details->overridden_plugins[i].plugin;
109         return use;
110       }
111     }
112   }
113 
114   // Check whether the plugin is disabled.
115   ResourceContextMap::iterator prefs_it =
116       resource_context_map_.find(context);
117   if (prefs_it == resource_context_map_.end())
118     return false;
119 
120   PluginPrefs* plugin_prefs = prefs_it->second.get();
121   if (!plugin_prefs->IsPluginEnabled(*plugin))
122     return false;
123 
124   // Check whether the plugin is restricted to a URL.
125   RestrictedPluginMap::const_iterator it =
126       restricted_plugins_.find(plugin->path);
127   if (it != restricted_plugins_.end()) {
128     if (it->second.first != plugin_prefs)
129       return false;
130     const GURL& origin = it->second.second;
131     if (!origin.is_empty() &&
132         (policy_url.scheme() != origin.scheme() ||
133          policy_url.host() != origin.host() ||
134          policy_url.port() != origin.port())) {
135       return false;
136     }
137   }
138 
139   return true;
140 }
141 
CanLoadPlugin(int render_process_id,const base::FilePath & path)142 bool ChromePluginServiceFilter::CanLoadPlugin(int render_process_id,
143                                               const base::FilePath& path) {
144   // The browser itself sometimes loads plug-ins to e.g. clear plug-in data.
145   // We always grant the browser permission.
146   if (!render_process_id)
147     return true;
148 
149   base::AutoLock auto_lock(lock_);
150   const ProcessDetails* details = GetProcess(render_process_id);
151   if (!details)
152     return false;
153 
154   if (details->authorized_plugins.find(path) ==
155           details->authorized_plugins.end() &&
156       details->authorized_plugins.find(base::FilePath()) ==
157           details->authorized_plugins.end()) {
158     return false;
159   }
160 
161   return true;
162 }
163 
AuthorizePlugin(int render_process_id,const base::FilePath & plugin_path)164 void ChromePluginServiceFilter::AuthorizePlugin(
165     int render_process_id,
166     const base::FilePath& plugin_path) {
167   base::AutoLock auto_lock(lock_);
168   ProcessDetails* details = GetOrRegisterProcess(render_process_id);
169   details->authorized_plugins.insert(plugin_path);
170 }
171 
AuthorizeAllPlugins(content::WebContents * web_contents,bool load_blocked,const std::string & identifier)172 void ChromePluginServiceFilter::AuthorizeAllPlugins(
173     content::WebContents* web_contents,
174     bool load_blocked,
175     const std::string& identifier) {
176   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
177   web_contents->ForEachFrame(base::Bind(&AuthorizeRenderer));
178   if (load_blocked) {
179     web_contents->SendToAllFrames(new ChromeViewMsg_LoadBlockedPlugins(
180         MSG_ROUTING_NONE, identifier));
181   }
182 }
183 
ChromePluginServiceFilter()184 ChromePluginServiceFilter::ChromePluginServiceFilter() {
185   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
186   registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
187                  content::NotificationService::AllSources());
188   registrar_.Add(this, chrome::NOTIFICATION_PLUGIN_ENABLE_STATUS_CHANGED,
189                  content::NotificationService::AllSources());
190 }
191 
~ChromePluginServiceFilter()192 ChromePluginServiceFilter::~ChromePluginServiceFilter() {
193 }
194 
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)195 void ChromePluginServiceFilter::Observe(
196     int type,
197     const content::NotificationSource& source,
198     const content::NotificationDetails& details) {
199   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
200   switch (type) {
201     case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
202       int render_process_id =
203           content::Source<content::RenderProcessHost>(source).ptr()->GetID();
204 
205       base::AutoLock auto_lock(lock_);
206       plugin_details_.erase(render_process_id);
207       break;
208     }
209     case chrome::NOTIFICATION_PLUGIN_ENABLE_STATUS_CHANGED: {
210       Profile* profile = content::Source<Profile>(source).ptr();
211       PluginService::GetInstance()->PurgePluginListCache(profile, false);
212       if (profile && profile->HasOffTheRecordProfile()) {
213         PluginService::GetInstance()->PurgePluginListCache(
214             profile->GetOffTheRecordProfile(), false);
215       }
216       break;
217     }
218     default: {
219       NOTREACHED();
220     }
221   }
222 }
223 
224 ChromePluginServiceFilter::ProcessDetails*
GetOrRegisterProcess(int render_process_id)225 ChromePluginServiceFilter::GetOrRegisterProcess(
226     int render_process_id) {
227   return &plugin_details_[render_process_id];
228 }
229 
230 const ChromePluginServiceFilter::ProcessDetails*
GetProcess(int render_process_id) const231 ChromePluginServiceFilter::GetProcess(
232     int render_process_id) const {
233   std::map<int, ProcessDetails>::const_iterator it =
234       plugin_details_.find(render_process_id);
235   if (it == plugin_details_.end())
236     return NULL;
237   return &it->second;
238 }
239 
OverriddenPlugin()240 ChromePluginServiceFilter::OverriddenPlugin::OverriddenPlugin()
241     : render_frame_id(MSG_ROUTING_NONE) {
242 }
243 
~OverriddenPlugin()244 ChromePluginServiceFilter::OverriddenPlugin::~OverriddenPlugin() {
245 }
246 
ProcessDetails()247 ChromePluginServiceFilter::ProcessDetails::ProcessDetails() {
248 }
249 
~ProcessDetails()250 ChromePluginServiceFilter::ProcessDetails::~ProcessDetails() {
251 }
252 
253