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::OverridePluginForFrame( 42 int render_process_id, 43 int render_frame_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_frame_id = render_frame_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::IsPluginRestricted( 71 const base::FilePath& plugin_path) { 72 base::AutoLock auto_lock(lock_); 73 return restricted_plugins_.find(plugin_path) != restricted_plugins_.end(); 74 } 75 76 bool ChromePluginServiceFilter::IsPluginAvailable( 77 int render_process_id, 78 int render_frame_id, 79 const void* context, 80 const GURL& url, 81 const GURL& policy_url, 82 content::WebPluginInfo* plugin) { 83 base::AutoLock auto_lock(lock_); 84 const ProcessDetails* details = GetProcess(render_process_id); 85 86 // Check whether the plugin is overridden. 87 if (details) { 88 for (size_t i = 0; i < details->overridden_plugins.size(); ++i) { 89 if (details->overridden_plugins[i].render_frame_id == render_frame_id && 90 (details->overridden_plugins[i].url == url || 91 details->overridden_plugins[i].url.is_empty())) { 92 93 bool use = details->overridden_plugins[i].plugin.path == plugin->path; 94 if (use) 95 *plugin = details->overridden_plugins[i].plugin; 96 return use; 97 } 98 } 99 } 100 101 // Check whether the plugin is disabled. 102 ResourceContextMap::iterator prefs_it = 103 resource_context_map_.find(context); 104 if (prefs_it == resource_context_map_.end()) 105 return false; 106 107 PluginPrefs* plugin_prefs = prefs_it->second.get(); 108 if (!plugin_prefs->IsPluginEnabled(*plugin)) 109 return false; 110 111 // Check whether the plugin is restricted to a URL. 112 RestrictedPluginMap::const_iterator it = 113 restricted_plugins_.find(plugin->path); 114 if (it != restricted_plugins_.end()) { 115 if (it->second.first != plugin_prefs) 116 return false; 117 const GURL& origin = it->second.second; 118 if (!origin.is_empty() && 119 (policy_url.scheme() != origin.scheme() || 120 policy_url.host() != origin.host() || 121 policy_url.port() != origin.port())) { 122 return false; 123 } 124 } 125 126 return true; 127 } 128 129 bool ChromePluginServiceFilter::CanLoadPlugin(int render_process_id, 130 const base::FilePath& path) { 131 // The browser itself sometimes loads plug-ins to e.g. clear plug-in data. 132 // We always grant the browser permission. 133 if (!render_process_id) 134 return true; 135 136 base::AutoLock auto_lock(lock_); 137 const ProcessDetails* details = GetProcess(render_process_id); 138 if (!details) 139 return false; 140 141 if (details->authorized_plugins.find(path) == 142 details->authorized_plugins.end() && 143 details->authorized_plugins.find(base::FilePath()) == 144 details->authorized_plugins.end()) { 145 return false; 146 } 147 148 return true; 149 } 150 151 void ChromePluginServiceFilter::AuthorizePlugin( 152 int render_process_id, 153 const base::FilePath& plugin_path) { 154 base::AutoLock auto_lock(lock_); 155 ProcessDetails* details = GetOrRegisterProcess(render_process_id); 156 details->authorized_plugins.insert(plugin_path); 157 } 158 159 void ChromePluginServiceFilter::AuthorizeAllPlugins(int render_process_id) { 160 AuthorizePlugin(render_process_id, base::FilePath()); 161 } 162 163 ChromePluginServiceFilter::ChromePluginServiceFilter() { 164 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 165 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, 166 content::NotificationService::AllSources()); 167 registrar_.Add(this, chrome::NOTIFICATION_PLUGIN_ENABLE_STATUS_CHANGED, 168 content::NotificationService::AllSources()); 169 } 170 171 ChromePluginServiceFilter::~ChromePluginServiceFilter() { 172 } 173 174 void ChromePluginServiceFilter::Observe( 175 int type, 176 const content::NotificationSource& source, 177 const content::NotificationDetails& details) { 178 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 179 switch (type) { 180 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { 181 int render_process_id = 182 content::Source<content::RenderProcessHost>(source).ptr()->GetID(); 183 184 base::AutoLock auto_lock(lock_); 185 plugin_details_.erase(render_process_id); 186 break; 187 } 188 case chrome::NOTIFICATION_PLUGIN_ENABLE_STATUS_CHANGED: { 189 Profile* profile = content::Source<Profile>(source).ptr(); 190 PluginService::GetInstance()->PurgePluginListCache(profile, false); 191 if (profile && profile->HasOffTheRecordProfile()) { 192 PluginService::GetInstance()->PurgePluginListCache( 193 profile->GetOffTheRecordProfile(), false); 194 } 195 break; 196 } 197 default: { 198 NOTREACHED(); 199 } 200 } 201 } 202 203 ChromePluginServiceFilter::ProcessDetails* 204 ChromePluginServiceFilter::GetOrRegisterProcess( 205 int render_process_id) { 206 return &plugin_details_[render_process_id]; 207 } 208 209 const ChromePluginServiceFilter::ProcessDetails* 210 ChromePluginServiceFilter::GetProcess( 211 int render_process_id) const { 212 std::map<int, ProcessDetails>::const_iterator it = 213 plugin_details_.find(render_process_id); 214 if (it == plugin_details_.end()) 215 return NULL; 216 return &it->second; 217 } 218 219 ChromePluginServiceFilter::OverriddenPlugin::OverriddenPlugin() 220 : render_frame_id(MSG_ROUTING_NONE) { 221 } 222 223 ChromePluginServiceFilter::OverriddenPlugin::~OverriddenPlugin() { 224 } 225 226 ChromePluginServiceFilter::ProcessDetails::ProcessDetails() { 227 } 228 229 ChromePluginServiceFilter::ProcessDetails::~ProcessDetails() { 230 } 231 232