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