Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(460)

Side by Side Diff: remoting/host/wts_session_process_launcher_win.cc

Issue 9705065: Introducing the WorkerProcessLauncher class implementing the common logic for spawning a worker pro… (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: CR feedback Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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/wts_session_process_launcher_win.h" 8 #include "remoting/host/wts_session_process_launcher_win.h"
9 9
10 #include <windows.h> 10 #include <windows.h>
11 #include <sddl.h> 11 #include <sddl.h>
12 #include <limits>
13 12
13 #include "base/bind.h"
14 #include "base/bind_helpers.h"
14 #include "base/logging.h" 15 #include "base/logging.h"
15 #include "base/process_util.h" 16 #include "base/process_util.h"
16 #include "base/rand_util.h" 17 #include "base/rand_util.h"
17 #include "base/string16.h" 18 #include "base/string16.h"
18 #include "base/stringprintf.h" 19 #include "base/stringprintf.h"
19 #include "base/threading/thread.h" 20 #include "base/threading/thread.h"
20 #include "base/utf_string_conversions.h" 21 #include "base/utf_string_conversions.h"
21 #include "base/win/scoped_handle.h" 22 #include "base/win/scoped_handle.h"
22 #include "ipc/ipc_channel_proxy.h" 23 #include "ipc/ipc_channel_proxy.h"
23 #include "ipc/ipc_message.h" 24 #include "ipc/ipc_message.h"
24 #include "ipc/ipc_message_macros.h" 25 #include "ipc/ipc_message_macros.h"
25 26
26 #include "remoting/host/chromoting_messages.h" 27 #include "remoting/host/chromoting_messages.h"
27 #include "remoting/host/sas_injector.h" 28 #include "remoting/host/sas_injector.h"
29 #include "remoting/host/worker_process_launcher.h"
28 #include "remoting/host/wts_console_monitor_win.h" 30 #include "remoting/host/wts_console_monitor_win.h"
29 31
30 using base::win::ScopedHandle; 32 using base::win::ScopedHandle;
31 using base::TimeDelta; 33 using base::TimeDelta;
32 34
33 namespace { 35 namespace {
34 36
35 // The minimum and maximum delays between attempts to inject host process into 37 // The minimum and maximum delays between attempts to inject host process into
36 // a session. 38 // a session.
37 const int kMaxLaunchDelaySeconds = 60; 39 const int kMaxLaunchDelaySeconds = 60;
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
130 sizeof(new_session_id))) { 132 sizeof(new_session_id))) {
131 LOG_GETLASTERROR(ERROR) << 133 LOG_GETLASTERROR(ERROR) <<
132 "Failed to change session ID of a token"; 134 "Failed to change session ID of a token";
133 return false; 135 return false;
134 } 136 }
135 137
136 token_out->Set(session_token.Take()); 138 token_out->Set(session_token.Take());
137 return true; 139 return true;
138 } 140 }
139 141
140 // Generates random channel ID.
141 // N.B. Stolen from src/content/common/child_process_host_impl.cc
142 string16 GenerateRandomChannelId(void* instance) {
143 return base::StringPrintf(ASCIIToUTF16("%d.%p.%d").c_str(),
144 base::GetCurrentProcId(), instance,
145 base::RandInt(0, std::numeric_limits<int>::max()));
146 }
147
148 // Creates the server end of the Chromoting IPC channel.
149 // N.B. This code is based on IPC::Channel's implementation.
150 bool CreatePipeForIpcChannel(void* instance,
151 string16* channel_name_out,
152 ScopedHandle* pipe_out) {
153 // Create security descriptor for the channel.
154 SECURITY_ATTRIBUTES security_attributes;
155 security_attributes.nLength = sizeof(security_attributes);
156 security_attributes.bInheritHandle = FALSE;
157
158 ULONG security_descriptor_length = 0;
159 if (!ConvertStringSecurityDescriptorToSecurityDescriptorA(
160 kChromotingChannelSecurityDescriptor,
161 SDDL_REVISION_1,
162 reinterpret_cast<PSECURITY_DESCRIPTOR*>(
163 &security_attributes.lpSecurityDescriptor),
164 &security_descriptor_length)) {
165 LOG_GETLASTERROR(ERROR) <<
166 "Failed to create a security descriptor for the Chromoting IPC channel";
167 return false;
168 }
169
170 // Generate a random channel name.
171 string16 channel_name(GenerateRandomChannelId(instance));
172
173 // Convert it to the pipe name.
174 string16 pipe_name(ASCIIToUTF16(kChromePipeNamePrefix));
175 pipe_name.append(channel_name);
176
177 // Create the server end of the pipe. This code should match the code in
178 // IPC::Channel with exception of passing a non-default security descriptor.
179 HANDLE pipe = CreateNamedPipeW(pipe_name.c_str(),
180 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
181 FILE_FLAG_FIRST_PIPE_INSTANCE,
182 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
183 1,
184 IPC::Channel::kReadBufferSize,
185 IPC::Channel::kReadBufferSize,
186 5000,
187 &security_attributes);
188 if (pipe == INVALID_HANDLE_VALUE) {
189 LOG_GETLASTERROR(ERROR) <<
190 "Failed to create the server end of the Chromoting IPC channel";
191 LocalFree(security_attributes.lpSecurityDescriptor);
192 return false;
193 }
194
195 LocalFree(security_attributes.lpSecurityDescriptor);
196
197 *channel_name_out = channel_name;
198 pipe_out->Set(pipe);
199 return true;
200 }
201
202 // Launches |binary| in the security context of the supplied |user_token|. 142 // Launches |binary| in the security context of the supplied |user_token|.
203 bool LaunchProcessAsUser(const FilePath& binary, 143 bool LaunchProcessAsUser(const FilePath& binary,
204 const string16& command_line, 144 const string16& command_line,
205 HANDLE user_token, 145 HANDLE user_token,
206 base::Process* process_out) { 146 base::Process* process_out) {
207 string16 application_name = binary.value(); 147 string16 application_name = binary.value();
208 string16 desktop = ASCIIToUTF16(kDefaultDesktopName); 148 string16 desktop = ASCIIToUTF16(kDefaultDesktopName);
209 149
210 PROCESS_INFORMATION process_info; 150 PROCESS_INFORMATION process_info;
211 STARTUPINFOW startup_info; 151 STARTUPINFOW startup_info;
(...skipping 23 matching lines...) Expand all
235 return true; 175 return true;
236 } 176 }
237 177
238 } // namespace 178 } // namespace
239 179
240 namespace remoting { 180 namespace remoting {
241 181
242 WtsSessionProcessLauncher::WtsSessionProcessLauncher( 182 WtsSessionProcessLauncher::WtsSessionProcessLauncher(
243 WtsConsoleMonitor* monitor, 183 WtsConsoleMonitor* monitor,
244 const FilePath& host_binary, 184 const FilePath& host_binary,
245 base::Thread* io_thread) 185 scoped_refptr<base::MessageLoopProxy> ipc_message_loop)
246 : host_binary_(host_binary), 186 : host_binary_(host_binary),
247 io_thread_(io_thread), 187 ipc_message_loop_(ipc_message_loop),
248 monitor_(monitor), 188 monitor_(monitor) {
249 state_(StateDetached) {
250 monitor_->AddWtsConsoleObserver(this); 189 monitor_->AddWtsConsoleObserver(this);
251 } 190 }
252 191
253 WtsSessionProcessLauncher::~WtsSessionProcessLauncher() { 192 WtsSessionProcessLauncher::~WtsSessionProcessLauncher() {
254 DCHECK(state_ == StateDetached);
255 DCHECK(!timer_.IsRunning()); 193 DCHECK(!timer_.IsRunning());
256 DCHECK(process_.handle() == NULL);
257 DCHECK(process_watcher_.GetWatchedObject() == NULL);
258 DCHECK(chromoting_channel_.get() == NULL);
259 194
260 monitor_->RemoveWtsConsoleObserver(this); 195 monitor_->RemoveWtsConsoleObserver(this);
261 } 196 }
262 197
198 // Creates the server end of the Chromoting IPC channel.
199 // N.B. This code is based on IPC::Channel's implementation.
200 bool WtsSessionProcessLauncher::CreateChannelHandle(
201 const std::string& channel_name,
202 IPC::ChannelHandle* channel_handle_out) {
203
204 // Create security descriptor for the channel.
205 SECURITY_ATTRIBUTES security_attributes;
206 security_attributes.nLength = sizeof(security_attributes);
207 security_attributes.bInheritHandle = FALSE;
208
209 ULONG security_descriptor_length = 0;
210 if (!ConvertStringSecurityDescriptorToSecurityDescriptorA(
211 kChromotingChannelSecurityDescriptor,
212 SDDL_REVISION_1,
213 reinterpret_cast<PSECURITY_DESCRIPTOR*>(
214 &security_attributes.lpSecurityDescriptor),
215 &security_descriptor_length)) {
216 LOG_GETLASTERROR(ERROR) <<
217 "Failed to create a security descriptor for the Chromoting IPC channel";
218 return false;
219 }
220
221 // Convert it to the pipe name.
222 string16 pipe_name(ASCIIToUTF16(kChromePipeNamePrefix));
223 pipe_name.append(ASCIIToUTF16(channel_name));
224
225 // Create the server end of the pipe. This code should match the code in
226 // IPC::Channel with exception of passing a non-default security descriptor.
227 ipc_pipe_.Set(CreateNamedPipeW(pipe_name.c_str(),
228 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
229 FILE_FLAG_FIRST_PIPE_INSTANCE,
230 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
231 1,
232 IPC::Channel::kReadBufferSize,
233 IPC::Channel::kReadBufferSize,
234 5000,
235 &security_attributes));
236 if (!ipc_pipe_.IsValid()) {
237 LOG_GETLASTERROR(ERROR) <<
238 "Failed to create the server end of the Chromoting IPC channel";
239 LocalFree(security_attributes.lpSecurityDescriptor);
240 return false;
241 }
242
243 LocalFree(security_attributes.lpSecurityDescriptor);
244
245 *channel_handle_out = IPC::ChannelHandle(ipc_pipe_.Get());
246 return true;
247
248 }
249
250 bool WtsSessionProcessLauncher::LaunchWorker(const std::string& channel_name,
251 base::Process* process_out) {
252
253 string16 command_line =
254 base::StringPrintf(ASCIIToUTF16(kHostProcessCommandLineFormat).c_str(),
255 host_binary_.value().c_str(),
256 ASCIIToUTF16(channel_name).c_str());
257
258 return LaunchProcessAsUser(host_binary_, command_line, session_token_,
259 process_out);
260 }
261
263 void WtsSessionProcessLauncher::LaunchProcess() { 262 void WtsSessionProcessLauncher::LaunchProcess() {
264 DCHECK(state_ == StateStarting);
265 DCHECK(!timer_.IsRunning()); 263 DCHECK(!timer_.IsRunning());
266 DCHECK(process_.handle() == NULL);
267 DCHECK(process_watcher_.GetWatchedObject() == NULL);
268 DCHECK(chromoting_channel_.get() == NULL);
269 264
270 launch_time_ = base::Time::Now(); 265 launch_time_ = base::Time::Now();
266 launcher_.reset(new WorkerProcessLauncherWin(ipc_message_loop_));
267 bool success =
268 launcher_->Start(
269 this,
270 base::Bind(&WtsSessionProcessLauncher::CreateChannelHandle,
271 base::Unretained(this)),
272 base::Bind(&WtsSessionProcessLauncher::LaunchWorker,
273 base::Unretained(this)));
271 274
272 string16 channel_name; 275 // The pipe handle has been duplicated by the IPC::Channel. We can close our
273 ScopedHandle pipe; 276 // copy now.
274 if (CreatePipeForIpcChannel(this, &channel_name, &pipe)) { 277 ipc_pipe_.Close();
275 // Wrap the pipe into an IPC channel.
276 chromoting_channel_.reset(new IPC::ChannelProxy(
277 IPC::ChannelHandle(pipe.Get()),
278 IPC::Channel::MODE_SERVER,
279 this,
280 io_thread_->message_loop_proxy().get()));
281 278
282 string16 command_line = 279 if (!success) {
283 base::StringPrintf(ASCIIToUTF16(kHostProcessCommandLineFormat).c_str(), 280 // Something went wrong. Try to launch the host again later. The attempts
284 host_binary_.value().c_str(), 281 // rate is limited by exponential backoff.
285 channel_name.c_str()); 282 launch_backoff_ = std::max(launch_backoff_ * 2,
286 283 TimeDelta::FromSeconds(kMinLaunchDelaySeconds));
287 // Try to launch the process and attach an object watcher to the returned 284 launch_backoff_ = std::min(launch_backoff_,
288 // handle so that we get notified when the process terminates. 285 TimeDelta::FromSeconds(kMaxLaunchDelaySeconds));
289 if (LaunchProcessAsUser(host_binary_, command_line, session_token_, 286 timer_.Start(FROM_HERE, launch_backoff_,
290 &process_)) { 287 this, &WtsSessionProcessLauncher::LaunchProcess);
291 if (process_watcher_.StartWatching(process_.handle(), this)) {
292 state_ = StateAttached;
293 return;
294 } else {
295 LOG(ERROR) << "Failed to arm the process watcher.";
296 process_.Terminate(0);
297 process_.Close();
298 }
299 }
300
301 chromoting_channel_.reset();
302 } 288 }
303
304 // Something went wrong. Try to launch the host again later. The attempts rate
305 // is limited by exponential backoff.
306 launch_backoff_ = std::max(launch_backoff_ * 2,
307 TimeDelta::FromSeconds(kMinLaunchDelaySeconds));
308 launch_backoff_ = std::min(launch_backoff_,
309 TimeDelta::FromSeconds(kMaxLaunchDelaySeconds));
310 timer_.Start(FROM_HERE, launch_backoff_,
311 this, &WtsSessionProcessLauncher::LaunchProcess);
312 } 289 }
313 290
314 void WtsSessionProcessLauncher::OnObjectSignaled(HANDLE object) { 291 bool WtsSessionProcessLauncher::OnMessageReceived(const IPC::Message& message) {
315 DCHECK(state_ == StateAttached); 292 bool handled = true;
293 IPC_BEGIN_MESSAGE_MAP(WtsSessionProcessLauncher, message)
294 IPC_MESSAGE_HANDLER(ChromotingHostMsg_SendSasToConsole,
295 OnSendSasToConsole)
296 IPC_MESSAGE_UNHANDLED(handled = false)
297 IPC_END_MESSAGE_MAP()
298 return handled;
299 }
300
301 void WtsSessionProcessLauncher::OnChannelError() {
316 DCHECK(!timer_.IsRunning()); 302 DCHECK(!timer_.IsRunning());
317 DCHECK(process_.handle() != NULL);
318 DCHECK(process_watcher_.GetWatchedObject() == NULL);
319 DCHECK(chromoting_channel_.get() != NULL);
320
321 // The host process has been terminated for some reason. The handle can now be
322 // closed.
323 process_.Close();
324 chromoting_channel_.reset();
325 303
326 // Expand the backoff interval if the process has died quickly or reset it if 304 // Expand the backoff interval if the process has died quickly or reset it if
327 // it was up longer than the maximum backoff delay. 305 // the process was up longer than the maximum backoff delay.
328 base::TimeDelta delta = base::Time::Now() - launch_time_; 306 base::TimeDelta delta = base::Time::Now() - launch_time_;
329 if (delta < base::TimeDelta() || 307 if (delta < base::TimeDelta() ||
330 delta >= base::TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)) { 308 delta >= base::TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)) {
331 launch_backoff_ = base::TimeDelta(); 309 launch_backoff_ = base::TimeDelta();
332 } else { 310 } else {
333 launch_backoff_ = std::max(launch_backoff_ * 2, 311 launch_backoff_ = std::max(launch_backoff_ * 2,
334 TimeDelta::FromSeconds(kMinLaunchDelaySeconds)); 312 TimeDelta::FromSeconds(kMinLaunchDelaySeconds));
335 launch_backoff_ = std::min(launch_backoff_, 313 launch_backoff_ = std::min(launch_backoff_,
336 TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)); 314 TimeDelta::FromSeconds(kMaxLaunchDelaySeconds));
337 } 315 }
338 316
339 // Try to restart the host. 317 // Try to restart the host.
340 state_ = StateStarting;
341 timer_.Start(FROM_HERE, launch_backoff_, 318 timer_.Start(FROM_HERE, launch_backoff_,
342 this, &WtsSessionProcessLauncher::LaunchProcess); 319 this, &WtsSessionProcessLauncher::LaunchProcess);
343 } 320 }
344 321
345 bool WtsSessionProcessLauncher::OnMessageReceived(const IPC::Message& message) { 322 void WtsSessionProcessLauncher::OnSendSasToConsole() {
346 bool handled = true; 323 if (sas_injector_.get() == NULL) {
347 IPC_BEGIN_MESSAGE_MAP(WtsSessionProcessLauncher, message) 324 sas_injector_ = SasInjector::Create();
348 IPC_MESSAGE_HANDLER(ChromotingHostMsg_SendSasToConsole, 325 }
349 OnSendSasToConsole)
350 IPC_MESSAGE_UNHANDLED(handled = false)
351 IPC_END_MESSAGE_MAP()
352 return handled;
353 }
354 326
355 void WtsSessionProcessLauncher::OnSendSasToConsole() { 327 if (sas_injector_.get() != NULL) {
356 if (state_ == StateAttached) { 328 sas_injector_->InjectSas();
357 if (sas_injector_.get() == NULL) {
358 sas_injector_ = SasInjector::Create();
359 }
360
361 if (sas_injector_.get() != NULL) {
362 sas_injector_->InjectSas();
363 }
364 } 329 }
365 } 330 }
366 331
367 void WtsSessionProcessLauncher::OnSessionAttached(uint32 session_id) { 332 void WtsSessionProcessLauncher::OnSessionAttached(uint32 session_id) {
368 DCHECK(state_ == StateDetached);
369 DCHECK(!timer_.IsRunning()); 333 DCHECK(!timer_.IsRunning());
370 DCHECK(process_.handle() == NULL);
371 DCHECK(process_watcher_.GetWatchedObject() == NULL);
372 DCHECK(chromoting_channel_.get() == NULL);
373 334
374 // Temporarily enable the SE_TCB_NAME privilege. The privileged token is 335 // Temporarily enable the SE_TCB_NAME privilege. The privileged token is
375 // created as needed and kept for later reuse. 336 // created as needed and kept for later reuse.
376 if (privileged_token_.Get() == NULL) { 337 if (privileged_token_.Get() == NULL) {
377 if (!CreatePrivilegedToken(&privileged_token_)) { 338 if (!CreatePrivilegedToken(&privileged_token_)) {
378 return; 339 return;
379 } 340 }
380 } 341 }
381 342
382 if (!ImpersonateLoggedOnUser(privileged_token_)) { 343 if (!ImpersonateLoggedOnUser(privileged_token_)) {
383 LOG_GETLASTERROR(ERROR) << 344 LOG_GETLASTERROR(ERROR) <<
384 "Failed to impersonate the privileged token"; 345 "Failed to impersonate the privileged token";
385 return; 346 return;
386 } 347 }
387 348
388 // While the SE_TCB_NAME privilege is enabled, create a session token for 349 // While the SE_TCB_NAME privilege is enabled, create a session token for
389 // the launched process. 350 // the launched process.
390 bool result = CreateSessionToken(session_id, &session_token_); 351 bool result = CreateSessionToken(session_id, &session_token_);
391 352
392 // Revert to the default token. The default token is sufficient to call 353 // Revert to the default token. The default token is sufficient to call
393 // CreateProcessAsUser() successfully. 354 // CreateProcessAsUser() successfully.
394 CHECK(RevertToSelf()); 355 CHECK(RevertToSelf());
395 356
396 if (!result)
397 return;
398
399 // Now try to launch the host. 357 // Now try to launch the host.
400 state_ = StateStarting; 358 if (result) {
401 LaunchProcess(); 359 LaunchProcess();
360 }
402 } 361 }
403 362
404 void WtsSessionProcessLauncher::OnSessionDetached() { 363 void WtsSessionProcessLauncher::OnSessionDetached() {
405 DCHECK(state_ == StateDetached || 364 launch_backoff_ = base::TimeDelta();
406 state_ == StateStarting || 365 timer_.Stop();
407 state_ == StateAttached); 366 launcher_.reset();
408
409 switch (state_) {
410 case StateDetached:
411 DCHECK(!timer_.IsRunning());
412 DCHECK(process_.handle() == NULL);
413 DCHECK(process_watcher_.GetWatchedObject() == NULL);
414 DCHECK(chromoting_channel_.get() == NULL);
415 break;
416
417 case StateStarting:
418 DCHECK(timer_.IsRunning());
419 DCHECK(process_.handle() == NULL);
420 DCHECK(process_watcher_.GetWatchedObject() == NULL);
421 DCHECK(chromoting_channel_.get() == NULL);
422
423 timer_.Stop();
424 launch_backoff_ = base::TimeDelta();
425 state_ = StateDetached;
426 break;
427
428 case StateAttached:
429 DCHECK(!timer_.IsRunning());
430 DCHECK(process_.handle() != NULL);
431 DCHECK(process_watcher_.GetWatchedObject() != NULL);
432 DCHECK(chromoting_channel_.get() != NULL);
433
434 process_watcher_.StopWatching();
435 process_.Terminate(0);
436 process_.Close();
437 chromoting_channel_.reset();
438 state_ = StateDetached;
439 break;
440 }
441 } 367 }
442 368
443 } // namespace remoting 369 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698