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 23using content::BrowserThread; 24using content::PluginService; 25 26namespace { 27 28void AuthorizeRenderer(content::RenderFrameHost* render_frame_host) { 29 ChromePluginServiceFilter::GetInstance()->AuthorizePlugin( 30 render_frame_host->GetProcess()->GetID(), base::FilePath()); 31} 32 33} 34 35// static 36ChromePluginServiceFilter* ChromePluginServiceFilter::GetInstance() { 37 return Singleton<ChromePluginServiceFilter>::get(); 38} 39 40void 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 48void ChromePluginServiceFilter::UnregisterResourceContext( 49 const void* context) { 50 base::AutoLock lock(lock_); 51 resource_context_map_.erase(context); 52} 53 54void 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 68void 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 77void ChromePluginServiceFilter::UnrestrictPlugin( 78 const base::FilePath& plugin_path) { 79 base::AutoLock auto_lock(lock_); 80 restricted_plugins_.erase(plugin_path); 81} 82 83bool 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 89bool 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 142bool 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 164void 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 172void 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 184ChromePluginServiceFilter::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 192ChromePluginServiceFilter::~ChromePluginServiceFilter() { 193} 194 195void 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 224ChromePluginServiceFilter::ProcessDetails* 225ChromePluginServiceFilter::GetOrRegisterProcess( 226 int render_process_id) { 227 return &plugin_details_[render_process_id]; 228} 229 230const ChromePluginServiceFilter::ProcessDetails* 231ChromePluginServiceFilter::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 240ChromePluginServiceFilter::OverriddenPlugin::OverriddenPlugin() 241 : render_frame_id(MSG_ROUTING_NONE) { 242} 243 244ChromePluginServiceFilter::OverriddenPlugin::~OverriddenPlugin() { 245} 246 247ChromePluginServiceFilter::ProcessDetails::ProcessDetails() { 248} 249 250ChromePluginServiceFilter::ProcessDetails::~ProcessDetails() { 251} 252 253