OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 // | 4 // |
5 // This file implements the Windows service controlling Me2Me host processes | 5 // This file implements the Windows service controlling Me2Me host processes |
6 // running within user sessions. | 6 // running within user sessions. |
7 | 7 |
8 #include "remoting/host/win/wts_session_process_delegate.h" | 8 #include "remoting/host/win/wts_session_process_delegate.h" |
9 | 9 |
10 #include <utility> | 10 #include <utility> |
11 | 11 |
12 #include "base/bind.h" | 12 #include "base/bind.h" |
13 #include "base/command_line.h" | 13 #include "base/command_line.h" |
14 #include "base/files/file_path.h" | 14 #include "base/files/file_path.h" |
15 #include "base/logging.h" | 15 #include "base/logging.h" |
16 #include "base/macros.h" | 16 #include "base/macros.h" |
17 #include "base/message_loop/message_loop.h" | 17 #include "base/message_loop/message_loop.h" |
18 #include "base/process/process_handle.h" | |
18 #include "base/single_thread_task_runner.h" | 19 #include "base/single_thread_task_runner.h" |
19 #include "base/strings/utf_string_conversions.h" | 20 #include "base/strings/utf_string_conversions.h" |
20 #include "base/threading/thread_task_runner_handle.h" | 21 #include "base/threading/thread_task_runner_handle.h" |
21 #include "base/win/scoped_handle.h" | 22 #include "base/win/scoped_handle.h" |
22 #include "ipc/attachment_broker.h" | 23 #include "ipc/attachment_broker.h" |
23 #include "ipc/ipc_channel.h" | 24 #include "ipc/ipc_channel.h" |
24 #include "ipc/ipc_channel_proxy.h" | 25 #include "ipc/ipc_channel_proxy.h" |
25 #include "ipc/ipc_listener.h" | 26 #include "ipc/ipc_listener.h" |
26 #include "ipc/ipc_message.h" | 27 #include "ipc/ipc_message.h" |
28 #include "mojo/edk/embedder/embedder.h" | |
29 #include "mojo/edk/embedder/named_platform_channel_pair.h" | |
30 #include "mojo/edk/embedder/platform_channel_pair.h" | |
31 #include "mojo/edk/embedder/platform_handle_utils.h" | |
32 #include "mojo/edk/embedder/scoped_platform_handle.h" | |
27 #include "remoting/host/host_main.h" | 33 #include "remoting/host/host_main.h" |
28 #include "remoting/host/ipc_constants.h" | 34 #include "remoting/host/ipc_constants.h" |
29 #include "remoting/host/ipc_util.h" | |
30 #include "remoting/host/switches.h" | 35 #include "remoting/host/switches.h" |
31 #include "remoting/host/win/launch_process_with_token.h" | 36 #include "remoting/host/win/launch_process_with_token.h" |
32 #include "remoting/host/win/security_descriptor.h" | 37 #include "remoting/host/win/security_descriptor.h" |
33 #include "remoting/host/win/worker_process_launcher.h" | 38 #include "remoting/host/win/worker_process_launcher.h" |
34 #include "remoting/host/win/wts_terminal_monitor.h" | 39 #include "remoting/host/win/wts_terminal_monitor.h" |
35 #include "remoting/host/worker_process_ipc_delegate.h" | 40 #include "remoting/host/worker_process_ipc_delegate.h" |
36 | 41 |
37 using base::win::ScopedHandle; | 42 using base::win::ScopedHandle; |
38 | 43 |
39 // Name of the default session desktop. | 44 // Name of the default session desktop. |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
94 // Creates and initializes the job object that will sandbox the launched child | 99 // Creates and initializes the job object that will sandbox the launched child |
95 // processes. | 100 // processes. |
96 void InitializeJob(ScopedHandle job); | 101 void InitializeJob(ScopedHandle job); |
97 | 102 |
98 // Notified that the job object initialization is complete. | 103 // Notified that the job object initialization is complete. |
99 void InitializeJobCompleted(ScopedHandle job); | 104 void InitializeJobCompleted(ScopedHandle job); |
100 | 105 |
101 // Called when the number of processes running in the job reaches zero. | 106 // Called when the number of processes running in the job reaches zero. |
102 void OnActiveProcessZero(); | 107 void OnActiveProcessZero(); |
103 | 108 |
109 // Called when a process is launched in |job_|. | |
110 void OnProcessLaunchDetected(base::ProcessId pid); | |
111 | |
104 void ReportFatalError(); | 112 void ReportFatalError(); |
105 void ReportProcessLaunched(base::win::ScopedHandle worker_process); | 113 void ReportProcessLaunched(base::win::ScopedHandle worker_process, |
114 mojo::edk::ScopedPlatformHandle server_handle); | |
106 | 115 |
107 // The task runner all public methods of this class should be called on. | 116 // The task runner all public methods of this class should be called on. |
108 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_; | 117 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_; |
109 | 118 |
110 // The task runner serving job object notifications. | 119 // The task runner serving job object notifications. |
111 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; | 120 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; |
112 | 121 |
113 // The server end of the IPC channel used to communicate to the worker | 122 // The server end of the IPC channel used to communicate to the worker |
114 // process. | 123 // process. |
115 std::unique_ptr<IPC::ChannelProxy> channel_; | 124 std::unique_ptr<IPC::ChannelProxy> channel_; |
116 | 125 |
117 // Security descriptor (as SDDL) to be applied to |channel_|. | 126 // Security descriptor (as SDDL) to be applied to |channel_|. |
118 std::string channel_security_; | 127 std::string channel_security_; |
119 | 128 |
120 // Security descriptor (as SDDL) to be applied to the newly created process. | 129 // Security descriptor (as SDDL) to be applied to the newly created process. |
121 std::string new_process_security_; | 130 std::string new_process_security_; |
122 | 131 |
123 WorkerProcessLauncher* event_handler_; | 132 WorkerProcessLauncher* event_handler_; |
124 | 133 |
125 // Pointer to GetNamedPipeClientProcessId() API if it is available. | |
126 typedef BOOL (WINAPI * GetNamedPipeClientProcessIdFn)(HANDLE, DWORD*); | |
127 GetNamedPipeClientProcessIdFn get_named_pipe_client_pid_; | |
128 | |
129 // The job object used to control the lifetime of child processes. | 134 // The job object used to control the lifetime of child processes. |
130 base::win::ScopedHandle job_; | 135 base::win::ScopedHandle job_; |
131 | 136 |
132 // True if the worker process should be launched elevated. | 137 // True if the worker process should be launched elevated. |
133 bool launch_elevated_; | 138 bool launch_elevated_; |
134 | 139 |
135 // True if a laucnh attemp is pending. | 140 // True if a laucnh attemp is pending. |
136 bool launch_pending_; | 141 bool launch_pending_; |
137 | 142 |
138 // The named pipe used as the transport by |channel_|. | |
139 base::win::ScopedHandle pipe_; | |
140 | |
141 // The token to be used to launch a process in a different session. | 143 // The token to be used to launch a process in a different session. |
142 base::win::ScopedHandle session_token_; | 144 base::win::ScopedHandle session_token_; |
143 | 145 |
144 // Command line of the launched process. | 146 // Command line of the launched process. |
145 std::unique_ptr<base::CommandLine> target_command_; | 147 std::unique_ptr<base::CommandLine> target_command_; |
146 | 148 |
147 // The handle of the worker process, if launched. | 149 // The handle of the worker process, if launched. |
148 base::win::ScopedHandle worker_process_; | 150 base::win::ScopedHandle worker_process_; |
149 | 151 |
152 // If launching elevated, this holds the server handle after launch, until | |
153 // the final process launches. | |
154 mojo::edk::ScopedPlatformHandle elevated_server_handle_; | |
155 | |
156 // If launching elevated, this is the pid of the launcher process. | |
157 base::ProcessId elevated_launcher_pid_ = base::kNullProcessId; | |
158 | |
159 // The mojo child token for the process being launched. | |
160 std::string mojo_child_token_; | |
161 | |
150 DISALLOW_COPY_AND_ASSIGN(Core); | 162 DISALLOW_COPY_AND_ASSIGN(Core); |
151 }; | 163 }; |
152 | 164 |
153 WtsSessionProcessDelegate::Core::Core( | 165 WtsSessionProcessDelegate::Core::Core( |
154 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, | 166 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, |
155 std::unique_ptr<base::CommandLine> target_command, | 167 std::unique_ptr<base::CommandLine> target_command, |
156 bool launch_elevated, | 168 bool launch_elevated, |
157 const std::string& channel_security, | 169 const std::string& channel_security, |
158 const std::string& new_process_security) | 170 const std::string& new_process_security) |
159 : caller_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 171 : caller_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
160 io_task_runner_(io_task_runner), | 172 io_task_runner_(io_task_runner), |
161 channel_security_(channel_security), | 173 channel_security_(channel_security), |
162 new_process_security_(new_process_security), | 174 new_process_security_(new_process_security), |
163 event_handler_(nullptr), | 175 event_handler_(nullptr), |
164 get_named_pipe_client_pid_(nullptr), | |
165 launch_elevated_(launch_elevated), | 176 launch_elevated_(launch_elevated), |
166 launch_pending_(false), | 177 launch_pending_(false), |
167 target_command_(std::move(target_command)) {} | 178 target_command_(std::move(target_command)) {} |
168 | 179 |
169 bool WtsSessionProcessDelegate::Core::Initialize(uint32_t session_id) { | 180 bool WtsSessionProcessDelegate::Core::Initialize(uint32_t session_id) { |
170 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 181 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
171 | 182 |
172 if (launch_elevated_) { | 183 if (launch_elevated_) { |
173 // GetNamedPipeClientProcessId() is available starting from Vista. | 184 // GetNamedPipeClientProcessId() is available starting from Vista. |
174 HMODULE kernel32 = ::GetModuleHandle(L"kernel32.dll"); | 185 HMODULE kernel32 = ::GetModuleHandle(L"kernel32.dll"); |
175 CHECK(kernel32 != nullptr); | 186 CHECK(kernel32 != nullptr); |
176 | 187 |
177 get_named_pipe_client_pid_ = | |
178 reinterpret_cast<GetNamedPipeClientProcessIdFn>( | |
179 GetProcAddress(kernel32, "GetNamedPipeClientProcessId")); | |
180 CHECK(get_named_pipe_client_pid_ != nullptr); | |
181 | |
182 ScopedHandle job; | 188 ScopedHandle job; |
183 job.Set(CreateJobObject(nullptr, nullptr)); | 189 job.Set(CreateJobObject(nullptr, nullptr)); |
184 if (!job.IsValid()) { | 190 if (!job.IsValid()) { |
185 PLOG(ERROR) << "Failed to create a job object"; | 191 PLOG(ERROR) << "Failed to create a job object"; |
186 return false; | 192 return false; |
187 } | 193 } |
188 | 194 |
189 // Limit the number of active processes in the job to two (the helper | 195 // Limit the number of active processes in the job to two (the helper |
190 // process performing elevation and the worker process itself) and make sure | 196 // process performing elevation and the worker process itself) and make sure |
191 // that all processes will be killed once the job object is destroyed. | 197 // that all processes will be killed once the job object is destroyed. |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
246 | 252 |
247 void WtsSessionProcessDelegate::Core::CloseChannel() { | 253 void WtsSessionProcessDelegate::Core::CloseChannel() { |
248 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 254 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
249 | 255 |
250 if (!channel_) | 256 if (!channel_) |
251 return; | 257 return; |
252 | 258 |
253 IPC::AttachmentBroker::GetGlobal()->DeregisterCommunicationChannel( | 259 IPC::AttachmentBroker::GetGlobal()->DeregisterCommunicationChannel( |
254 channel_.get()); | 260 channel_.get()); |
255 channel_.reset(); | 261 channel_.reset(); |
256 pipe_.Close(); | 262 elevated_server_handle_.reset(); |
263 elevated_launcher_pid_ = base::kNullProcessId; | |
264 if (!mojo_child_token_.empty()) { | |
265 mojo::edk::ChildProcessLaunchFailed(mojo_child_token_); | |
266 mojo_child_token_.clear(); | |
267 } | |
257 } | 268 } |
258 | 269 |
259 void WtsSessionProcessDelegate::Core::KillProcess() { | 270 void WtsSessionProcessDelegate::Core::KillProcess() { |
260 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 271 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
261 | 272 |
262 CloseChannel(); | 273 CloseChannel(); |
263 | 274 |
264 event_handler_ = nullptr; | 275 event_handler_ = nullptr; |
265 launch_pending_ = false; | 276 launch_pending_ = false; |
266 | 277 |
267 if (launch_elevated_) { | 278 if (launch_elevated_) { |
268 if (job_.IsValid()) | 279 if (job_.IsValid()) |
269 TerminateJobObject(job_.Get(), CONTROL_C_EXIT); | 280 TerminateJobObject(job_.Get(), CONTROL_C_EXIT); |
270 } else { | 281 } else { |
271 if (worker_process_.IsValid()) | 282 if (worker_process_.IsValid()) |
272 TerminateProcess(worker_process_.Get(), CONTROL_C_EXIT); | 283 TerminateProcess(worker_process_.Get(), CONTROL_C_EXIT); |
273 } | 284 } |
274 | 285 |
275 worker_process_.Close(); | 286 worker_process_.Close(); |
276 } | 287 } |
277 | 288 |
278 WtsSessionProcessDelegate::Core::~Core() { | 289 WtsSessionProcessDelegate::Core::~Core() { |
279 DCHECK(!channel_); | 290 DCHECK(!channel_); |
280 DCHECK(!event_handler_); | 291 DCHECK(!event_handler_); |
281 DCHECK(!pipe_.IsValid()); | |
282 DCHECK(!worker_process_.IsValid()); | 292 DCHECK(!worker_process_.IsValid()); |
283 } | 293 } |
284 | 294 |
285 void WtsSessionProcessDelegate::Core::OnIOCompleted( | 295 void WtsSessionProcessDelegate::Core::OnIOCompleted( |
286 base::MessagePumpForIO::IOContext* context, | 296 base::MessagePumpForIO::IOContext* context, |
287 DWORD bytes_transferred, | 297 DWORD bytes_transferred, |
288 DWORD error) { | 298 DWORD error) { |
289 DCHECK(io_task_runner_->BelongsToCurrentThread()); | 299 DCHECK(io_task_runner_->BelongsToCurrentThread()); |
290 | 300 |
291 // |bytes_transferred| is used in job object notifications to supply | 301 // |bytes_transferred| is used in job object notifications to supply |
292 // the message ID; |context| carries process ID. | 302 // the message ID; |context| carries process ID. |
293 if (bytes_transferred == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO) { | 303 switch (bytes_transferred) { |
294 caller_task_runner_->PostTask(FROM_HERE, | 304 case JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO: { |
295 base::Bind(&Core::OnActiveProcessZero, this)); | 305 caller_task_runner_->PostTask( |
306 FROM_HERE, base::Bind(&Core::OnActiveProcessZero, this)); | |
307 break; | |
308 } | |
309 case JOB_OBJECT_MSG_NEW_PROCESS: { | |
310 caller_task_runner_->PostTask( | |
311 FROM_HERE, base::Bind(&Core::OnProcessLaunchDetected, this, | |
312 reinterpret_cast<base::ProcessId>(context))); | |
313 break; | |
314 } | |
296 } | 315 } |
297 } | 316 } |
298 | 317 |
299 bool WtsSessionProcessDelegate::Core::OnMessageReceived( | 318 bool WtsSessionProcessDelegate::Core::OnMessageReceived( |
300 const IPC::Message& message) { | 319 const IPC::Message& message) { |
301 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 320 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
302 | 321 |
303 return event_handler_->OnMessageReceived(message); | 322 return event_handler_->OnMessageReceived(message); |
304 } | 323 } |
305 | 324 |
306 void WtsSessionProcessDelegate::Core::OnChannelConnected(int32_t peer_pid) { | 325 void WtsSessionProcessDelegate::Core::OnChannelConnected(int32_t peer_pid) { |
307 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 326 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
308 | 327 |
309 // Report the worker PID now if the worker process is launched indirectly. | |
310 // Note that in this case the pipe's security descriptor is the only | |
311 // protection against a malicious processed connecting to the pipe. | |
312 if (launch_elevated_) { | |
313 DWORD pid; | |
314 if (!get_named_pipe_client_pid_(pipe_.Get(), &pid)) { | |
315 PLOG(ERROR) << "Failed to retrive PID of the client"; | |
316 ReportFatalError(); | |
317 return; | |
318 } | |
319 | |
320 if (pid != static_cast<DWORD>(peer_pid)) { | |
321 LOG(ERROR) << "The actual client PID " << pid | |
322 << " does not match the one reported by the client: " | |
323 << peer_pid; | |
324 ReportFatalError(); | |
325 return; | |
326 } | |
327 | |
328 DWORD desired_access = | |
329 SYNCHRONIZE | PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION; | |
330 ScopedHandle worker_process(OpenProcess(desired_access, false, pid)); | |
331 if (!worker_process.IsValid()) { | |
332 PLOG(ERROR) << "Failed to open process " << pid; | |
333 ReportFatalError(); | |
334 return; | |
335 } | |
336 | |
337 ReportProcessLaunched(std::move(worker_process)); | |
338 } | |
339 | |
340 if (event_handler_) | 328 if (event_handler_) |
341 event_handler_->OnChannelConnected(peer_pid); | 329 event_handler_->OnChannelConnected(peer_pid); |
342 } | 330 } |
343 | 331 |
344 void WtsSessionProcessDelegate::Core::OnChannelError() { | 332 void WtsSessionProcessDelegate::Core::OnChannelError() { |
345 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 333 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
346 | 334 |
347 event_handler_->OnChannelError(); | 335 event_handler_->OnChannelError(); |
348 } | 336 } |
349 | 337 |
350 void WtsSessionProcessDelegate::Core::DoLaunchProcess() { | 338 void WtsSessionProcessDelegate::Core::DoLaunchProcess() { |
351 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 339 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
352 DCHECK(!channel_); | 340 DCHECK(!channel_); |
353 DCHECK(!pipe_.IsValid()); | |
354 DCHECK(!worker_process_.IsValid()); | 341 DCHECK(!worker_process_.IsValid()); |
355 | 342 |
356 base::CommandLine command_line(target_command_->argv()); | 343 base::CommandLine command_line(target_command_->argv()); |
357 if (launch_elevated_) { | 344 if (launch_elevated_) { |
358 // The job object is not ready. Retry starting the host process later. | 345 // The job object is not ready. Retry starting the host process later. |
359 if (!job_.IsValid()) { | 346 if (!job_.IsValid()) { |
360 launch_pending_ = true; | 347 launch_pending_ = true; |
361 return; | 348 return; |
362 } | 349 } |
363 | 350 |
364 // Construct the helper binary name. | 351 // Construct the helper binary name. |
365 base::FilePath helper_binary; | 352 base::FilePath helper_binary; |
366 if (!GetInstalledBinaryPath(kHostBinaryName, &helper_binary)) { | 353 if (!GetInstalledBinaryPath(kHostBinaryName, &helper_binary)) { |
367 ReportFatalError(); | 354 ReportFatalError(); |
368 return; | 355 return; |
369 } | 356 } |
370 | 357 |
371 // Create the command line passing the name of the IPC channel to use and | 358 // Create the command line passing the name of the IPC channel to use and |
372 // copying known switches from the caller's command line. | 359 // copying known switches from the caller's command line. |
373 command_line.SetProgram(helper_binary); | 360 command_line.SetProgram(helper_binary); |
374 command_line.AppendSwitchPath(kElevateSwitchName, | 361 command_line.AppendSwitchPath(kElevateSwitchName, |
375 target_command_->GetProgram()); | 362 target_command_->GetProgram()); |
376 } | 363 } |
377 | 364 |
378 // Create the server end of the IPC channel. | 365 const std::string mojo_message_pipe_token = mojo::edk::GenerateRandomToken(); |
379 std::string channel_name = IPC::Channel::GenerateUniqueRandomChannelID(); | 366 mojo_child_token_ = mojo::edk::GenerateRandomToken(); |
380 ScopedHandle pipe; | |
381 if (!CreateIpcChannel(channel_name, channel_security_, &pipe)) { | |
382 ReportFatalError(); | |
383 return; | |
384 } | |
385 | |
386 // Wrap the pipe into an IPC channel. | |
387 std::unique_ptr<IPC::ChannelProxy> channel( | 367 std::unique_ptr<IPC::ChannelProxy> channel( |
388 new IPC::ChannelProxy(this, io_task_runner_)); | 368 new IPC::ChannelProxy(this, io_task_runner_)); |
389 IPC::AttachmentBroker::GetGlobal()->RegisterCommunicationChannel( | 369 IPC::AttachmentBroker::GetGlobal()->RegisterCommunicationChannel( |
390 channel.get(), io_task_runner_); | 370 channel.get(), io_task_runner_); |
391 channel->Init(IPC::ChannelHandle(pipe.Get()), IPC::Channel::MODE_SERVER, | 371 channel->Init(mojo::edk::CreateParentMessagePipe(mojo_message_pipe_token, |
392 /*create_pipe_now=*/true); | 372 mojo_child_token_) |
373 .release(), | |
374 IPC::Channel::MODE_SERVER, /*create_pipe_now=*/true); | |
375 command_line.AppendSwitchASCII(kMojoPipeToken, mojo_message_pipe_token); | |
393 | 376 |
394 // Pass the name of the IPC channel to use. | 377 std::unique_ptr<mojo::edk::PlatformChannelPair> normal_mojo_channel; |
395 command_line.AppendSwitchNative(kDaemonPipeSwitchName, | 378 std::unique_ptr<mojo::edk::NamedPlatformChannelPair> elevated_mojo_channel; |
396 base::UTF8ToWide(channel_name)); | 379 base::HandlesToInheritVector handles_to_inherit; |
380 if (launch_elevated_) { | |
381 // Pass the name of the IPC channel to use. | |
382 mojo::edk::NamedPlatformChannelPair::Options options; | |
383 options.security_descriptor = base::UTF8ToUTF16(channel_security_); | |
384 elevated_mojo_channel = | |
385 base::MakeUnique<mojo::edk::NamedPlatformChannelPair>(options); | |
386 elevated_mojo_channel->PrepareToPassClientHandleToChildProcess( | |
387 &command_line); | |
388 } else { | |
389 normal_mojo_channel = base::MakeUnique<mojo::edk::PlatformChannelPair>(); | |
390 normal_mojo_channel->PrepareToPassClientHandleToChildProcess( | |
391 &command_line, &handles_to_inherit); | |
392 } | |
397 | 393 |
398 ScopedSd security_descriptor; | 394 ScopedSd security_descriptor; |
399 std::unique_ptr<SECURITY_ATTRIBUTES> security_attributes; | 395 std::unique_ptr<SECURITY_ATTRIBUTES> security_attributes; |
400 if (!new_process_security_.empty()) { | 396 if (!new_process_security_.empty()) { |
401 security_descriptor = ConvertSddlToSd(new_process_security_); | 397 security_descriptor = ConvertSddlToSd(new_process_security_); |
402 if (!security_descriptor) { | 398 if (!security_descriptor) { |
403 PLOG(ERROR) << "ConvertSddlToSd() failed."; | 399 PLOG(ERROR) << "ConvertSddlToSd() failed."; |
404 ReportFatalError(); | 400 ReportFatalError(); |
405 return; | 401 return; |
406 } | 402 } |
407 | 403 |
408 security_attributes.reset(new SECURITY_ATTRIBUTES()); | 404 security_attributes.reset(new SECURITY_ATTRIBUTES()); |
409 security_attributes->nLength = sizeof(SECURITY_ATTRIBUTES); | 405 security_attributes->nLength = sizeof(SECURITY_ATTRIBUTES); |
410 security_attributes->lpSecurityDescriptor = security_descriptor.get(); | 406 security_attributes->lpSecurityDescriptor = security_descriptor.get(); |
411 security_attributes->bInheritHandle = FALSE; | 407 security_attributes->bInheritHandle = FALSE; |
412 } | 408 } |
413 | 409 |
414 // Try to launch the process. | 410 // Try to launch the process. |
415 ScopedHandle worker_process; | 411 ScopedHandle worker_process; |
416 ScopedHandle worker_thread; | 412 ScopedHandle worker_thread; |
417 if (!LaunchProcessWithToken( | 413 if (!LaunchProcessWithToken( |
418 command_line.GetProgram(), command_line.GetCommandLineString(), | 414 command_line.GetProgram(), command_line.GetCommandLineString(), |
419 session_token_.Get(), security_attributes.get(), | 415 session_token_.Get(), security_attributes.get(), |
420 /* thread_attributes= */ nullptr, /* handles_to_inherit=*/{}, | 416 /* thread_attributes= */ nullptr, handles_to_inherit, |
421 /* creation_flags= */ CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB, | 417 /* creation_flags= */ CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB, |
422 base::UTF8ToUTF16(kDefaultDesktopName).c_str(), &worker_process, | 418 base::UTF8ToUTF16(kDefaultDesktopName).c_str(), &worker_process, |
423 &worker_thread)) { | 419 &worker_thread)) { |
424 ReportFatalError(); | 420 ReportFatalError(); |
425 return; | 421 return; |
426 } | 422 } |
427 | 423 |
428 if (launch_elevated_) { | 424 if (launch_elevated_) { |
429 if (!AssignProcessToJobObject(job_.Get(), worker_process.Get())) { | 425 if (!AssignProcessToJobObject(job_.Get(), worker_process.Get())) { |
430 PLOG(ERROR) << "Failed to assign the worker to the job object"; | 426 PLOG(ERROR) << "Failed to assign the worker to the job object"; |
431 ReportFatalError(); | 427 ReportFatalError(); |
432 return; | 428 return; |
433 } | 429 } |
434 } | 430 } |
435 | 431 |
436 if (!ResumeThread(worker_thread.Get())) { | 432 if (!ResumeThread(worker_thread.Get())) { |
437 PLOG(ERROR) << "Failed to resume the worker thread"; | 433 PLOG(ERROR) << "Failed to resume the worker thread"; |
438 ReportFatalError(); | 434 ReportFatalError(); |
439 return; | 435 return; |
440 } | 436 } |
441 | 437 |
442 channel_ = std::move(channel); | 438 channel_ = std::move(channel); |
443 pipe_ = std::move(pipe); | |
444 | 439 |
445 // Report success if the worker process is lauched directly. Otherwise, PID of | 440 if (launch_elevated_) { |
446 // the client connected to the pipe will be used later. See | 441 // When launching an elevated worker process, an intermediate launcher |
447 // OnChannelConnected(). | 442 // process launches the worker process. Reporting the launch waits until the |
448 if (!launch_elevated_) | 443 // worker process launch is detected. Until then, store the values needed in |
449 ReportProcessLaunched(std::move(worker_process)); | 444 // fields. See OnProcessLaunchDetected for their use. |
445 elevated_server_handle_ = elevated_mojo_channel->PassServerHandle(); | |
446 elevated_launcher_pid_ = GetProcessId(worker_process.Get()); | |
447 DCHECK(elevated_server_handle_.is_valid()); | |
448 } else { | |
449 ReportProcessLaunched(std::move(worker_process), | |
450 normal_mojo_channel->PassServerHandle()); | |
451 } | |
450 } | 452 } |
451 | 453 |
452 void WtsSessionProcessDelegate::Core::DrainJobNotifications() { | 454 void WtsSessionProcessDelegate::Core::DrainJobNotifications() { |
453 DCHECK(io_task_runner_->BelongsToCurrentThread()); | 455 DCHECK(io_task_runner_->BelongsToCurrentThread()); |
454 | 456 |
455 // DrainJobNotifications() is posted after the job object is destroyed, so | 457 // DrainJobNotifications() is posted after the job object is destroyed, so |
456 // by this time all notifications from the job object have been processed | 458 // by this time all notifications from the job object have been processed |
457 // already. Let the main thread know that the queue has been drained. | 459 // already. Let the main thread know that the queue has been drained. |
458 caller_task_runner_->PostTask(FROM_HERE, base::Bind( | 460 caller_task_runner_->PostTask(FROM_HERE, base::Bind( |
459 &Core::DrainJobNotificationsCompleted, this)); | 461 &Core::DrainJobNotificationsCompleted, this)); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
499 void WtsSessionProcessDelegate::Core::OnActiveProcessZero() { | 501 void WtsSessionProcessDelegate::Core::OnActiveProcessZero() { |
500 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 502 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
501 | 503 |
502 if (launch_pending_) { | 504 if (launch_pending_) { |
503 LOG(ERROR) << "The worker process exited before connecting via IPC."; | 505 LOG(ERROR) << "The worker process exited before connecting via IPC."; |
504 launch_pending_ = false; | 506 launch_pending_ = false; |
505 ReportFatalError(); | 507 ReportFatalError(); |
506 } | 508 } |
507 } | 509 } |
508 | 510 |
511 void WtsSessionProcessDelegate::Core::OnProcessLaunchDetected( | |
512 base::ProcessId pid) { | |
joedow
2016/10/26 21:48:20
Thanks for moving this out of the OnClientConnecte
Sam McNally
2016/10/27 00:43:46
Indeed, the connection will not be usable by anoth
| |
513 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | |
514 if (!elevated_server_handle_.is_valid()) | |
515 return; | |
516 | |
517 if (pid == elevated_launcher_pid_) | |
518 return; | |
519 | |
520 DWORD desired_access = | |
521 SYNCHRONIZE | PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION; | |
522 base::win::ScopedHandle worker_process( | |
523 OpenProcess(desired_access, false, pid)); | |
524 if (!worker_process.IsValid()) { | |
525 PLOG(ERROR) << "Failed to open process " << pid; | |
526 ReportFatalError(); | |
527 return; | |
528 } | |
529 elevated_launcher_pid_ = base::kNullProcessId; | |
530 ReportProcessLaunched(std::move(worker_process), | |
531 std::move(elevated_server_handle_)); | |
532 } | |
533 | |
509 void WtsSessionProcessDelegate::Core::ReportFatalError() { | 534 void WtsSessionProcessDelegate::Core::ReportFatalError() { |
510 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 535 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
511 | 536 |
512 CloseChannel(); | 537 CloseChannel(); |
513 | 538 |
514 WorkerProcessLauncher* event_handler = event_handler_; | 539 WorkerProcessLauncher* event_handler = event_handler_; |
515 event_handler_ = nullptr; | 540 event_handler_ = nullptr; |
516 event_handler->OnFatalError(); | 541 event_handler->OnFatalError(); |
517 } | 542 } |
518 | 543 |
519 void WtsSessionProcessDelegate::Core::ReportProcessLaunched( | 544 void WtsSessionProcessDelegate::Core::ReportProcessLaunched( |
520 base::win::ScopedHandle worker_process) { | 545 base::win::ScopedHandle worker_process, |
546 mojo::edk::ScopedPlatformHandle server_handle) { | |
521 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 547 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
522 DCHECK(!worker_process_.IsValid()); | 548 DCHECK(!worker_process_.IsValid()); |
523 | 549 |
550 mojo::edk::ChildProcessLaunched(worker_process.Get(), | |
551 std::move(server_handle), | |
552 mojo_child_token_); | |
553 mojo_child_token_.clear(); | |
524 worker_process_ = std::move(worker_process); | 554 worker_process_ = std::move(worker_process); |
525 | 555 |
526 // Report a handle that can be used to wait for the worker process completion, | 556 // Report a handle that can be used to wait for the worker process completion, |
527 // query information about the process and duplicate handles. | 557 // query information about the process and duplicate handles. |
528 DWORD desired_access = | 558 DWORD desired_access = |
529 SYNCHRONIZE | PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION; | 559 SYNCHRONIZE | PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION; |
530 HANDLE temp_handle; | 560 HANDLE temp_handle; |
531 if (!DuplicateHandle(GetCurrentProcess(), worker_process_.Get(), | 561 if (!DuplicateHandle(GetCurrentProcess(), worker_process_.Get(), |
532 GetCurrentProcess(), &temp_handle, desired_access, FALSE, | 562 GetCurrentProcess(), &temp_handle, desired_access, FALSE, |
533 0)) { | 563 0)) { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
569 | 599 |
570 void WtsSessionProcessDelegate::CloseChannel() { | 600 void WtsSessionProcessDelegate::CloseChannel() { |
571 core_->CloseChannel(); | 601 core_->CloseChannel(); |
572 } | 602 } |
573 | 603 |
574 void WtsSessionProcessDelegate::KillProcess() { | 604 void WtsSessionProcessDelegate::KillProcess() { |
575 core_->KillProcess(); | 605 core_->KillProcess(); |
576 } | 606 } |
577 | 607 |
578 } // namespace remoting | 608 } // namespace remoting |
OLD | NEW |