• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
PermissionsData(const Extension * extension)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 
~PermissionsData()43 PermissionsData::~PermissionsData() {
44 }
45 
46 // static
SetPolicyDelegate(PolicyDelegate * delegate)47 void PermissionsData::SetPolicyDelegate(PolicyDelegate* delegate) {
48   g_policy_delegate = delegate;
49 }
50 
51 // static
CanSilentlyIncreasePermissions(const Extension * extension)52 bool PermissionsData::CanSilentlyIncreasePermissions(
53     const Extension* extension) {
54   return extension->location() != Manifest::INTERNAL;
55 }
56 
57 // static
CanExecuteScriptEverywhere(const Extension * extension)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 
ShouldSkipPermissionWarnings(const std::string & extension_id)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
IsRestrictedUrl(const GURL & document_url,const GURL & top_frame_url,const Extension * extension,std::string * error)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 
SetPermissions(const scoped_refptr<const PermissionSet> & active,const scoped_refptr<const PermissionSet> & withheld) const116 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 
UpdateTabSpecificPermissions(int tab_id,scoped_refptr<const PermissionSet> permissions) const124 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 
ClearTabSpecificPermissions(int tab_id) const137 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 
HasAPIPermission(APIPermission::ID permission) const143 bool PermissionsData::HasAPIPermission(APIPermission::ID permission) const {
144   return active_permissions()->HasAPIPermission(permission);
145 }
146 
HasAPIPermission(const std::string & permission_name) const147 bool PermissionsData::HasAPIPermission(
148     const std::string& permission_name) const {
149   return active_permissions()->HasAPIPermission(permission_name);
150 }
151 
HasAPIPermissionForTab(int tab_id,APIPermission::ID permission) const152 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 
CheckAPIPermissionWithParam(APIPermission::ID permission,const APIPermission::CheckParam * param) const167 bool PermissionsData::CheckAPIPermissionWithParam(
168     APIPermission::ID permission,
169     const APIPermission::CheckParam* param) const {
170   return active_permissions()->CheckAPIPermissionWithParam(permission, param);
171 }
172 
GetEffectiveHostPermissions() const173 const URLPatternSet& PermissionsData::GetEffectiveHostPermissions() const {
174   return active_permissions()->effective_hosts();
175 }
176 
HasHostPermission(const GURL & url) const177 bool PermissionsData::HasHostPermission(const GURL& url) const {
178   return active_permissions()->HasExplicitAccessToOrigin(url);
179 }
180 
HasEffectiveAccessToAllHosts() const181 bool PermissionsData::HasEffectiveAccessToAllHosts() const {
182   return active_permissions()->HasEffectiveAccessToAllHosts();
183 }
184 
GetPermissionMessages() const185 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 
GetPermissionMessageStrings() const194 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>
GetPermissionMessageDetailsStrings() const203 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 
HasWithheldImpliedAllHosts() const210 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 
CanAccessPage(const Extension * extension,const GURL & document_url,const GURL & top_frame_url,int tab_id,int process_id,std::string * error) const217 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 
GetPageAccess(const Extension * extension,const GURL & document_url,const GURL & top_frame_url,int tab_id,int process_id,std::string * error) const235 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 
CanRunContentScriptOnPage(const Extension * extension,const GURL & document_url,const GURL & top_frame_url,int tab_id,int process_id,std::string * error) const252 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 
GetContentScriptAccess(const Extension * extension,const GURL & document_url,const GURL & top_frame_url,int tab_id,int process_id,std::string * error) const270 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 
CanCaptureVisiblePage(int tab_id,std::string * error) const287 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 
GetTabSpecificPermissions(int tab_id) const312 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 
HasTabSpecificPermissionToExecuteScript(int tab_id,const GURL & url) const321 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 
CanRunOnPage(const Extension * extension,const GURL & document_url,const GURL & top_frame_url,int tab_id,int process_id,const URLPatternSet & permitted_url_patterns,const URLPatternSet & withheld_url_patterns,std::string * error) const335 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