1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file.
4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "components/nacl/browser/nacl_file_host.h"
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/bind.h"
8a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/files/file.h"
9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/files/file_path.h"
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/path_service.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/threading/sequenced_worker_pool.h"
140f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "components/nacl/browser/nacl_browser.h"
15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "components/nacl/browser/nacl_browser_delegate.h"
16f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "components/nacl/browser/nacl_host_message_filter.h"
17a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "components/nacl/common/nacl_host_messages.h"
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/public/browser/render_view_host.h"
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/public/browser/site_instance.h"
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ipc/ipc_platform_file.h"
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using content::BrowserThread;
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace {
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Force a prefix to prevent user from opening "magic" files.
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const char* kExpectedFilePrefix = "pnacl_public_";
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Restrict PNaCl file lengths to reduce likelyhood of hitting bugs
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// in file name limit error-handling-code-paths, etc.
32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const size_t kMaxFileLength = 40;
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void NotifyRendererOfError(
35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    nacl::NaClHostMessageFilter* nacl_host_message_filter,
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    IPC::Message* reply_msg) {
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  reply_msg->set_reply_error();
387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  nacl_host_message_filter->Send(reply_msg);
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
41116680a4aac90f2aa7413d9095a592090648e557Ben Murdochtypedef void (*WriteFileInfoReply)(IPC::Message* reply_msg,
42116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                   IPC::PlatformFileForTransit file_desc,
43116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                   uint64 file_token_lo,
44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                   uint64 file_token_hi);
45116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
46116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid DoRegisterOpenedNaClExecutableFile(
47116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scoped_refptr<nacl::NaClHostMessageFilter> nacl_host_message_filter,
48116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    base::File file,
49116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    base::FilePath file_path,
50116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    IPC::Message* reply_msg,
51116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    WriteFileInfoReply write_reply_message) {
52116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // IO thread owns the NaClBrowser singleton.
53116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
54116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
55116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  nacl::NaClBrowser* nacl_browser = nacl::NaClBrowser::GetInstance();
56116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  uint64 file_token_lo = 0;
57116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  uint64 file_token_hi = 0;
58116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  nacl_browser->PutFilePath(file_path, &file_token_lo, &file_token_hi);
59116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
60116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  IPC::PlatformFileForTransit file_desc = IPC::TakeFileHandleForProcess(
61116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      file.Pass(),
62116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      nacl_host_message_filter->PeerHandle());
63116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
64116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  write_reply_message(reply_msg, file_desc, file_token_lo, file_token_hi);
65116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  nacl_host_message_filter->Send(reply_msg);
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void DoOpenPnaclFile(
69f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    scoped_refptr<nacl::NaClHostMessageFilter> nacl_host_message_filter,
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& filename,
71116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    bool is_executable,
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    IPC::Message* reply_msg) {
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::FilePath full_filepath;
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
76eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // PNaCl must be installed.
77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::FilePath pnacl_dir;
780f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!nacl::NaClBrowser::GetDelegate()->GetPnaclDirectory(&pnacl_dir) ||
797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      !base::PathExists(pnacl_dir)) {
802385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    NotifyRendererOfError(nacl_host_message_filter.get(), reply_msg);
81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return;
82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
83eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Do some validation.
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!nacl_file_host::PnaclCanOpenFile(filename, &full_filepath)) {
867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    NotifyRendererOfError(nacl_host_message_filter.get(), reply_msg);
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
90116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::File file_to_open = nacl::OpenNaClReadExecImpl(full_filepath,
91116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                                       is_executable);
92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!file_to_open.IsValid()) {
937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    NotifyRendererOfError(nacl_host_message_filter.get(), reply_msg);
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
97116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // This function is running on the blocking pool, but the path needs to be
98116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // registered in a structure owned by the IO thread.
99116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Not all PNaCl files are executable. Only register those that are
100116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // executable in the NaCl file_path cache.
101116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (is_executable) {
102116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    BrowserThread::PostTask(
103116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        BrowserThread::IO, FROM_HERE,
104116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        base::Bind(&DoRegisterOpenedNaClExecutableFile,
105116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                   nacl_host_message_filter,
106116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                   Passed(file_to_open.Pass()), full_filepath, reply_msg,
107116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                   static_cast<WriteFileInfoReply>(
108116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                       NaClHostMsg_GetReadonlyPnaclFD::WriteReplyParams)));
109116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  } else {
110116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    IPC::PlatformFileForTransit target_desc =
111116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        IPC::TakeFileHandleForProcess(file_to_open.Pass(),
112116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                      nacl_host_message_filter->PeerHandle());
113116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    uint64_t dummy_file_token = 0;
114116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    NaClHostMsg_GetReadonlyPnaclFD::WriteReplyParams(
115116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        reply_msg, target_desc, dummy_file_token, dummy_file_token);
116116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    nacl_host_message_filter->Send(reply_msg);
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
11890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
11990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Convert the file URL into a file descriptor.
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// This function is security sensitive.  Be sure to check with a security
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// person before you modify it.
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void DoOpenNaClExecutableOnThreadPool(
124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    scoped_refptr<nacl::NaClHostMessageFilter> nacl_host_message_filter,
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GURL& file_url,
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    IPC::Message* reply_msg) {
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::FilePath file_path;
1300f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!nacl::NaClBrowser::GetDelegate()->MapUrlToLocalFilePath(
131010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)          file_url,
132010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)          true /* use_blocking_api */,
133010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)          nacl_host_message_filter->profile_directory(),
134010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)          &file_path)) {
1357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    NotifyRendererOfError(nacl_host_message_filter.get(), reply_msg);
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
139116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::File file = nacl::OpenNaClReadExecImpl(file_path,
140116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                               true /* is_executable */);
141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (file.IsValid()) {
14290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // This function is running on the blocking pool, but the path needs to be
14390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // registered in a structure owned by the IO thread.
14490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    BrowserThread::PostTask(
14590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        BrowserThread::IO, FROM_HERE,
14690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::Bind(
14790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            &DoRegisterOpenedNaClExecutableFile,
1487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)            nacl_host_message_filter,
149116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch            Passed(file.Pass()), file_path, reply_msg,
150116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch            static_cast<WriteFileInfoReply>(
151116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                NaClHostMsg_OpenNaClExecutable::WriteReplyParams)));
15290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  } else {
1537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    NotifyRendererOfError(nacl_host_message_filter.get(), reply_msg);
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace nacl_file_host {
161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void GetReadonlyPnaclFd(
163f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    scoped_refptr<nacl::NaClHostMessageFilter> nacl_host_message_filter,
164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& filename,
165116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    bool is_executable,
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    IPC::Message* reply_msg) {
167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!BrowserThread::PostBlockingPoolTask(
168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          FROM_HERE,
169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          base::Bind(&DoOpenPnaclFile,
1707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                     nacl_host_message_filter,
171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     filename,
172116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                     is_executable,
173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     reply_msg))) {
1747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    NotifyRendererOfError(nacl_host_message_filter.get(), reply_msg);
175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// This function is security sensitive.  Be sure to check with a security
179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// person before you modify it.
180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool PnaclCanOpenFile(const std::string& filename,
181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                      base::FilePath* file_to_open) {
182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (filename.length() > kMaxFileLength)
183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (filename.empty())
186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Restrict character set of the file name to something really simple
189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // (a-z, 0-9, and underscores).
190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (size_t i = 0; i < filename.length(); ++i) {
191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    char charAt = filename[i];
192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (charAt < 'a' || charAt > 'z')
193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (charAt < '0' || charAt > '9')
194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (charAt != '_')
195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          return false;
196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // PNaCl must be installed.
199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::FilePath pnacl_dir;
2000f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!nacl::NaClBrowser::GetDelegate()->GetPnaclDirectory(&pnacl_dir) ||
201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      pnacl_dir.empty())
202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Prepend the prefix to restrict files to a whitelisted set.
205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::FilePath full_path = pnacl_dir.AppendASCII(
206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      std::string(kExpectedFilePrefix) + filename);
207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  *file_to_open = full_path;
208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return true;
209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void OpenNaClExecutable(
212f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    scoped_refptr<nacl::NaClHostMessageFilter> nacl_host_message_filter,
213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int render_view_id,
214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GURL& file_url,
215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    IPC::Message* reply_msg) {
216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    BrowserThread::PostTask(
218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        BrowserThread::UI, FROM_HERE,
219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(
220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            &OpenNaClExecutable,
2217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)            nacl_host_message_filter,
222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            render_view_id, file_url, reply_msg));
223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
225c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Make sure render_view_id is valid and that the URL is a part of the
227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // render view's site. Without these checks, apps could probe the extension
228c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // directory or run NaCl code from other extensions.
229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  content::RenderViewHost* rvh = content::RenderViewHost::FromID(
2307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      nacl_host_message_filter->render_process_id(), render_view_id);
231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!rvh) {
2327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    nacl_host_message_filter->BadMessageReceived();  // Kill the renderer.
233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  content::SiteInstance* site_instance = rvh->GetSiteInstance();
236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!content::SiteInstance::IsSameWebSite(site_instance->GetBrowserContext(),
237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                            site_instance->GetSiteURL(),
238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                            file_url)) {
2397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    NotifyRendererOfError(nacl_host_message_filter.get(), reply_msg);
240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
242c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // The URL is part of the current app. Now query the extension system for the
244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // file path and convert that to a file descriptor. This should be done on a
245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // blocking pool thread.
246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!BrowserThread::PostBlockingPoolTask(
247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      FROM_HERE,
248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(
249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          &DoOpenNaClExecutableOnThreadPool,
2507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          nacl_host_message_filter,
251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          file_url, reply_msg))) {
2527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    NotifyRendererOfError(nacl_host_message_filter.get(), reply_msg);
253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace nacl_file_host
257