OLD | NEW |
| (Empty) |
1 // Copyright 2016 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 "remoting/host/security_key/security_key_auth_handler.h" | |
6 | |
7 #include <cstdint> | |
8 #include <map> | |
9 #include <memory> | |
10 #include <string> | |
11 | |
12 #include "base/bind.h" | |
13 #include "base/location.h" | |
14 #include "base/logging.h" | |
15 #include "base/memory/weak_ptr.h" | |
16 #include "base/strings/stringprintf.h" | |
17 #include "base/strings/utf_string_conversions.h" | |
18 #include "base/threading/thread_checker.h" | |
19 #include "base/threading/thread_task_runner_handle.h" | |
20 #include "base/time/time.h" | |
21 #include "base/timer/timer.h" | |
22 #include "base/win/win_util.h" | |
23 #include "ipc/ipc_channel.h" | |
24 #include "ipc/ipc_listener.h" | |
25 #include "ipc/ipc_message.h" | |
26 #include "ipc/ipc_message_macros.h" | |
27 #include "remoting/base/logging.h" | |
28 #include "remoting/host/chromoting_messages.h" | |
29 #include "remoting/host/client_session_details.h" | |
30 #include "remoting/host/ipc_util.h" | |
31 #include "remoting/host/security_key/security_key_ipc_constants.h" | |
32 #include "remoting/host/security_key/security_key_ipc_server.h" | |
33 | |
34 namespace { | |
35 | |
36 // The timeout used to disconnect a client from the IPC Server channel if it | |
37 // forgets to do so. This ensures the server channel is not blocked forever. | |
38 const int kInitialRequestTimeoutSeconds = 5; | |
39 | |
40 // This value represents the amount of time to wait for a security key request | |
41 // from the client before terminating the connection. | |
42 const int kSecurityKeyRequestTimeoutSeconds = 60; | |
43 | |
44 } // namespace | |
45 | |
46 namespace remoting { | |
47 | |
48 // Creates an IPC server channel which services IPC clients that want to start | |
49 // a security key forwarding session. Once an IPC Client connects to the | |
50 // server, the SecurityKeyAuthHandlerWin class will create a new | |
51 // SecurityKeyIpcServer instance that will service that request. The new | |
52 // instance will exist for the lifetime of the security key request and will be | |
53 // assigned a unique IPC channel name and connection id. The channel name is | |
54 // sent to the client which should disconnect the IPC server channel and | |
55 // connect to the security key forwarding session IPC channel to send/receive | |
56 // security key messages. The IPC server channel will then be reset so it can | |
57 // can service the next client/request. This system allows multiple security | |
58 // key forwarding sessions to occur concurrently. | |
59 // TODO(joedow): Update SecurityKeyAuthHandler impls to run on a separate IO | |
60 // thread instead of the thread it was created on: crbug.com/591739 | |
61 class SecurityKeyAuthHandlerWin : public SecurityKeyAuthHandler, | |
62 public IPC::Listener { | |
63 public: | |
64 explicit SecurityKeyAuthHandlerWin( | |
65 ClientSessionDetails* client_session_details); | |
66 ~SecurityKeyAuthHandlerWin() override; | |
67 | |
68 private: | |
69 typedef std::map<int, std::unique_ptr<SecurityKeyIpcServer>> ActiveChannels; | |
70 | |
71 // SecurityKeyAuthHandler interface. | |
72 void CreateSecurityKeyConnection() override; | |
73 bool IsValidConnectionId(int security_key_connection_id) const override; | |
74 void SendClientResponse(int security_key_connection_id, | |
75 const std::string& response) override; | |
76 void SendErrorAndCloseConnection(int security_key_connection_id) override; | |
77 void SetSendMessageCallback(const SendMessageCallback& callback) override; | |
78 size_t GetActiveConnectionCountForTest() const override; | |
79 void SetRequestTimeoutForTest(base::TimeDelta timeout) override; | |
80 | |
81 // IPC::Listener implementation. | |
82 bool OnMessageReceived(const IPC::Message& message) override; | |
83 void OnChannelConnected(int32_t peer_pid) override; | |
84 void OnChannelError() override; | |
85 | |
86 // Creates the IPC server channel and waits for a connection using | |
87 // |ipc_server_channel_name_|. | |
88 void StartIpcServerChannel(); | |
89 | |
90 // Restarts the IPC server channel to prepare for another connection. | |
91 void RecreateIpcServerChannel(); | |
92 | |
93 // Closes the IPC channel created for a security key forwarding session. | |
94 void CloseSecurityKeyRequestIpcChannel(int connection_id); | |
95 | |
96 // Returns the IPC Channel instance created for |connection_id|. | |
97 ActiveChannels::const_iterator GetChannelForConnectionId( | |
98 int connection_id) const; | |
99 | |
100 // Creates a unique name based on the well-known IPC channel name. | |
101 std::string GenerateUniqueChannelName(); | |
102 | |
103 // Represents the last id assigned to a new security key request IPC channel. | |
104 int last_connection_id_ = 0; | |
105 | |
106 // Sends a security key extension message to the client when called. | |
107 SendMessageCallback send_message_callback_; | |
108 | |
109 // Interface which provides details about the client session. | |
110 ClientSessionDetails* client_session_details_ = nullptr; | |
111 | |
112 // Tracks the IPC channel created for each security key forwarding session. | |
113 ActiveChannels active_channels_; | |
114 | |
115 // The amount of time to wait for a client to process the connection details | |
116 // message and disconnect from the IPC server channel before disconnecting it. | |
117 base::TimeDelta disconnect_timeout_; | |
118 | |
119 // Used to recreate the IPC server channel if a client forgets to disconnect. | |
120 base::OneShotTimer timer_; | |
121 | |
122 // IPC Clients connect to this channel first to receive their own IPC | |
123 // channel to start a security key forwarding session on. | |
124 std::unique_ptr<IPC::Channel> ipc_server_channel_; | |
125 | |
126 // Ensures SecurityKeyAuthHandlerWin methods are called on the same thread. | |
127 base::ThreadChecker thread_checker_; | |
128 | |
129 base::WeakPtrFactory<SecurityKeyAuthHandlerWin> weak_factory_; | |
130 | |
131 DISALLOW_COPY_AND_ASSIGN(SecurityKeyAuthHandlerWin); | |
132 }; | |
133 | |
134 std::unique_ptr<SecurityKeyAuthHandler> SecurityKeyAuthHandler::Create( | |
135 ClientSessionDetails* client_session_details, | |
136 const SendMessageCallback& send_message_callback) { | |
137 std::unique_ptr<SecurityKeyAuthHandler> auth_handler( | |
138 new SecurityKeyAuthHandlerWin(client_session_details)); | |
139 auth_handler->SetSendMessageCallback(send_message_callback); | |
140 return auth_handler; | |
141 } | |
142 | |
143 SecurityKeyAuthHandlerWin::SecurityKeyAuthHandlerWin( | |
144 ClientSessionDetails* client_session_details) | |
145 : client_session_details_(client_session_details), | |
146 disconnect_timeout_( | |
147 base::TimeDelta::FromSeconds(kInitialRequestTimeoutSeconds)), | |
148 weak_factory_(this) { | |
149 DCHECK(client_session_details_); | |
150 } | |
151 | |
152 SecurityKeyAuthHandlerWin::~SecurityKeyAuthHandlerWin() {} | |
153 | |
154 void SecurityKeyAuthHandlerWin::CreateSecurityKeyConnection() { | |
155 DCHECK(thread_checker_.CalledOnValidThread()); | |
156 StartIpcServerChannel(); | |
157 } | |
158 | |
159 bool SecurityKeyAuthHandlerWin::IsValidConnectionId(int connection_id) const { | |
160 DCHECK(thread_checker_.CalledOnValidThread()); | |
161 return (GetChannelForConnectionId(connection_id) != active_channels_.end()); | |
162 } | |
163 | |
164 void SecurityKeyAuthHandlerWin::SendClientResponse( | |
165 int connection_id, | |
166 const std::string& response_data) { | |
167 DCHECK(thread_checker_.CalledOnValidThread()); | |
168 | |
169 ActiveChannels::const_iterator iter = | |
170 GetChannelForConnectionId(connection_id); | |
171 if (iter == active_channels_.end()) { | |
172 HOST_LOG << "Invalid security key connection ID received: " | |
173 << connection_id; | |
174 return; | |
175 } | |
176 | |
177 if (!iter->second->SendResponse(response_data)) { | |
178 CloseSecurityKeyRequestIpcChannel(connection_id); | |
179 } | |
180 } | |
181 | |
182 void SecurityKeyAuthHandlerWin::SendErrorAndCloseConnection(int connection_id) { | |
183 DCHECK(thread_checker_.CalledOnValidThread()); | |
184 | |
185 SendClientResponse(connection_id, kSecurityKeyConnectionError); | |
186 CloseSecurityKeyRequestIpcChannel(connection_id); | |
187 } | |
188 | |
189 void SecurityKeyAuthHandlerWin::SetSendMessageCallback( | |
190 const SendMessageCallback& callback) { | |
191 DCHECK(thread_checker_.CalledOnValidThread()); | |
192 send_message_callback_ = callback; | |
193 } | |
194 | |
195 size_t SecurityKeyAuthHandlerWin::GetActiveConnectionCountForTest() const { | |
196 return active_channels_.size(); | |
197 } | |
198 | |
199 void SecurityKeyAuthHandlerWin::SetRequestTimeoutForTest( | |
200 base::TimeDelta timeout) { | |
201 disconnect_timeout_ = timeout; | |
202 } | |
203 | |
204 void SecurityKeyAuthHandlerWin::StartIpcServerChannel() { | |
205 DCHECK(thread_checker_.CalledOnValidThread()); | |
206 | |
207 // Create a named pipe owned by the current user (the LocalService account | |
208 // (SID: S-1-5-19) when running in the network process) which is available to | |
209 // all authenticated users. | |
210 // presubmit: allow wstring | |
211 std::wstring user_sid; | |
212 CHECK(base::win::GetUserSidString(&user_sid)); | |
213 std::string user_sid_utf8 = base::WideToUTF8(user_sid); | |
214 std::string security_descriptor = base::StringPrintf( | |
215 "O:%sG:%sD:(A;;GA;;;AU)", user_sid_utf8.c_str(), user_sid_utf8.c_str()); | |
216 | |
217 base::win::ScopedHandle pipe; | |
218 CHECK(CreateIpcChannel(remoting::GetSecurityKeyIpcChannelName(), | |
219 security_descriptor, &pipe)); | |
220 ipc_server_channel_ = | |
221 IPC::Channel::CreateNamedServer(IPC::ChannelHandle(pipe.Get()), this); | |
222 CHECK(ipc_server_channel_->Connect()); | |
223 } | |
224 | |
225 void SecurityKeyAuthHandlerWin::RecreateIpcServerChannel() { | |
226 DCHECK(thread_checker_.CalledOnValidThread()); | |
227 | |
228 timer_.Stop(); | |
229 ipc_server_channel_.reset(); | |
230 | |
231 StartIpcServerChannel(); | |
232 } | |
233 | |
234 void SecurityKeyAuthHandlerWin::CloseSecurityKeyRequestIpcChannel( | |
235 int connection_id) { | |
236 active_channels_.erase(connection_id); | |
237 } | |
238 | |
239 SecurityKeyAuthHandlerWin::ActiveChannels::const_iterator | |
240 SecurityKeyAuthHandlerWin::GetChannelForConnectionId(int connection_id) const { | |
241 return active_channels_.find(connection_id); | |
242 } | |
243 | |
244 std::string SecurityKeyAuthHandlerWin::GenerateUniqueChannelName() { | |
245 return GetSecurityKeyIpcChannelName() + "." + | |
246 IPC::Channel::GenerateUniqueRandomChannelID(); | |
247 } | |
248 | |
249 bool SecurityKeyAuthHandlerWin::OnMessageReceived(const IPC::Message& message) { | |
250 DCHECK(thread_checker_.CalledOnValidThread()); | |
251 // This class does handle any IPC messages sent by the client. | |
252 return false; | |
253 } | |
254 | |
255 void SecurityKeyAuthHandlerWin::OnChannelConnected(int32_t peer_pid) { | |
256 DCHECK(thread_checker_.CalledOnValidThread()); | |
257 | |
258 timer_.Start(FROM_HERE, disconnect_timeout_, | |
259 base::Bind(&SecurityKeyAuthHandlerWin::OnChannelError, | |
260 base::Unretained(this))); | |
261 | |
262 // Verify the IPC connection attempt originated from the session we are | |
263 // currently remoting. We don't want to service requests from arbitrary | |
264 // Windows sessions. | |
265 bool close_connection = false; | |
266 DWORD peer_session_id; | |
267 if (!ProcessIdToSessionId(peer_pid, &peer_session_id)) { | |
268 PLOG(ERROR) << "ProcessIdToSessionId() failed"; | |
269 close_connection = true; | |
270 } else if (peer_session_id != client_session_details_->desktop_session_id()) { | |
271 LOG(INFO) << "Ignoring connection attempt from outside remoted session."; | |
272 close_connection = true; | |
273 } | |
274 if (close_connection) { | |
275 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
276 FROM_HERE, base::Bind(&SecurityKeyAuthHandlerWin::OnChannelError, | |
277 weak_factory_.GetWeakPtr())); | |
278 return; | |
279 } | |
280 | |
281 int new_connection_id = ++last_connection_id_; | |
282 std::unique_ptr<SecurityKeyIpcServer> ipc_server(SecurityKeyIpcServer::Create( | |
283 new_connection_id, peer_session_id, disconnect_timeout_, | |
284 send_message_callback_, | |
285 base::Bind(&SecurityKeyAuthHandlerWin::CloseSecurityKeyRequestIpcChannel, | |
286 base::Unretained(this), new_connection_id))); | |
287 | |
288 std::string unique_channel_name = GenerateUniqueChannelName(); | |
289 if (ipc_server->CreateChannel( | |
290 unique_channel_name, | |
291 base::TimeDelta::FromSeconds(kSecurityKeyRequestTimeoutSeconds))) { | |
292 active_channels_[new_connection_id] = std::move(ipc_server); | |
293 ipc_server_channel_->Send( | |
294 new ChromotingNetworkToRemoteSecurityKeyMsg_ConnectionDetails( | |
295 unique_channel_name)); | |
296 } | |
297 } | |
298 | |
299 void SecurityKeyAuthHandlerWin::OnChannelError() { | |
300 DCHECK(thread_checker_.CalledOnValidThread()); | |
301 | |
302 // Could be an error, most likely the client disconnected though. Either way | |
303 // we should restart the server to prepare for the next connection. | |
304 RecreateIpcServerChannel(); | |
305 } | |
306 | |
307 } // namespace remoting | |
OLD | NEW |