summaryrefslogtreecommitdiffstats
path: root/remoting/host/ipc_util_win.cc
blob: e3b7cec357128a0495a3397d58e726e8b00147f5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "remoting/host/ipc_util.h"

#include "base/logging.h"
#include "base/single_thread_task_runner.h"
#include "base/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/scoped_handle.h"
#include "base/win/win_util.h"
#include "ipc/ipc_channel.h"
#include "ipc/ipc_channel_proxy.h"
#include "remoting/host/win/security_descriptor.h"

using base::win::ScopedHandle;

namespace remoting {

// Pipe name prefix used by Chrome IPC channels to convert a channel name into
// a pipe name.
const char kChromePipeNamePrefix[] = "\\\\.\\pipe\\chrome.";

bool CreateConnectedIpcChannel(
    scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
    IPC::Listener* listener,
    IPC::PlatformFileForTransit* client_out,
    scoped_ptr<IPC::ChannelProxy>* server_out) {
  // presubmit: allow wstring
  std::wstring user_sid;
  if (!base::win::GetUserSidString(&user_sid)) {
    LOG(ERROR) << "Failed to query the current user SID.";
    return false;
  }

  // Create a security descriptor that will be used to protect the named pipe in
  // between CreateNamedPipe() and CreateFile() calls before it will be passed
  // to the network process. It gives full access to the account that
  // the calling code is running under and  denies access by anyone else.
  std::string security_descriptor = base::StringPrintf(
      "O:%1$sG:%1$sD:(A;;GA;;;%1$s)", WideToUTF8(user_sid).c_str());

  // Generate a unique name for the channel.
  std::string channel_name = IPC::Channel::GenerateUniqueRandomChannelID();

  // Create the server end of the channel.
  ScopedHandle pipe;
  if (!CreateIpcChannel(channel_name, security_descriptor, &pipe)) {
    return false;
  }

  // Wrap the pipe into an IPC channel.
  scoped_ptr<IPC::ChannelProxy> server(new IPC::ChannelProxy(
      IPC::ChannelHandle(pipe),
      IPC::Channel::MODE_SERVER,
      listener,
      io_task_runner));

  // Convert the channel name to the pipe name.
  std::string pipe_name(kChromePipeNamePrefix);
  pipe_name.append(channel_name);

  SECURITY_ATTRIBUTES security_attributes = {0};
  security_attributes.nLength = sizeof(security_attributes);
  security_attributes.lpSecurityDescriptor = NULL;
  security_attributes.bInheritHandle = TRUE;

  // Create the client end of the channel. This code should match the code in
  // IPC::Channel.
  ScopedHandle client;
  client.Set(CreateFile(UTF8ToUTF16(pipe_name).c_str(),
                        GENERIC_READ | GENERIC_WRITE,
                        0,
                        &security_attributes,
                        OPEN_EXISTING,
                        SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION |
                            FILE_FLAG_OVERLAPPED,
                        NULL));
  if (!client.IsValid()) {
    LOG_GETLASTERROR(ERROR) << "Failed to connect to '" << pipe_name << "'";
    return false;
  }

  *client_out = client.Take();
  *server_out = server.Pass();
  return true;
}

bool CreateIpcChannel(
    const std::string& channel_name,
    const std::string& pipe_security_descriptor,
    base::win::ScopedHandle* pipe_out) {
  // Create security descriptor for the channel.
  ScopedSd sd = ConvertSddlToSd(pipe_security_descriptor);
  if (!sd) {
    LOG_GETLASTERROR(ERROR) <<
        "Failed to create a security descriptor for the Chromoting IPC channel";
    return false;
  }

  SECURITY_ATTRIBUTES security_attributes = {0};
  security_attributes.nLength = sizeof(security_attributes);
  security_attributes.lpSecurityDescriptor = sd.get();
  security_attributes.bInheritHandle = FALSE;

  // Convert the channel name to the pipe name.
  std::string pipe_name(kChromePipeNamePrefix);
  pipe_name.append(channel_name);

  // Create the server end of the pipe. This code should match the code in
  // IPC::Channel with exception of passing a non-default security descriptor.
  base::win::ScopedHandle pipe;
  pipe.Set(CreateNamedPipe(
      UTF8ToUTF16(pipe_name).c_str(),
      PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE,
      PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
      1,
      IPC::Channel::kReadBufferSize,
      IPC::Channel::kReadBufferSize,
      5000,
      &security_attributes));
  if (!pipe.IsValid()) {
    LOG_GETLASTERROR(ERROR) <<
        "Failed to create the server end of the Chromoting IPC channel";
    return false;
  }

  *pipe_out = pipe.Pass();
  return true;
}

} // namespace remoting