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 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 36 ChromePluginServiceFilter* ChromePluginServiceFilter::GetInstance() { 37 return Singleton<ChromePluginServiceFilter>::get(); 38 } 39 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 48 void ChromePluginServiceFilter::UnregisterResourceContext( 49 const void* context) { 50 base::AutoLock lock(lock_); 51 resource_context_map_.erase(context); 52 } 53 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 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 77 void ChromePluginServiceFilter::UnrestrictPlugin( 78 const base::FilePath& plugin_path) { 79 base::AutoLock auto_lock(lock_); 80 restricted_plugins_.erase(plugin_path); 81 } 82 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 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 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 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 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 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 192 ChromePluginServiceFilter::~ChromePluginServiceFilter() { 193 } 194 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* 225 ChromePluginServiceFilter::GetOrRegisterProcess( 226 int render_process_id) { 227 return &plugin_details_[render_process_id]; 228 } 229 230 const ChromePluginServiceFilter::ProcessDetails* 231 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 240 ChromePluginServiceFilter::OverriddenPlugin::OverriddenPlugin() 241 : render_frame_id(MSG_ROUTING_NONE) { 242 } 243 244 ChromePluginServiceFilter::OverriddenPlugin::~OverriddenPlugin() { 245 } 246 247 ChromePluginServiceFilter::ProcessDetails::ProcessDetails() { 248 } 249 250 ChromePluginServiceFilter::ProcessDetails::~ProcessDetails() { 251 } 252 253