15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/api/messaging/native_process_launcher.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/command_line.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 11bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "base/process/kill.h" 12bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "base/process/launch.h" 13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string16.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h" 15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h" 16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/win/registry.h" 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/win/scoped_handle.h" 19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "crypto/random.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace extensions { 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const wchar_t kNativeMessagingRegistryKey[] = 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) L"SOFTWARE\\Google\\Chrome\\NativeMessagingHosts"; 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace { 27eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Reads path to the native messaging host manifest from the registry. Returns 295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// false if the path isn't found. 305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GetManifestPathWithFlags(HKEY root_key, 315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DWORD flags, 325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::string16& host_name, 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16* result) { 34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::win::RegKey key; 35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (key.Open(root_key, kNativeMessagingRegistryKey, 37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch KEY_QUERY_VALUE | flags) != ERROR_SUCCESS || 385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) key.OpenKey(host_name.c_str(), 39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch KEY_QUERY_VALUE | flags) != ERROR_SUCCESS || 405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) key.ReadValue(NULL, result) != ERROR_SUCCESS) { 415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return true; 455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GetManifestPath(HKEY root_key, 485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::string16& host_name, 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16* result) { 505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // First check 32-bit registry and then try 64-bit. 515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return GetManifestPathWithFlags( 525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) root_key, KEY_WOW64_32KEY, host_name, result) || 535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) GetManifestPathWithFlags( 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) root_key, KEY_WOW64_64KEY, host_name, result); 55eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 56eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} // namespace 58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static 60a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)base::FilePath NativeProcessLauncher::FindManifest( 615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const std::string& host_name, 625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool allow_user_level_hosts, 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string* error_message) { 645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16 host_name_wide = base::UTF8ToUTF16(host_name); 655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Try to find the key in HKEY_LOCAL_MACHINE and then in HKEY_CURRENT_USER. 675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16 path_str; 685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool found = false; 695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (allow_user_level_hosts) 705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) found = GetManifestPath(HKEY_CURRENT_USER, host_name_wide, &path_str); 715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!found) 725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) found = GetManifestPath(HKEY_LOCAL_MACHINE, host_name_wide, &path_str); 735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!found) { 755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) *error_message = 765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Native messaging host " + host_name + " is not registered."; 77a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return base::FilePath(); 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::FilePath manifest_path(path_str); 81a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (!manifest_path.IsAbsolute()) { 82a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) *error_message = "Path to native messaging host manifest must be absolute."; 83a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return base::FilePath(); 84a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 85a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 86a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return manifest_path; 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NativeProcessLauncher::LaunchNativeProcess( 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const CommandLine& command_line, 924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::ProcessHandle* process_handle, 9323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) base::File* read_file, 9423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) base::File* write_file) { 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Timeout for the IO pipes. 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const DWORD kTimeoutMs = 5000; 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Windows will use default buffer size when 0 is passed to 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // CreateNamedPipeW(). 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const DWORD kBufferSize = 0; 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!command_line.GetProgram().IsAbsolute()) { 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(ERROR) << "Native Messaging host path must be absolute."; 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) uint64 pipe_name_token; 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) crypto::RandBytes(&pipe_name_token, sizeof(pipe_name_token)); 109a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 out_pipe_name = base::StringPrintf( 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) L"\\\\.\\pipe\\chrome.nativeMessaging.out.%llx", pipe_name_token); 111a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 in_pipe_name = base::StringPrintf( 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) L"\\\\.\\pipe\\chrome.nativeMessaging.in.%llx", pipe_name_token); 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Create the pipes to read and write from. 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::win::ScopedHandle stdout_pipe( 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CreateNamedPipeW(out_pipe_name.c_str(), 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED | 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FILE_FLAG_FIRST_PIPE_INSTANCE, 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PIPE_TYPE_BYTE, 1, kBufferSize, kBufferSize, 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kTimeoutMs, NULL)); 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!stdout_pipe.IsValid()) { 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(ERROR) << "Failed to create pipe " << out_pipe_name; 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::win::ScopedHandle stdin_pipe( 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CreateNamedPipeW(in_pipe_name.c_str(), 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED | 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FILE_FLAG_FIRST_PIPE_INSTANCE, 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PIPE_TYPE_BYTE, 1, kBufferSize, kBufferSize, 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kTimeoutMs, NULL)); 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!stdin_pipe.IsValid()) { 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(ERROR) << "Failed to create pipe " << in_pipe_name; 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DWORD comspec_length = ::GetEnvironmentVariable(L"COMSPEC", NULL, 0); 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (comspec_length == 0) { 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(ERROR) << "COMSPEC is not set"; 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<wchar_t[]> comspec(new wchar_t[comspec_length]); 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ::GetEnvironmentVariable(L"COMSPEC", comspec.get(), comspec_length); 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 145a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 command_line_string = command_line.GetCommandLineString(); 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 147a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 command = base::StringPrintf( 14868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) L"%ls /c %ls < %ls > %ls", 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) comspec.get(), command_line_string.c_str(), 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) in_pipe_name.c_str(), out_pipe_name.c_str()); 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::LaunchOptions options; 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) options.start_hidden = true; 154f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::win::ScopedHandle cmd_handle; 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!base::LaunchProcess(command.c_str(), options, &cmd_handle)) { 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(ERROR) << "Error launching process " 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << command_line.GetProgram().MaybeAsASCII(); 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool stdout_connected = ConnectNamedPipe(stdout_pipe.Get(), NULL) ? 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TRUE : GetLastError() == ERROR_PIPE_CONNECTED; 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool stdin_connected = ConnectNamedPipe(stdin_pipe.Get(), NULL) ? 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TRUE : GetLastError() == ERROR_PIPE_CONNECTED; 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!stdout_connected || !stdin_connected) { 166f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::KillProcess(cmd_handle.Get(), 0, false); 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(ERROR) << "Failed to connect IO pipes when starting " 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << command_line.GetProgram().MaybeAsASCII(); 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 172f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *process_handle = cmd_handle.Take(); 17323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) *read_file = base::File(stdout_pipe.Take()); 17423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) *write_file = base::File(stdin_pipe.Take()); 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace extensions 180