Home | History | Annotate | Download | only in permissions
      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