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 "base/memory/scoped_ptr.h" 9 #include "base/strings/string16.h" 10 #include "base/strings/string_number_conversions.h" 11 #include "base/strings/stringprintf.h" 12 #include "base/strings/utf_string_conversions.h" 13 #include "base/values.h" 14 #include "content/public/common/url_constants.h" 15 #include "extensions/common/constants.h" 16 #include "extensions/common/error_utils.h" 17 #include "extensions/common/extension.h" 18 #include "extensions/common/extensions_client.h" 19 #include "extensions/common/features/feature.h" 20 #include "extensions/common/features/feature_provider.h" 21 #include "extensions/common/manifest.h" 22 #include "extensions/common/manifest_constants.h" 23 #include "extensions/common/manifest_handler.h" 24 #include "extensions/common/permissions/api_permission_set.h" 25 #include "extensions/common/permissions/permission_message_provider.h" 26 #include "extensions/common/permissions/permission_set.h" 27 #include "extensions/common/permissions/permissions_info.h" 28 #include "extensions/common/switches.h" 29 #include "extensions/common/url_pattern_set.h" 30 #include "extensions/common/user_script.h" 31 #include "url/gurl.h" 32 33 namespace extensions { 34 35 namespace keys = manifest_keys; 36 namespace errors = manifest_errors; 37 38 namespace { 39 40 PermissionsData::PolicyDelegate* g_policy_delegate = NULL; 41 42 // Custom checks for the experimental permission that can't be expressed in 43 // _permission_features.json. 44 bool CanSpecifyExperimentalPermission(const Extension* extension) { 45 if (extension->location() == Manifest::COMPONENT) 46 return true; 47 48 if (CommandLine::ForCurrentProcess()->HasSwitch( 49 switches::kEnableExperimentalExtensionApis)) { 50 return true; 51 } 52 53 // We rely on the webstore to check access to experimental. This way we can 54 // whitelist extensions to have access to experimental in just the store, and 55 // not have to push a new version of the client. 56 if (extension->from_webstore()) 57 return true; 58 59 return false; 60 } 61 62 // Checks whether the host |pattern| is allowed for the given |extension|, 63 // given API permissions |permissions|. 64 bool CanSpecifyHostPermission(const Extension* extension, 65 const URLPattern& pattern, 66 const APIPermissionSet& permissions) { 67 if (!pattern.match_all_urls() && 68 pattern.MatchesScheme(chrome::kChromeUIScheme)) { 69 URLPatternSet chrome_scheme_hosts = ExtensionsClient::Get()-> 70 GetPermittedChromeSchemeHosts(extension, permissions); 71 if (chrome_scheme_hosts.ContainsPattern(pattern)) 72 return true; 73 74 // Component extensions can have access to all of chrome://*. 75 if (PermissionsData::CanExecuteScriptEverywhere(extension)) 76 return true; 77 78 if (CommandLine::ForCurrentProcess()->HasSwitch( 79 switches::kExtensionsOnChromeURLs)) { 80 return true; 81 } 82 83 // TODO(aboxhall): return from_webstore() when webstore handles blocking 84 // extensions which request chrome:// urls 85 return false; 86 } 87 88 // Otherwise, the valid schemes were handled by URLPattern. 89 return true; 90 } 91 92 // Parses the host and api permissions from the specified permission |key| 93 // from |extension|'s manifest. 94 bool ParseHelper(Extension* extension, 95 const char* key, 96 APIPermissionSet* api_permissions, 97 URLPatternSet* host_permissions, 98 string16* error) { 99 if (!extension->manifest()->HasKey(key)) 100 return true; 101 102 const base::ListValue* permissions = NULL; 103 if (!extension->manifest()->GetList(key, &permissions)) { 104 *error = ErrorUtils::FormatErrorMessageUTF16(errors::kInvalidPermissions, 105 std::string()); 106 return false; 107 } 108 109 // NOTE: We need to get the APIPermission before we check if features 110 // associated with them are available because the feature system does not 111 // know about aliases. 112 113 std::vector<std::string> host_data; 114 if (!APIPermissionSet::ParseFromJSON( 115 permissions, APIPermissionSet::kDisallowInternalPermissions, 116 api_permissions, error, &host_data)) { 117 return false; 118 } 119 120 // Verify feature availability of permissions. 121 std::vector<APIPermission::ID> to_remove; 122 FeatureProvider* permission_features = 123 FeatureProvider::GetPermissionFeatures(); 124 for (APIPermissionSet::const_iterator iter = api_permissions->begin(); 125 iter != api_permissions->end(); ++iter) { 126 Feature* feature = permission_features->GetFeature(iter->name()); 127 128 // The feature should exist since we just got an APIPermission for it. The 129 // two systems should be updated together whenever a permission is added. 130 DCHECK(feature); 131 // http://crbug.com/176381 132 if (!feature) { 133 to_remove.push_back(iter->id()); 134 continue; 135 } 136 137 Feature::Availability availability = feature->IsAvailableToManifest( 138 extension->id(), 139 extension->GetType(), 140 Feature::ConvertLocation(extension->location()), 141 extension->manifest_version()); 142 143 if (!availability.is_available()) { 144 // Don't fail, but warn the developer that the manifest contains 145 // unrecognized permissions. This may happen legitimately if the 146 // extensions requests platform- or channel-specific permissions. 147 extension->AddInstallWarning(InstallWarning(availability.message(), 148 feature->name())); 149 to_remove.push_back(iter->id()); 150 continue; 151 } 152 153 if (iter->id() == APIPermission::kExperimental) { 154 if (!CanSpecifyExperimentalPermission(extension)) { 155 *error = ASCIIToUTF16(errors::kExperimentalFlagRequired); 156 return false; 157 } 158 } 159 } 160 161 api_permissions->AddImpliedPermissions(); 162 163 // Remove permissions that are not available to this extension. 164 for (std::vector<APIPermission::ID>::const_iterator iter = to_remove.begin(); 165 iter != to_remove.end(); ++iter) { 166 api_permissions->erase(*iter); 167 } 168 169 // Parse host pattern permissions. 170 const int kAllowedSchemes = 171 PermissionsData::CanExecuteScriptEverywhere(extension) ? 172 URLPattern::SCHEME_ALL : Extension::kValidHostPermissionSchemes; 173 174 for (std::vector<std::string>::const_iterator iter = host_data.begin(); 175 iter != host_data.end(); ++iter) { 176 const std::string& permission_str = *iter; 177 178 // Check if it's a host pattern permission. 179 URLPattern pattern = URLPattern(kAllowedSchemes); 180 URLPattern::ParseResult parse_result = pattern.Parse(permission_str); 181 if (parse_result == URLPattern::PARSE_SUCCESS) { 182 // The path component is not used for host permissions, so we force it 183 // to match all paths. 184 pattern.SetPath("/*"); 185 int valid_schemes = pattern.valid_schemes(); 186 if (pattern.MatchesScheme(chrome::kFileScheme) && 187 !PermissionsData::CanExecuteScriptEverywhere(extension)) { 188 extension->set_wants_file_access(true); 189 if (!(extension->creation_flags() & Extension::ALLOW_FILE_ACCESS)) 190 valid_schemes &= ~URLPattern::SCHEME_FILE; 191 } 192 193 if (pattern.scheme() != chrome::kChromeUIScheme && 194 !PermissionsData::CanExecuteScriptEverywhere(extension)) { 195 // Keep chrome:// in allowed schemes only if it's explicitly requested 196 // or CanExecuteScriptEverywhere is true. If the 197 // extensions_on_chrome_urls flag is not set, CanSpecifyHostPermission 198 // will fail, so don't check the flag here. 199 valid_schemes &= ~URLPattern::SCHEME_CHROMEUI; 200 } 201 pattern.SetValidSchemes(valid_schemes); 202 203 if (!CanSpecifyHostPermission(extension, pattern, *api_permissions)) { 204 // TODO(aboxhall): make a warning (see pattern.match_all_urls() block 205 // below). 206 extension->AddInstallWarning(InstallWarning( 207 ErrorUtils::FormatErrorMessage( 208 errors::kInvalidPermissionScheme, permission_str), 209 key, 210 permission_str)); 211 continue; 212 } 213 214 host_permissions->AddPattern(pattern); 215 // We need to make sure all_urls matches chrome://favicon and (maybe) 216 // chrome://thumbnail, so add them back in to host_permissions separately. 217 if (pattern.match_all_urls()) { 218 host_permissions->AddPatterns( 219 ExtensionsClient::Get()->GetPermittedChromeSchemeHosts( 220 extension, *api_permissions)); 221 } 222 continue; 223 } 224 225 // It's probably an unknown API permission. Do not throw an error so 226 // extensions can retain backwards compatability (http://crbug.com/42742). 227 extension->AddInstallWarning(InstallWarning( 228 ErrorUtils::FormatErrorMessage( 229 manifest_errors::kPermissionUnknownOrMalformed, 230 permission_str), 231 key, 232 permission_str)); 233 } 234 235 return true; 236 } 237 238 // Returns true if this extension id is from a trusted provider. 239 bool IsTrustedId(const std::string& extension_id) { 240 // See http://b/4946060 for more details. 241 return extension_id == std::string("nckgahadagoaajjgafhacjanaoiihapd"); 242 } 243 244 } // namespace 245 246 struct PermissionsData::InitialPermissions { 247 APIPermissionSet api_permissions; 248 ManifestPermissionSet manifest_permissions; 249 URLPatternSet host_permissions; 250 URLPatternSet scriptable_hosts; 251 }; 252 253 PermissionsData::PermissionsData() { 254 } 255 256 PermissionsData::~PermissionsData() { 257 } 258 259 // static 260 void PermissionsData::SetPolicyDelegate(PolicyDelegate* delegate) { 261 g_policy_delegate = delegate; 262 } 263 264 // static 265 const PermissionSet* PermissionsData::GetOptionalPermissions( 266 const Extension* extension) { 267 return extension->permissions_data()->optional_permission_set_.get(); 268 } 269 270 // static 271 const PermissionSet* PermissionsData::GetRequiredPermissions( 272 const Extension* extension) { 273 return extension->permissions_data()->required_permission_set_.get(); 274 } 275 276 // static 277 const APIPermissionSet* PermissionsData::GetInitialAPIPermissions( 278 const Extension* extension) { 279 return &extension->permissions_data()-> 280 initial_required_permissions_->api_permissions; 281 } 282 283 // static 284 APIPermissionSet* PermissionsData::GetInitialAPIPermissions( 285 Extension* extension) { 286 return &extension->permissions_data()-> 287 initial_required_permissions_->api_permissions; 288 } 289 290 // static 291 void PermissionsData::SetInitialScriptableHosts( 292 Extension* extension, const URLPatternSet& scriptable_hosts) { 293 extension->permissions_data()-> 294 initial_required_permissions_->scriptable_hosts = scriptable_hosts; 295 } 296 297 // static 298 void PermissionsData::SetActivePermissions(const Extension* extension, 299 const PermissionSet* permissions) { 300 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_); 301 extension->permissions_data()->active_permissions_ = permissions; 302 } 303 304 // static 305 scoped_refptr<const PermissionSet> PermissionsData::GetActivePermissions( 306 const Extension* extension) { 307 return extension->permissions_data()->active_permissions_; 308 } 309 310 // static 311 scoped_refptr<const PermissionSet> PermissionsData::GetTabSpecificPermissions( 312 const Extension* extension, 313 int tab_id) { 314 CHECK_GE(tab_id, 0); 315 TabPermissionsMap::const_iterator iter = 316 extension->permissions_data()->tab_specific_permissions_.find(tab_id); 317 return 318 (iter != extension->permissions_data()->tab_specific_permissions_.end()) 319 ? iter->second 320 : NULL; 321 } 322 323 // static 324 void PermissionsData::UpdateTabSpecificPermissions( 325 const Extension* extension, 326 int tab_id, 327 scoped_refptr<const PermissionSet> permissions) { 328 CHECK_GE(tab_id, 0); 329 TabPermissionsMap* tab_permissions = 330 &extension->permissions_data()->tab_specific_permissions_; 331 if (tab_permissions->count(tab_id)) { 332 (*tab_permissions)[tab_id] = PermissionSet::CreateUnion( 333 (*tab_permissions)[tab_id].get(), permissions.get()); 334 } else { 335 (*tab_permissions)[tab_id] = permissions; 336 } 337 } 338 339 // static 340 void PermissionsData::ClearTabSpecificPermissions( 341 const Extension* extension, 342 int tab_id) { 343 CHECK_GE(tab_id, 0); 344 extension->permissions_data()->tab_specific_permissions_.erase(tab_id); 345 } 346 347 // static 348 bool PermissionsData::HasAPIPermission(const Extension* extension, 349 APIPermission::ID permission) { 350 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_); 351 return GetActivePermissions(extension)->HasAPIPermission(permission); 352 } 353 354 // static 355 bool PermissionsData::HasAPIPermission( 356 const Extension* extension, 357 const std::string& permission_name) { 358 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_); 359 return GetActivePermissions(extension)->HasAPIPermission(permission_name); 360 } 361 362 // static 363 bool PermissionsData::HasAPIPermissionForTab( 364 const Extension* extension, 365 int tab_id, 366 APIPermission::ID permission) { 367 if (HasAPIPermission(extension, permission)) 368 return true; 369 370 // Place autolock below the HasAPIPermission() check, since HasAPIPermission 371 // also acquires the lock. 372 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_); 373 scoped_refptr<const PermissionSet> tab_permissions = 374 GetTabSpecificPermissions(extension, tab_id); 375 return tab_permissions.get() && tab_permissions->HasAPIPermission(permission); 376 } 377 378 // static 379 bool PermissionsData::CheckAPIPermissionWithParam( 380 const Extension* extension, 381 APIPermission::ID permission, 382 const APIPermission::CheckParam* param) { 383 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_); 384 return GetActivePermissions(extension)->CheckAPIPermissionWithParam( 385 permission, param); 386 } 387 388 // static 389 const URLPatternSet& PermissionsData::GetEffectiveHostPermissions( 390 const Extension* extension) { 391 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_); 392 return GetActivePermissions(extension)->effective_hosts(); 393 } 394 395 // static 396 bool PermissionsData::CanSilentlyIncreasePermissions( 397 const Extension* extension) { 398 return extension->location() != Manifest::INTERNAL; 399 } 400 401 // static 402 bool PermissionsData::ShouldSkipPermissionWarnings(const Extension* extension) { 403 return IsTrustedId(extension->id()); 404 } 405 406 // static 407 bool PermissionsData::HasHostPermission(const Extension* extension, 408 const GURL& url) { 409 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_); 410 return GetActivePermissions(extension)->HasExplicitAccessToOrigin(url); 411 } 412 413 // static 414 bool PermissionsData::HasEffectiveAccessToAllHosts(const Extension* extension) { 415 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_); 416 return GetActivePermissions(extension)->HasEffectiveAccessToAllHosts(); 417 } 418 419 // static 420 PermissionMessages PermissionsData::GetPermissionMessages( 421 const Extension* extension) { 422 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_); 423 if (ShouldSkipPermissionWarnings(extension)) { 424 return PermissionMessages(); 425 } else { 426 return PermissionMessageProvider::Get()->GetPermissionMessages( 427 GetActivePermissions(extension), extension->GetType()); 428 } 429 } 430 431 // static 432 std::vector<string16> PermissionsData::GetPermissionMessageStrings( 433 const Extension* extension) { 434 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_); 435 if (ShouldSkipPermissionWarnings(extension)) { 436 return std::vector<string16>(); 437 } else { 438 return PermissionMessageProvider::Get()->GetWarningMessages( 439 GetActivePermissions(extension), extension->GetType()); 440 } 441 } 442 443 // static 444 std::vector<string16> PermissionsData::GetPermissionMessageDetailsStrings( 445 const Extension* extension) { 446 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_); 447 if (ShouldSkipPermissionWarnings(extension)) { 448 return std::vector<string16>(); 449 } else { 450 return PermissionMessageProvider::Get()->GetWarningMessagesDetails( 451 GetActivePermissions(extension), extension->GetType()); 452 } 453 } 454 455 // static 456 bool PermissionsData::CanExecuteScriptOnPage(const Extension* extension, 457 const GURL& document_url, 458 const GURL& top_frame_url, 459 int tab_id, 460 const UserScript* script, 461 int process_id, 462 std::string* error) { 463 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_); 464 const CommandLine* command_line = CommandLine::ForCurrentProcess(); 465 bool can_execute_everywhere = CanExecuteScriptEverywhere(extension); 466 467 if (g_policy_delegate && 468 !g_policy_delegate->CanExecuteScriptOnPage( 469 extension, document_url, top_frame_url, tab_id, 470 script, process_id, error)) 471 return false; 472 473 if (!can_execute_everywhere && 474 !ExtensionsClient::Get()->IsScriptableURL(document_url, error)) { 475 return false; 476 } 477 478 if (!command_line->HasSwitch(switches::kExtensionsOnChromeURLs)) { 479 if (document_url.SchemeIs(chrome::kChromeUIScheme) && 480 !can_execute_everywhere) { 481 if (error) 482 *error = errors::kCannotAccessChromeUrl; 483 return false; 484 } 485 } 486 487 if (top_frame_url.SchemeIs(extensions::kExtensionScheme) && 488 top_frame_url.GetOrigin() != 489 Extension::GetBaseURLFromExtensionId(extension->id()).GetOrigin() && 490 !can_execute_everywhere) { 491 if (error) 492 *error = errors::kCannotAccessExtensionUrl; 493 return false; 494 } 495 496 // If a tab ID is specified, try the tab-specific permissions. 497 if (tab_id >= 0) { 498 scoped_refptr<const PermissionSet> tab_permissions = 499 GetTabSpecificPermissions(extension, tab_id); 500 if (tab_permissions.get() && 501 tab_permissions->explicit_hosts().MatchesSecurityOrigin(document_url)) { 502 return true; 503 } 504 } 505 506 bool can_access = false; 507 508 if (script) { 509 // If a script is specified, use its matches. 510 can_access = script->MatchesURL(document_url); 511 } else { 512 // Otherwise, see if this extension has permission to execute script 513 // programmatically on pages. 514 can_access = GetActivePermissions(extension)-> 515 HasExplicitAccessToOrigin(document_url); 516 } 517 518 if (!can_access && error) { 519 *error = ErrorUtils::FormatErrorMessage(errors::kCannotAccessPage, 520 document_url.spec()); 521 } 522 523 return can_access; 524 } 525 526 // static 527 bool PermissionsData::CanExecuteScriptEverywhere(const Extension* extension) { 528 if (extension->location() == Manifest::COMPONENT) 529 return true; 530 531 const ExtensionsClient::ScriptingWhitelist& whitelist = 532 ExtensionsClient::Get()->GetScriptingWhitelist(); 533 534 return std::find(whitelist.begin(), whitelist.end(), extension->id()) != 535 whitelist.end(); 536 } 537 538 // static 539 bool PermissionsData::CanCaptureVisiblePage(const Extension* extension, 540 const GURL& page_url, 541 int tab_id, 542 std::string* error) { 543 if (tab_id >= 0) { 544 scoped_refptr<const PermissionSet> tab_permissions = 545 GetTabSpecificPermissions(extension, tab_id); 546 if (tab_permissions.get() && 547 tab_permissions->explicit_hosts().MatchesSecurityOrigin(page_url)) { 548 return true; 549 } 550 } 551 552 if (HasHostPermission(extension, page_url) || 553 page_url.GetOrigin() == extension->url()) { 554 return true; 555 } 556 557 if (error) { 558 *error = ErrorUtils::FormatErrorMessage(errors::kCannotAccessPage, 559 page_url.spec()); 560 } 561 return false; 562 } 563 564 bool PermissionsData::ParsePermissions(Extension* extension, string16* error) { 565 initial_required_permissions_.reset(new InitialPermissions); 566 if (!ParseHelper(extension, 567 keys::kPermissions, 568 &initial_required_permissions_->api_permissions, 569 &initial_required_permissions_->host_permissions, 570 error)) { 571 return false; 572 } 573 574 // TODO(jeremya/kalman) do this via the features system by exposing the 575 // app.window API to platform apps, with no dependency on any permissions. 576 // See http://crbug.com/120069. 577 if (extension->is_platform_app()) { 578 initial_required_permissions_->api_permissions.insert( 579 APIPermission::kAppCurrentWindowInternal); 580 initial_required_permissions_->api_permissions.insert( 581 APIPermission::kAppRuntime); 582 initial_required_permissions_->api_permissions.insert( 583 APIPermission::kAppWindow); 584 } 585 586 initial_optional_permissions_.reset(new InitialPermissions); 587 if (!ParseHelper(extension, 588 keys::kOptionalPermissions, 589 &initial_optional_permissions_->api_permissions, 590 &initial_optional_permissions_->host_permissions, 591 error)) { 592 return false; 593 } 594 595 return true; 596 } 597 598 void PermissionsData::InitializeManifestPermissions(Extension* extension) { 599 ManifestHandler::AddExtensionInitialRequiredPermissions( 600 extension, &initial_required_permissions_->manifest_permissions); 601 } 602 603 void PermissionsData::FinalizePermissions(Extension* extension) { 604 active_permissions_ = new PermissionSet( 605 initial_required_permissions_->api_permissions, 606 initial_required_permissions_->manifest_permissions, 607 initial_required_permissions_->host_permissions, 608 initial_required_permissions_->scriptable_hosts); 609 610 required_permission_set_ = new PermissionSet( 611 initial_required_permissions_->api_permissions, 612 initial_required_permissions_->manifest_permissions, 613 initial_required_permissions_->host_permissions, 614 initial_required_permissions_->scriptable_hosts); 615 616 optional_permission_set_ = new PermissionSet( 617 initial_optional_permissions_->api_permissions, 618 initial_optional_permissions_->manifest_permissions, 619 initial_optional_permissions_->host_permissions, 620 URLPatternSet()); 621 622 initial_required_permissions_.reset(); 623 initial_optional_permissions_.reset(); 624 } 625 626 } // namespace extensions 627