1 // Copyright (c) 2013 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 "extensions/common/permissions/permissions_data.h" 6 7 #include "base/command_line.h" 8 #include "content/public/common/url_constants.h" 9 #include "extensions/common/constants.h" 10 #include "extensions/common/error_utils.h" 11 #include "extensions/common/extensions_client.h" 12 #include "extensions/common/manifest.h" 13 #include "extensions/common/manifest_constants.h" 14 #include "extensions/common/manifest_handlers/permissions_parser.h" 15 #include "extensions/common/permissions/permission_message_provider.h" 16 #include "extensions/common/switches.h" 17 #include "extensions/common/url_pattern_set.h" 18 #include "extensions/common/user_script.h" 19 #include "url/gurl.h" 20 #include "url/url_constants.h" 21 22 namespace extensions { 23 24 namespace { 25 26 PermissionsData::PolicyDelegate* g_policy_delegate = NULL; 27 28 } // namespace 29 30 PermissionsData::PermissionsData(const Extension* extension) 31 : extension_id_(extension->id()), manifest_type_(extension->GetType()) { 32 base::AutoLock auto_lock(runtime_lock_); 33 scoped_refptr<const PermissionSet> required_permissions = 34 PermissionsParser::GetRequiredPermissions(extension); 35 active_permissions_unsafe_ = 36 new PermissionSet(required_permissions->apis(), 37 required_permissions->manifest_permissions(), 38 required_permissions->explicit_hosts(), 39 required_permissions->scriptable_hosts()); 40 withheld_permissions_unsafe_ = new PermissionSet(); 41 } 42 43 PermissionsData::~PermissionsData() { 44 } 45 46 // static 47 void PermissionsData::SetPolicyDelegate(PolicyDelegate* delegate) { 48 g_policy_delegate = delegate; 49 } 50 51 // static 52 bool PermissionsData::CanSilentlyIncreasePermissions( 53 const Extension* extension) { 54 return extension->location() != Manifest::INTERNAL; 55 } 56 57 // static 58 bool PermissionsData::CanExecuteScriptEverywhere(const Extension* extension) { 59 if (extension->location() == Manifest::COMPONENT) 60 return true; 61 62 const ExtensionsClient::ScriptingWhitelist& whitelist = 63 ExtensionsClient::Get()->GetScriptingWhitelist(); 64 65 return std::find(whitelist.begin(), whitelist.end(), extension->id()) != 66 whitelist.end(); 67 } 68 69 bool PermissionsData::ShouldSkipPermissionWarnings( 70 const std::string& extension_id) { 71 // See http://b/4946060 for more details. 72 return extension_id == std::string("nckgahadagoaajjgafhacjanaoiihapd"); 73 } 74 75 // static 76 bool PermissionsData::IsRestrictedUrl(const GURL& document_url, 77 const GURL& top_frame_url, 78 const Extension* extension, 79 std::string* error) { 80 if (extension && CanExecuteScriptEverywhere(extension)) 81 return false; 82 83 // Check if the scheme is valid for extensions. If not, return. 84 if (!URLPattern::IsValidSchemeForExtensions(document_url.scheme()) && 85 document_url.spec() != url::kAboutBlankURL) { 86 if (error) { 87 *error = ErrorUtils::FormatErrorMessage( 88 manifest_errors::kCannotAccessPage, 89 document_url.spec()); 90 } 91 return true; 92 } 93 94 if (!ExtensionsClient::Get()->IsScriptableURL(document_url, error)) 95 return true; 96 97 bool allow_on_chrome_urls = base::CommandLine::ForCurrentProcess()->HasSwitch( 98 switches::kExtensionsOnChromeURLs); 99 if (document_url.SchemeIs(content::kChromeUIScheme) && 100 !allow_on_chrome_urls) { 101 if (error) 102 *error = manifest_errors::kCannotAccessChromeUrl; 103 return true; 104 } 105 106 if (extension && top_frame_url.SchemeIs(kExtensionScheme) && 107 top_frame_url.host() != extension->id() && !allow_on_chrome_urls) { 108 if (error) 109 *error = manifest_errors::kCannotAccessExtensionUrl; 110 return true; 111 } 112 113 return false; 114 } 115 116 void PermissionsData::SetPermissions( 117 const scoped_refptr<const PermissionSet>& active, 118 const scoped_refptr<const PermissionSet>& withheld) const { 119 base::AutoLock auto_lock(runtime_lock_); 120 active_permissions_unsafe_ = active; 121 withheld_permissions_unsafe_ = withheld; 122 } 123 124 void PermissionsData::UpdateTabSpecificPermissions( 125 int tab_id, 126 scoped_refptr<const PermissionSet> permissions) const { 127 base::AutoLock auto_lock(runtime_lock_); 128 CHECK_GE(tab_id, 0); 129 TabPermissionsMap::iterator iter = tab_specific_permissions_.find(tab_id); 130 if (iter == tab_specific_permissions_.end()) 131 tab_specific_permissions_[tab_id] = permissions; 132 else 133 iter->second = 134 PermissionSet::CreateUnion(iter->second.get(), permissions.get()); 135 } 136 137 void PermissionsData::ClearTabSpecificPermissions(int tab_id) const { 138 base::AutoLock auto_lock(runtime_lock_); 139 CHECK_GE(tab_id, 0); 140 tab_specific_permissions_.erase(tab_id); 141 } 142 143 bool PermissionsData::HasAPIPermission(APIPermission::ID permission) const { 144 return active_permissions()->HasAPIPermission(permission); 145 } 146 147 bool PermissionsData::HasAPIPermission( 148 const std::string& permission_name) const { 149 return active_permissions()->HasAPIPermission(permission_name); 150 } 151 152 bool PermissionsData::HasAPIPermissionForTab( 153 int tab_id, 154 APIPermission::ID permission) const { 155 if (HasAPIPermission(permission)) 156 return true; 157 158 scoped_refptr<const PermissionSet> tab_permissions = 159 GetTabSpecificPermissions(tab_id); 160 161 // Place autolock below the HasAPIPermission() and 162 // GetTabSpecificPermissions(), since each already acquires the lock. 163 base::AutoLock auto_lock(runtime_lock_); 164 return tab_permissions.get() && tab_permissions->HasAPIPermission(permission); 165 } 166 167 bool PermissionsData::CheckAPIPermissionWithParam( 168 APIPermission::ID permission, 169 const APIPermission::CheckParam* param) const { 170 return active_permissions()->CheckAPIPermissionWithParam(permission, param); 171 } 172 173 const URLPatternSet& PermissionsData::GetEffectiveHostPermissions() const { 174 return active_permissions()->effective_hosts(); 175 } 176 177 bool PermissionsData::HasHostPermission(const GURL& url) const { 178 return active_permissions()->HasExplicitAccessToOrigin(url); 179 } 180 181 bool PermissionsData::HasEffectiveAccessToAllHosts() const { 182 return active_permissions()->HasEffectiveAccessToAllHosts(); 183 } 184 185 PermissionMessages PermissionsData::GetPermissionMessages() const { 186 if (ShouldSkipPermissionWarnings(extension_id_)) { 187 return PermissionMessages(); 188 } else { 189 return PermissionMessageProvider::Get()->GetPermissionMessages( 190 active_permissions().get(), manifest_type_); 191 } 192 } 193 194 std::vector<base::string16> PermissionsData::GetPermissionMessageStrings() 195 const { 196 if (ShouldSkipPermissionWarnings(extension_id_)) 197 return std::vector<base::string16>(); 198 return PermissionMessageProvider::Get()->GetWarningMessages( 199 active_permissions().get(), manifest_type_); 200 } 201 202 std::vector<base::string16> 203 PermissionsData::GetPermissionMessageDetailsStrings() const { 204 if (ShouldSkipPermissionWarnings(extension_id_)) 205 return std::vector<base::string16>(); 206 return PermissionMessageProvider::Get()->GetWarningMessagesDetails( 207 active_permissions().get(), manifest_type_); 208 } 209 210 bool PermissionsData::HasWithheldImpliedAllHosts() const { 211 // Since we currently only withhold all_hosts, it's sufficient to check 212 // that either set is not empty. 213 return !withheld_permissions()->explicit_hosts().is_empty() || 214 !withheld_permissions()->scriptable_hosts().is_empty(); 215 } 216 217 bool PermissionsData::CanAccessPage(const Extension* extension, 218 const GURL& document_url, 219 const GURL& top_frame_url, 220 int tab_id, 221 int process_id, 222 std::string* error) const { 223 AccessType result = CanRunOnPage(extension, 224 document_url, 225 top_frame_url, 226 tab_id, 227 process_id, 228 active_permissions()->explicit_hosts(), 229 withheld_permissions()->explicit_hosts(), 230 error); 231 // TODO(rdevlin.cronin) Update callers so that they only need ACCESS_ALLOWED. 232 return result == ACCESS_ALLOWED || result == ACCESS_WITHHELD; 233 } 234 235 PermissionsData::AccessType PermissionsData::GetPageAccess( 236 const Extension* extension, 237 const GURL& document_url, 238 const GURL& top_frame_url, 239 int tab_id, 240 int process_id, 241 std::string* error) const { 242 return CanRunOnPage(extension, 243 document_url, 244 top_frame_url, 245 tab_id, 246 process_id, 247 active_permissions()->explicit_hosts(), 248 withheld_permissions()->explicit_hosts(), 249 error); 250 } 251 252 bool PermissionsData::CanRunContentScriptOnPage(const Extension* extension, 253 const GURL& document_url, 254 const GURL& top_frame_url, 255 int tab_id, 256 int process_id, 257 std::string* error) const { 258 AccessType result = CanRunOnPage(extension, 259 document_url, 260 top_frame_url, 261 tab_id, 262 process_id, 263 active_permissions()->scriptable_hosts(), 264 withheld_permissions()->scriptable_hosts(), 265 error); 266 // TODO(rdevlin.cronin) Update callers so that they only need ACCESS_ALLOWED. 267 return result == ACCESS_ALLOWED || result == ACCESS_WITHHELD; 268 } 269 270 PermissionsData::AccessType PermissionsData::GetContentScriptAccess( 271 const Extension* extension, 272 const GURL& document_url, 273 const GURL& top_frame_url, 274 int tab_id, 275 int process_id, 276 std::string* error) const { 277 return CanRunOnPage(extension, 278 document_url, 279 top_frame_url, 280 tab_id, 281 process_id, 282 active_permissions()->scriptable_hosts(), 283 withheld_permissions()->scriptable_hosts(), 284 error); 285 } 286 287 bool PermissionsData::CanCaptureVisiblePage(int tab_id, 288 std::string* error) const { 289 const URLPattern all_urls(URLPattern::SCHEME_ALL, 290 URLPattern::kAllUrlsPattern); 291 292 if (active_permissions()->explicit_hosts().ContainsPattern(all_urls)) 293 return true; 294 295 if (tab_id >= 0) { 296 scoped_refptr<const PermissionSet> tab_permissions = 297 GetTabSpecificPermissions(tab_id); 298 if (tab_permissions.get() && 299 tab_permissions->HasAPIPermission(APIPermission::kTab)) { 300 return true; 301 } 302 if (error) 303 *error = manifest_errors::kActiveTabPermissionNotGranted; 304 return false; 305 } 306 307 if (error) 308 *error = manifest_errors::kAllURLOrActiveTabNeeded; 309 return false; 310 } 311 312 scoped_refptr<const PermissionSet> PermissionsData::GetTabSpecificPermissions( 313 int tab_id) const { 314 base::AutoLock auto_lock(runtime_lock_); 315 CHECK_GE(tab_id, 0); 316 TabPermissionsMap::const_iterator iter = 317 tab_specific_permissions_.find(tab_id); 318 return (iter != tab_specific_permissions_.end()) ? iter->second : NULL; 319 } 320 321 bool PermissionsData::HasTabSpecificPermissionToExecuteScript( 322 int tab_id, 323 const GURL& url) const { 324 if (tab_id >= 0) { 325 scoped_refptr<const PermissionSet> tab_permissions = 326 GetTabSpecificPermissions(tab_id); 327 if (tab_permissions.get() && 328 tab_permissions->explicit_hosts().MatchesSecurityOrigin(url)) { 329 return true; 330 } 331 } 332 return false; 333 } 334 335 PermissionsData::AccessType PermissionsData::CanRunOnPage( 336 const Extension* extension, 337 const GURL& document_url, 338 const GURL& top_frame_url, 339 int tab_id, 340 int process_id, 341 const URLPatternSet& permitted_url_patterns, 342 const URLPatternSet& withheld_url_patterns, 343 std::string* error) const { 344 if (g_policy_delegate && 345 !g_policy_delegate->CanExecuteScriptOnPage( 346 extension, document_url, top_frame_url, tab_id, process_id, error)) { 347 return ACCESS_DENIED; 348 } 349 350 if (IsRestrictedUrl(document_url, top_frame_url, extension, error)) 351 return ACCESS_DENIED; 352 353 if (HasTabSpecificPermissionToExecuteScript(tab_id, top_frame_url)) 354 return ACCESS_ALLOWED; 355 356 if (permitted_url_patterns.MatchesURL(document_url)) 357 return ACCESS_ALLOWED; 358 359 if (withheld_url_patterns.MatchesURL(document_url)) 360 return ACCESS_WITHHELD; 361 362 if (error) { 363 *error = ErrorUtils::FormatErrorMessage(manifest_errors::kCannotAccessPage, 364 document_url.spec()); 365 } 366 return ACCESS_DENIED; 367 } 368 369 } // namespace extensions 370