- add sources.
[platform/framework/web/crosswalk.git] / src / content / browser / child_process_security_policy_impl.cc
1 // Copyright (c) 2012 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 "content/browser/child_process_security_policy_impl.h"
6
7 #include "base/command_line.h"
8 #include "base/files/file_path.h"
9 #include "base/logging.h"
10 #include "base/metrics/histogram.h"
11 #include "base/platform_file.h"
12 #include "base/stl_util.h"
13 #include "base/strings/string_util.h"
14 #include "content/browser/plugin_process_host.h"
15 #include "content/browser/site_instance_impl.h"
16 #include "content/public/browser/child_process_data.h"
17 #include "content/public/browser/content_browser_client.h"
18 #include "content/public/browser/render_process_host.h"
19 #include "content/public/common/bindings_policy.h"
20 #include "content/public/common/content_switches.h"
21 #include "content/public/common/url_constants.h"
22 #include "net/base/net_util.h"
23 #include "net/url_request/url_request.h"
24 #include "url/gurl.h"
25 #include "webkit/browser/fileapi/file_permission_policy.h"
26 #include "webkit/browser/fileapi/file_system_url.h"
27 #include "webkit/browser/fileapi/isolated_context.h"
28 #include "webkit/common/fileapi/file_system_util.h"
29
30 namespace content {
31
32 namespace {
33
34 // Used internally only. These bit positions have no relationship to any
35 // underlying OS and can be changed to accommodate finer-grained permissions.
36 enum ChildProcessSecurityPermissions {
37   READ_FILE_PERMISSION             = 1 << 0,
38   WRITE_FILE_PERMISSION            = 1 << 1,
39   CREATE_NEW_FILE_PERMISSION       = 1 << 2,
40   CREATE_OVERWRITE_FILE_PERMISSION = 1 << 3,
41   DELETE_FILE_PERMISSION           = 1 << 4,
42
43   // Used by Media Galleries API
44   COPY_INTO_FILE_PERMISSION        = 1 << 5,
45 };
46
47 // Used internally only. Bitmasks that are actually used by the Grant* and Can*
48 // methods. These contain one or more ChildProcessSecurityPermissions.
49 enum ChildProcessSecurityGrants {
50   READ_FILE_GRANT              = READ_FILE_PERMISSION,
51   WRITE_FILE_GRANT             = WRITE_FILE_PERMISSION,
52
53   CREATE_NEW_FILE_GRANT        = CREATE_NEW_FILE_PERMISSION |
54                                  COPY_INTO_FILE_PERMISSION,
55
56   CREATE_READ_WRITE_FILE_GRANT = CREATE_NEW_FILE_PERMISSION |
57                                  CREATE_OVERWRITE_FILE_PERMISSION |
58                                  READ_FILE_PERMISSION |
59                                  WRITE_FILE_PERMISSION |
60                                  COPY_INTO_FILE_PERMISSION |
61                                  DELETE_FILE_PERMISSION,
62
63   COPY_INTO_FILE_GRANT         = COPY_INTO_FILE_PERMISSION,
64   DELETE_FILE_GRANT            = DELETE_FILE_PERMISSION,
65 };
66
67 }  // namespace
68
69 // The SecurityState class is used to maintain per-child process security state
70 // information.
71 class ChildProcessSecurityPolicyImpl::SecurityState {
72  public:
73   SecurityState()
74     : enabled_bindings_(0),
75       can_read_raw_cookies_(false),
76       can_send_midi_sysex_(false) { }
77
78   ~SecurityState() {
79     scheme_policy_.clear();
80     fileapi::IsolatedContext* isolated_context =
81         fileapi::IsolatedContext::GetInstance();
82     for (FileSystemMap::iterator iter = filesystem_permissions_.begin();
83          iter != filesystem_permissions_.end();
84          ++iter) {
85       isolated_context->RemoveReference(iter->first);
86     }
87     UMA_HISTOGRAM_COUNTS("ChildProcessSecurityPolicy.PerChildFilePermissions",
88                          file_permissions_.size());
89   }
90
91   // Grant permission to request URLs with the specified scheme.
92   void GrantScheme(const std::string& scheme) {
93     scheme_policy_[scheme] = true;
94   }
95
96   // Revoke permission to request URLs with the specified scheme.
97   void RevokeScheme(const std::string& scheme) {
98     scheme_policy_[scheme] = false;
99   }
100
101   // Grant certain permissions to a file.
102   void GrantPermissionsForFile(const base::FilePath& file, int permissions) {
103     base::FilePath stripped = file.StripTrailingSeparators();
104     file_permissions_[stripped] |= permissions;
105     UMA_HISTOGRAM_COUNTS("ChildProcessSecurityPolicy.FilePermissionPathLength",
106                          stripped.value().size());
107   }
108
109   // Grant navigation to a file but not the file:// scheme in general.
110   void GrantRequestOfSpecificFile(const base::FilePath &file) {
111     request_file_set_.insert(file.StripTrailingSeparators());
112   }
113
114   // Revokes all permissions granted to a file.
115   void RevokeAllPermissionsForFile(const base::FilePath& file) {
116     base::FilePath stripped = file.StripTrailingSeparators();
117     file_permissions_.erase(stripped);
118     request_file_set_.erase(stripped);
119   }
120
121   // Grant certain permissions to a file.
122   void GrantPermissionsForFileSystem(const std::string& filesystem_id,
123                                      int permissions) {
124     if (!ContainsKey(filesystem_permissions_, filesystem_id))
125       fileapi::IsolatedContext::GetInstance()->AddReference(filesystem_id);
126     filesystem_permissions_[filesystem_id] |= permissions;
127   }
128
129   bool HasPermissionsForFileSystem(const std::string& filesystem_id,
130                                    int permissions) {
131     FileSystemMap::const_iterator it =
132         filesystem_permissions_.find(filesystem_id);
133     if (it == filesystem_permissions_.end())
134       return false;
135     return (it->second & permissions) == permissions;
136   }
137
138   void GrantBindings(int bindings) {
139     enabled_bindings_ |= bindings;
140   }
141
142   void GrantReadRawCookies() {
143     can_read_raw_cookies_ = true;
144   }
145
146   void RevokeReadRawCookies() {
147     can_read_raw_cookies_ = false;
148   }
149
150   void GrantPermissionForMIDISysEx() {
151     can_send_midi_sysex_ = true;
152   }
153
154   // Determine whether permission has been granted to request |url|.
155   bool CanRequestURL(const GURL& url) {
156     // Having permission to a scheme implies permssion to all of its URLs.
157     SchemeMap::const_iterator judgment(scheme_policy_.find(url.scheme()));
158     if (judgment != scheme_policy_.end())
159       return judgment->second;
160
161     // file:// URLs are more granular.  The child may have been given
162     // permission to a specific file but not the file:// scheme in general.
163     if (url.SchemeIs(chrome::kFileScheme)) {
164       base::FilePath path;
165       if (net::FileURLToFilePath(url, &path))
166         return ContainsKey(request_file_set_, path);
167     }
168
169     return false;  // Unmentioned schemes are disallowed.
170   }
171
172   // Determine if the certain permissions have been granted to a file.
173   bool HasPermissionsForFile(const base::FilePath& file, int permissions) {
174     if (!permissions || file.empty() || !file.IsAbsolute())
175       return false;
176     base::FilePath current_path = file.StripTrailingSeparators();
177     base::FilePath last_path;
178     int skip = 0;
179     while (current_path != last_path) {
180       base::FilePath base_name = current_path.BaseName();
181       if (base_name.value() == base::FilePath::kParentDirectory) {
182         ++skip;
183       } else if (skip > 0) {
184         if (base_name.value() != base::FilePath::kCurrentDirectory)
185           --skip;
186       } else {
187         FileMap::const_iterator it = file_permissions_.find(current_path);
188         if (it != file_permissions_.end())
189           return (it->second & permissions) == permissions;
190       }
191       last_path = current_path;
192       current_path = current_path.DirName();
193     }
194
195     return false;
196   }
197
198   bool CanLoadPage(const GURL& gurl) {
199     if (origin_lock_.is_empty())
200       return true;
201
202     // TODO(creis): We must pass the valid browser_context to convert hosted
203     // apps URLs.  Currently, hosted apps cannot be loaded in this mode.
204     // See http://crbug.com/160576.
205     GURL site_gurl = SiteInstanceImpl::GetSiteForURL(NULL, gurl);
206     return origin_lock_ == site_gurl;
207   }
208
209   bool CanAccessCookiesForOrigin(const GURL& gurl) {
210     if (origin_lock_.is_empty())
211       return true;
212     // TODO(creis): We must pass the valid browser_context to convert hosted
213     // apps URLs.  Currently, hosted apps cannot set cookies in this mode.
214     // See http://crbug.com/160576.
215     GURL site_gurl = SiteInstanceImpl::GetSiteForURL(NULL, gurl);
216     return origin_lock_ == site_gurl;
217   }
218
219   bool CanSendCookiesForOrigin(const GURL& gurl) {
220     // We only block cross-site cookies on network requests if the
221     // --enable-strict-site-isolation flag is passed.  This is expected to break
222     // compatibility with many sites.  The similar --site-per-process flag only
223     // blocks JavaScript access to cross-site cookies (in
224     // CanAccessCookiesForOrigin).
225     const CommandLine& command_line = *CommandLine::ForCurrentProcess();
226     if (!command_line.HasSwitch(switches::kEnableStrictSiteIsolation))
227       return true;
228
229     if (origin_lock_.is_empty())
230       return true;
231     // TODO(creis): We must pass the valid browser_context to convert hosted
232     // apps URLs.  Currently, hosted apps cannot set cookies in this mode.
233     // See http://crbug.com/160576.
234     GURL site_gurl = SiteInstanceImpl::GetSiteForURL(NULL, gurl);
235     return origin_lock_ == site_gurl;
236   }
237
238   void LockToOrigin(const GURL& gurl) {
239     origin_lock_ = gurl;
240   }
241
242   bool has_web_ui_bindings() const {
243     return enabled_bindings_ & BINDINGS_POLICY_WEB_UI;
244   }
245
246   bool can_read_raw_cookies() const {
247     return can_read_raw_cookies_;
248   }
249
250   bool can_send_midi_sysex() const {
251     return can_send_midi_sysex_;
252   }
253
254  private:
255   typedef std::map<std::string, bool> SchemeMap;
256
257   typedef int FilePermissionFlags;  // bit-set of PlatformFileFlags
258   typedef std::map<base::FilePath, FilePermissionFlags> FileMap;
259   typedef std::map<std::string, FilePermissionFlags> FileSystemMap;
260   typedef std::set<base::FilePath> FileSet;
261
262   // Maps URL schemes to whether permission has been granted or revoked:
263   //   |true| means the scheme has been granted.
264   //   |false| means the scheme has been revoked.
265   // If a scheme is not present in the map, then it has never been granted
266   // or revoked.
267   SchemeMap scheme_policy_;
268
269   // The set of files the child process is permited to upload to the web.
270   FileMap file_permissions_;
271
272   // The set of files the child process is permitted to load.
273   FileSet request_file_set_;
274
275   int enabled_bindings_;
276
277   bool can_read_raw_cookies_;
278
279   bool can_send_midi_sysex_;
280
281   GURL origin_lock_;
282
283   // The set of isolated filesystems the child process is permitted to access.
284   FileSystemMap filesystem_permissions_;
285
286   DISALLOW_COPY_AND_ASSIGN(SecurityState);
287 };
288
289 ChildProcessSecurityPolicyImpl::ChildProcessSecurityPolicyImpl() {
290   // We know about these schemes and believe them to be safe.
291   RegisterWebSafeScheme(kHttpScheme);
292   RegisterWebSafeScheme(kHttpsScheme);
293   RegisterWebSafeScheme(chrome::kFtpScheme);
294   RegisterWebSafeScheme(chrome::kDataScheme);
295   RegisterWebSafeScheme("feed");
296   RegisterWebSafeScheme(chrome::kBlobScheme);
297   RegisterWebSafeScheme(chrome::kFileSystemScheme);
298
299   // We know about the following pseudo schemes and treat them specially.
300   RegisterPseudoScheme(chrome::kAboutScheme);
301   RegisterPseudoScheme(kJavaScriptScheme);
302   RegisterPseudoScheme(kViewSourceScheme);
303 }
304
305 ChildProcessSecurityPolicyImpl::~ChildProcessSecurityPolicyImpl() {
306   web_safe_schemes_.clear();
307   pseudo_schemes_.clear();
308   STLDeleteContainerPairSecondPointers(security_state_.begin(),
309                                        security_state_.end());
310   security_state_.clear();
311 }
312
313 // static
314 ChildProcessSecurityPolicy* ChildProcessSecurityPolicy::GetInstance() {
315   return ChildProcessSecurityPolicyImpl::GetInstance();
316 }
317
318 ChildProcessSecurityPolicyImpl* ChildProcessSecurityPolicyImpl::GetInstance() {
319   return Singleton<ChildProcessSecurityPolicyImpl>::get();
320 }
321
322 void ChildProcessSecurityPolicyImpl::Add(int child_id) {
323   base::AutoLock lock(lock_);
324   AddChild(child_id);
325 }
326
327 void ChildProcessSecurityPolicyImpl::AddWorker(int child_id,
328                                                int main_render_process_id) {
329   base::AutoLock lock(lock_);
330   AddChild(child_id);
331   worker_map_[child_id] = main_render_process_id;
332 }
333
334 void ChildProcessSecurityPolicyImpl::Remove(int child_id) {
335   base::AutoLock lock(lock_);
336   SecurityStateMap::iterator it = security_state_.find(child_id);
337   if (it == security_state_.end())
338     return;  // May be called multiple times.
339
340   delete it->second;
341   security_state_.erase(it);
342   worker_map_.erase(child_id);
343 }
344
345 void ChildProcessSecurityPolicyImpl::RegisterWebSafeScheme(
346     const std::string& scheme) {
347   base::AutoLock lock(lock_);
348   DCHECK_EQ(0U, web_safe_schemes_.count(scheme)) << "Add schemes at most once.";
349   DCHECK_EQ(0U, pseudo_schemes_.count(scheme))
350       << "Web-safe implies not pseudo.";
351
352   web_safe_schemes_.insert(scheme);
353 }
354
355 bool ChildProcessSecurityPolicyImpl::IsWebSafeScheme(
356     const std::string& scheme) {
357   base::AutoLock lock(lock_);
358
359   return ContainsKey(web_safe_schemes_, scheme);
360 }
361
362 void ChildProcessSecurityPolicyImpl::RegisterPseudoScheme(
363     const std::string& scheme) {
364   base::AutoLock lock(lock_);
365   DCHECK_EQ(0U, pseudo_schemes_.count(scheme)) << "Add schemes at most once.";
366   DCHECK_EQ(0U, web_safe_schemes_.count(scheme))
367       << "Pseudo implies not web-safe.";
368
369   pseudo_schemes_.insert(scheme);
370 }
371
372 bool ChildProcessSecurityPolicyImpl::IsPseudoScheme(
373     const std::string& scheme) {
374   base::AutoLock lock(lock_);
375
376   return ContainsKey(pseudo_schemes_, scheme);
377 }
378
379 void ChildProcessSecurityPolicyImpl::GrantRequestURL(
380     int child_id, const GURL& url) {
381
382   if (!url.is_valid())
383     return;  // Can't grant the capability to request invalid URLs.
384
385   if (IsWebSafeScheme(url.scheme()))
386     return;  // The scheme has already been whitelisted for every child process.
387
388   if (IsPseudoScheme(url.scheme())) {
389     // The view-source scheme is a special case of a pseudo-URL that eventually
390     // results in requesting its embedded URL.
391     if (url.SchemeIs(kViewSourceScheme)) {
392       // URLs with the view-source scheme typically look like:
393       //   view-source:http://www.google.com/a
394       // In order to request these URLs, the child_id needs to be able to
395       // request the embedded URL.
396       GrantRequestURL(child_id, GURL(url.GetContent()));
397     }
398
399     return;  // Can't grant the capability to request pseudo schemes.
400   }
401
402   {
403     base::AutoLock lock(lock_);
404     SecurityStateMap::iterator state = security_state_.find(child_id);
405     if (state == security_state_.end())
406       return;
407
408     // When the child process has been commanded to request this scheme,
409     // we grant it the capability to request all URLs of that scheme.
410     state->second->GrantScheme(url.scheme());
411   }
412 }
413
414 void ChildProcessSecurityPolicyImpl::GrantRequestSpecificFileURL(
415     int child_id,
416     const GURL& url) {
417   if (!url.SchemeIs(chrome::kFileScheme))
418     return;
419
420   {
421     base::AutoLock lock(lock_);
422     SecurityStateMap::iterator state = security_state_.find(child_id);
423     if (state == security_state_.end())
424       return;
425
426     // When the child process has been commanded to request a file:// URL,
427     // then we grant it the capability for that URL only.
428     base::FilePath path;
429     if (net::FileURLToFilePath(url, &path))
430       state->second->GrantRequestOfSpecificFile(path);
431   }
432 }
433
434 void ChildProcessSecurityPolicyImpl::GrantReadFile(int child_id,
435                                                    const base::FilePath& file) {
436   GrantPermissionsForFile(child_id, file, READ_FILE_GRANT);
437 }
438
439 void ChildProcessSecurityPolicyImpl::GrantCreateReadWriteFile(
440     int child_id, const base::FilePath& file) {
441   GrantPermissionsForFile(child_id, file, CREATE_READ_WRITE_FILE_GRANT);
442 }
443
444 void ChildProcessSecurityPolicyImpl::GrantPermissionsForFile(
445     int child_id, const base::FilePath& file, int permissions) {
446   base::AutoLock lock(lock_);
447
448   SecurityStateMap::iterator state = security_state_.find(child_id);
449   if (state == security_state_.end())
450     return;
451
452   state->second->GrantPermissionsForFile(file, permissions);
453 }
454
455 void ChildProcessSecurityPolicyImpl::RevokeAllPermissionsForFile(
456     int child_id, const base::FilePath& file) {
457   base::AutoLock lock(lock_);
458
459   SecurityStateMap::iterator state = security_state_.find(child_id);
460   if (state == security_state_.end())
461     return;
462
463   state->second->RevokeAllPermissionsForFile(file);
464 }
465
466 void ChildProcessSecurityPolicyImpl::GrantReadFileSystem(
467     int child_id, const std::string& filesystem_id) {
468   GrantPermissionsForFileSystem(child_id, filesystem_id, READ_FILE_GRANT);
469 }
470
471 void ChildProcessSecurityPolicyImpl::GrantWriteFileSystem(
472     int child_id, const std::string& filesystem_id) {
473   GrantPermissionsForFileSystem(child_id, filesystem_id, WRITE_FILE_GRANT);
474 }
475
476 void ChildProcessSecurityPolicyImpl::GrantCreateFileForFileSystem(
477     int child_id, const std::string& filesystem_id) {
478   GrantPermissionsForFileSystem(child_id, filesystem_id, CREATE_NEW_FILE_GRANT);
479 }
480
481 void ChildProcessSecurityPolicyImpl::GrantCopyIntoFileSystem(
482     int child_id, const std::string& filesystem_id) {
483   GrantPermissionsForFileSystem(child_id, filesystem_id, COPY_INTO_FILE_GRANT);
484 }
485
486 void ChildProcessSecurityPolicyImpl::GrantDeleteFromFileSystem(
487     int child_id, const std::string& filesystem_id) {
488   GrantPermissionsForFileSystem(child_id, filesystem_id, DELETE_FILE_GRANT);
489 }
490
491 void ChildProcessSecurityPolicyImpl::GrantSendMIDISysExMessage(int child_id) {
492   base::AutoLock lock(lock_);
493
494   SecurityStateMap::iterator state = security_state_.find(child_id);
495   if (state == security_state_.end())
496     return;
497
498   state->second->GrantPermissionForMIDISysEx();
499 }
500
501 void ChildProcessSecurityPolicyImpl::GrantScheme(int child_id,
502                                                  const std::string& scheme) {
503   base::AutoLock lock(lock_);
504
505   SecurityStateMap::iterator state = security_state_.find(child_id);
506   if (state == security_state_.end())
507     return;
508
509   state->second->GrantScheme(scheme);
510 }
511
512 void ChildProcessSecurityPolicyImpl::GrantWebUIBindings(int child_id) {
513   base::AutoLock lock(lock_);
514
515   SecurityStateMap::iterator state = security_state_.find(child_id);
516   if (state == security_state_.end())
517     return;
518
519   state->second->GrantBindings(BINDINGS_POLICY_WEB_UI);
520
521   // Web UI bindings need the ability to request chrome: URLs.
522   state->second->GrantScheme(chrome::kChromeUIScheme);
523
524   // Web UI pages can contain links to file:// URLs.
525   state->second->GrantScheme(chrome::kFileScheme);
526 }
527
528 void ChildProcessSecurityPolicyImpl::GrantReadRawCookies(int child_id) {
529   base::AutoLock lock(lock_);
530
531   SecurityStateMap::iterator state = security_state_.find(child_id);
532   if (state == security_state_.end())
533     return;
534
535   state->second->GrantReadRawCookies();
536 }
537
538 void ChildProcessSecurityPolicyImpl::RevokeReadRawCookies(int child_id) {
539   base::AutoLock lock(lock_);
540
541   SecurityStateMap::iterator state = security_state_.find(child_id);
542   if (state == security_state_.end())
543     return;
544
545   state->second->RevokeReadRawCookies();
546 }
547
548 bool ChildProcessSecurityPolicyImpl::CanLoadPage(
549     int child_id,
550     const GURL& url,
551     ResourceType::Type resource_type) {
552   // If --site-per-process flag is passed, we should enforce
553   // stronger security restrictions on page navigation.
554   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess) &&
555       ResourceType::IsFrame(resource_type)) {
556     // TODO(nasko): Do the proper check for site-per-process, once
557     // out-of-process iframes is ready to go.
558     return true;
559   }
560   return true;
561 }
562
563 bool ChildProcessSecurityPolicyImpl::CanRequestURL(
564     int child_id, const GURL& url) {
565   if (!url.is_valid())
566     return false;  // Can't request invalid URLs.
567
568   if (IsWebSafeScheme(url.scheme()))
569     return true;  // The scheme has been white-listed for every child process.
570
571   if (IsPseudoScheme(url.scheme())) {
572     // There are a number of special cases for pseudo schemes.
573
574     if (url.SchemeIs(kViewSourceScheme)) {
575       // A view-source URL is allowed if the child process is permitted to
576       // request the embedded URL. Careful to avoid pointless recursion.
577       GURL child_url(url.GetContent());
578       if (child_url.SchemeIs(kViewSourceScheme) &&
579           url.SchemeIs(kViewSourceScheme))
580           return false;
581
582       return CanRequestURL(child_id, child_url);
583     }
584
585     if (LowerCaseEqualsASCII(url.spec(), kAboutBlankURL))
586       return true;  // Every child process can request <about:blank>.
587
588     // URLs like <about:memory> and <about:crash> shouldn't be requestable by
589     // any child process.  Also, this case covers <javascript:...>, which should
590     // be handled internally by the process and not kicked up to the browser.
591     return false;
592   }
593
594   if (!GetContentClient()->browser()->IsHandledURL(url) &&
595       !net::URLRequest::IsHandledURL(url)) {
596     return true;  // This URL request is destined for ShellExecute.
597   }
598
599   {
600     base::AutoLock lock(lock_);
601
602     SecurityStateMap::iterator state = security_state_.find(child_id);
603     if (state == security_state_.end())
604       return false;
605
606     // Otherwise, we consult the child process's security state to see if it is
607     // allowed to request the URL.
608     return state->second->CanRequestURL(url);
609   }
610 }
611
612 bool ChildProcessSecurityPolicyImpl::CanReadFile(int child_id,
613                                                  const base::FilePath& file) {
614   return HasPermissionsForFile(child_id, file, READ_FILE_GRANT);
615 }
616
617 bool ChildProcessSecurityPolicyImpl::CanCreateReadWriteFile(
618     int child_id,
619     const base::FilePath& file) {
620   return HasPermissionsForFile(child_id, file, CREATE_READ_WRITE_FILE_GRANT);
621 }
622
623 bool ChildProcessSecurityPolicyImpl::CanReadFileSystem(
624     int child_id, const std::string& filesystem_id) {
625   return HasPermissionsForFileSystem(child_id, filesystem_id, READ_FILE_GRANT);
626 }
627
628 bool ChildProcessSecurityPolicyImpl::CanReadWriteFileSystem(
629     int child_id, const std::string& filesystem_id) {
630   return HasPermissionsForFileSystem(child_id, filesystem_id,
631                                      READ_FILE_GRANT | WRITE_FILE_GRANT);
632 }
633
634 bool ChildProcessSecurityPolicyImpl::CanCopyIntoFileSystem(
635     int child_id, const std::string& filesystem_id) {
636   return HasPermissionsForFileSystem(child_id, filesystem_id,
637                                      COPY_INTO_FILE_GRANT);
638 }
639
640 bool ChildProcessSecurityPolicyImpl::CanDeleteFromFileSystem(
641     int child_id, const std::string& filesystem_id) {
642   return HasPermissionsForFileSystem(child_id, filesystem_id,
643                                      DELETE_FILE_GRANT);
644 }
645
646 void ChildProcessSecurityPolicyImpl::GrantCreateReadWriteFileSystem(
647     int child_id, const std::string& filesystem_id) {
648   GrantPermissionsForFileSystem(
649       child_id, filesystem_id, CREATE_READ_WRITE_FILE_GRANT);
650 }
651
652 bool ChildProcessSecurityPolicyImpl::HasPermissionsForFile(
653     int child_id, const base::FilePath& file, int permissions) {
654   base::AutoLock lock(lock_);
655   bool result = ChildProcessHasPermissionsForFile(child_id, file, permissions);
656   if (!result) {
657     // If this is a worker thread that has no access to a given file,
658     // let's check that its renderer process has access to that file instead.
659     WorkerToMainProcessMap::iterator iter = worker_map_.find(child_id);
660     if (iter != worker_map_.end() && iter->second != 0) {
661       result = ChildProcessHasPermissionsForFile(iter->second,
662                                                  file,
663                                                  permissions);
664     }
665   }
666   return result;
667 }
668
669 bool ChildProcessSecurityPolicyImpl::HasPermissionsForFileSystemFile(
670     int child_id, const fileapi::FileSystemURL& url, int permissions) {
671   if (!url.is_valid())
672     return false;
673
674   if (url.path().ReferencesParent())
675     return false;
676
677   // Any write access is disallowed on the root path.
678   if (fileapi::VirtualPath::IsRootPath(url.path()) &&
679       (permissions & ~READ_FILE_GRANT)) {
680     return false;
681   }
682
683   if (url.mount_type() == fileapi::kFileSystemTypeIsolated) {
684     // When Isolated filesystems is overlayed on top of another filesystem,
685     // its per-filesystem permission overrides the underlying filesystem
686     // permissions).
687     return HasPermissionsForFileSystem(
688         child_id, url.mount_filesystem_id(), permissions);
689   }
690
691   FileSystemPermissionPolicyMap::iterator found =
692       file_system_policy_map_.find(url.type());
693   if (found == file_system_policy_map_.end())
694     return false;
695
696   if ((found->second & fileapi::FILE_PERMISSION_READ_ONLY) &&
697       permissions & ~READ_FILE_GRANT) {
698     return false;
699   }
700
701   if (found->second & fileapi::FILE_PERMISSION_USE_FILE_PERMISSION)
702     return HasPermissionsForFile(child_id, url.path(), permissions);
703
704   if (found->second & fileapi::FILE_PERMISSION_SANDBOX)
705     return true;
706
707   return false;
708 }
709
710 bool ChildProcessSecurityPolicyImpl::CanReadFileSystemFile(
711     int child_id,
712     const fileapi::FileSystemURL& url) {
713   return HasPermissionsForFileSystemFile(child_id, url, READ_FILE_GRANT);
714 }
715
716 bool ChildProcessSecurityPolicyImpl::CanWriteFileSystemFile(
717     int child_id,
718     const fileapi::FileSystemURL& url) {
719   return HasPermissionsForFileSystemFile(child_id, url, WRITE_FILE_GRANT);
720 }
721
722 bool ChildProcessSecurityPolicyImpl::CanCreateFileSystemFile(
723     int child_id,
724     const fileapi::FileSystemURL& url) {
725   return HasPermissionsForFileSystemFile(child_id, url, CREATE_NEW_FILE_GRANT);
726 }
727
728 bool ChildProcessSecurityPolicyImpl::CanCreateReadWriteFileSystemFile(
729     int child_id,
730     const fileapi::FileSystemURL& url) {
731   return HasPermissionsForFileSystemFile(child_id, url,
732                                          CREATE_READ_WRITE_FILE_GRANT);
733 }
734
735 bool ChildProcessSecurityPolicyImpl::CanCopyIntoFileSystemFile(
736     int child_id,
737     const fileapi::FileSystemURL& url) {
738   return HasPermissionsForFileSystemFile(child_id, url, COPY_INTO_FILE_GRANT);
739 }
740
741 bool ChildProcessSecurityPolicyImpl::CanDeleteFileSystemFile(
742     int child_id,
743     const fileapi::FileSystemURL& url) {
744   return HasPermissionsForFileSystemFile(child_id, url, DELETE_FILE_GRANT);
745 }
746
747 bool ChildProcessSecurityPolicyImpl::HasWebUIBindings(int child_id) {
748   base::AutoLock lock(lock_);
749
750   SecurityStateMap::iterator state = security_state_.find(child_id);
751   if (state == security_state_.end())
752     return false;
753
754   return state->second->has_web_ui_bindings();
755 }
756
757 bool ChildProcessSecurityPolicyImpl::CanReadRawCookies(int child_id) {
758   base::AutoLock lock(lock_);
759
760   SecurityStateMap::iterator state = security_state_.find(child_id);
761   if (state == security_state_.end())
762     return false;
763
764   return state->second->can_read_raw_cookies();
765 }
766
767 void ChildProcessSecurityPolicyImpl::AddChild(int child_id) {
768   if (security_state_.count(child_id) != 0) {
769     NOTREACHED() << "Add child process at most once.";
770     return;
771   }
772
773   security_state_[child_id] = new SecurityState();
774 }
775
776 bool ChildProcessSecurityPolicyImpl::ChildProcessHasPermissionsForFile(
777     int child_id, const base::FilePath& file, int permissions) {
778   SecurityStateMap::iterator state = security_state_.find(child_id);
779   if (state == security_state_.end())
780     return false;
781   return state->second->HasPermissionsForFile(file, permissions);
782 }
783
784 bool ChildProcessSecurityPolicyImpl::CanAccessCookiesForOrigin(
785     int child_id, const GURL& gurl) {
786   base::AutoLock lock(lock_);
787   SecurityStateMap::iterator state = security_state_.find(child_id);
788   if (state == security_state_.end())
789     return false;
790   return state->second->CanAccessCookiesForOrigin(gurl);
791 }
792
793 bool ChildProcessSecurityPolicyImpl::CanSendCookiesForOrigin(int child_id,
794                                                              const GURL& gurl) {
795   for (PluginProcessHostIterator iter; !iter.Done(); ++iter) {
796     if (iter.GetData().id == child_id) {
797       if (iter.GetData().process_type == PROCESS_TYPE_PLUGIN) {
798         // NPAPI plugin processes are unsandboxed and so are trusted. Plugins
799         // can make request to any origin.
800         return true;
801       }
802       break;
803     }
804   }
805
806   base::AutoLock lock(lock_);
807   SecurityStateMap::iterator state = security_state_.find(child_id);
808   if (state == security_state_.end())
809     return false;
810   return state->second->CanSendCookiesForOrigin(gurl);
811 }
812
813 void ChildProcessSecurityPolicyImpl::LockToOrigin(int child_id,
814                                                   const GURL& gurl) {
815   // "gurl" can be currently empty in some cases, such as file://blah.
816   DCHECK(SiteInstanceImpl::GetSiteForURL(NULL, gurl) == gurl);
817   base::AutoLock lock(lock_);
818   SecurityStateMap::iterator state = security_state_.find(child_id);
819   DCHECK(state != security_state_.end());
820   state->second->LockToOrigin(gurl);
821 }
822
823 void ChildProcessSecurityPolicyImpl::GrantPermissionsForFileSystem(
824     int child_id,
825     const std::string& filesystem_id,
826     int permission) {
827   base::AutoLock lock(lock_);
828
829   SecurityStateMap::iterator state = security_state_.find(child_id);
830   if (state == security_state_.end())
831     return;
832   state->second->GrantPermissionsForFileSystem(filesystem_id, permission);
833 }
834
835 bool ChildProcessSecurityPolicyImpl::HasPermissionsForFileSystem(
836     int child_id,
837     const std::string& filesystem_id,
838     int permission) {
839   base::AutoLock lock(lock_);
840
841   SecurityStateMap::iterator state = security_state_.find(child_id);
842   if (state == security_state_.end())
843     return false;
844   return state->second->HasPermissionsForFileSystem(filesystem_id, permission);
845 }
846
847 void ChildProcessSecurityPolicyImpl::RegisterFileSystemPermissionPolicy(
848     fileapi::FileSystemType type,
849     int policy) {
850   base::AutoLock lock(lock_);
851   file_system_policy_map_[type] = policy;
852 }
853
854 bool ChildProcessSecurityPolicyImpl::CanSendMIDISysExMessage(int child_id) {
855   base::AutoLock lock(lock_);
856
857   SecurityStateMap::iterator state = security_state_.find(child_id);
858   if (state == security_state_.end())
859     return false;
860
861   return state->second->can_send_midi_sysex();
862 }
863
864 }  // namespace content