15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "mojo/embedder/platform_channel_pair.h"
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <windows.h>
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <string>
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/command_line.h"
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/logging.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/rand_util.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/stringprintf.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/win/windows_version.h"
1723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "mojo/embedder/platform_handle.h"
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace mojo {
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace embedder {
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::wstring GeneratePipeName() {
255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return base::StringPrintf(L"\\\\.\\pipe\\mojo.%u.%u.%I64u",
265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            GetCurrentProcessId(),
275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            GetCurrentThreadId(),
285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            base::RandUint64());
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)PlatformChannelPair::PlatformChannelPair() {
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::wstring pipe_name = GeneratePipeName();
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const DWORD kOpenMode =
375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE;
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const DWORD kPipeMode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE;
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  server_handle_.reset(PlatformHandle(
401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      CreateNamedPipeW(pipe_name.c_str(),
411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                       kOpenMode,
421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                       kPipeMode,
431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                       1,           // Max instances.
441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                       4096,        // Out buffer size.
451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                       4096,        // In buffer size.
461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                       5000,        // Timeout in milliseconds.
471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                       nullptr)));  // Default security descriptor.
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  PCHECK(server_handle_.is_valid());
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const DWORD kDesiredAccess = GENERIC_READ | GENERIC_WRITE;
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // The SECURITY_ANONYMOUS flag means that the server side cannot impersonate
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // the client.
535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const DWORD kFlags =
545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS | FILE_FLAG_OVERLAPPED;
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Allow the handle to be inherited by child processes.
561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  SECURITY_ATTRIBUTES security_attributes = {sizeof(SECURITY_ATTRIBUTES),
571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                             nullptr, TRUE};
581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  client_handle_.reset(
591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      PlatformHandle(CreateFileW(pipe_name.c_str(),
601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                 kDesiredAccess,
611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                 0,  // No sharing.
621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                 &security_attributes,
631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                 OPEN_EXISTING,
641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                 kFlags,
651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                 nullptr)));  // No template file.
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  PCHECK(client_handle_.is_valid());
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Since a client has connected, ConnectNamedPipe() should return zero and
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // GetLastError() should return ERROR_PIPE_CONNECTED.
701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CHECK(!ConnectNamedPipe(server_handle_.get().handle, nullptr));
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  PCHECK(GetLastError() == ERROR_PIPE_CONNECTED);
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// static
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ScopedPlatformHandle PlatformChannelPair::PassClientHandleFromParentProcess(
76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const base::CommandLine& command_line) {
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string client_handle_string =
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      command_line.GetSwitchValueASCII(kMojoPlatformChannelHandleSwitch);
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int client_handle_value = 0;
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (client_handle_string.empty() ||
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      !base::StringToInt(client_handle_string, &client_handle_value)) {
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "Missing or invalid --" << kMojoPlatformChannelHandleSwitch;
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return ScopedPlatformHandle();
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return ScopedPlatformHandle(
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      PlatformHandle(LongToHandle(client_handle_value)));
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void PlatformChannelPair::PrepareToPassClientHandleToChildProcess(
92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    base::CommandLine* command_line,
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::HandlesToInheritVector* handle_passing_info) const {
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(command_line);
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(handle_passing_info);
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(client_handle_.is_valid());
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CHECK_GE(base::win::GetVersion(), base::win::VERSION_VISTA);
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  handle_passing_info->push_back(client_handle_.get().handle);
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Log a warning if the command line already has the switch, but "clobber" it
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // anyway, since it's reasonably likely that all the switches were just copied
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // from the parent.
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG_IF(WARNING, command_line->HasSwitch(kMojoPlatformChannelHandleSwitch))
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      << "Child command line already has switch --"
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      << kMojoPlatformChannelHandleSwitch << "="
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      << command_line->GetSwitchValueASCII(kMojoPlatformChannelHandleSwitch);
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // (Any existing switch won't actually be removed from the command line, but
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // the last one appended takes precedence.)
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  command_line->AppendSwitchASCII(
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      kMojoPlatformChannelHandleSwitch,
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::IntToString(HandleToLong(client_handle_.get().handle)));
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace embedder
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace mojo
118