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