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

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

Issue 9617027: Chromoting: Implemented security attention sequence (SAS) emulation on Windows. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: - 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
« no previous file with comments | « remoting/host/wts_session_process_launcher_win.h ('k') | remoting/remoting.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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>
12 #include <limits>
11 13
12 #include "base/logging.h" 14 #include "base/logging.h"
15 #include "base/process_util.h"
16 #include "base/rand_util.h"
17 #include "base/string16.h"
18 #include "base/stringprintf.h"
19 #include "base/threading/thread.h"
13 #include "base/utf_string_conversions.h" 20 #include "base/utf_string_conversions.h"
14 #include "base/win/scoped_handle.h" 21 #include "base/win/scoped_handle.h"
22 #include "ipc/ipc_channel_proxy.h"
23 #include "ipc/ipc_message.h"
24 #include "ipc/ipc_message_macros.h"
15 25
26 #include "remoting/host/chromoting_messages.h"
27 #include "remoting/host/sas_injector.h"
16 #include "remoting/host/wts_console_monitor_win.h" 28 #include "remoting/host/wts_console_monitor_win.h"
17 29
18 using base::win::ScopedHandle; 30 using base::win::ScopedHandle;
19 using base::TimeDelta; 31 using base::TimeDelta;
20 32
21 namespace { 33 namespace {
22 34
23 // The minimum and maximum delays between attempts to inject host process into 35 // The minimum and maximum delays between attempts to inject host process into
24 // a session. 36 // a session.
25 const int kMaxLaunchDelaySeconds = 60; 37 const int kMaxLaunchDelaySeconds = 60;
26 const int kMinLaunchDelaySeconds = 1; 38 const int kMinLaunchDelaySeconds = 1;
27 39
28 // Name of the default session desktop. 40 // Name of the default session desktop.
29 const char kDefaultDesktopName[] = "winsta0\\default"; 41 const char kDefaultDesktopName[] = "winsta0\\default";
30 42
43 // Match the pipe name prefix used by Chrome IPC channels.
44 const char kChromePipeNamePrefix[] = "\\\\.\\pipe\\chrome.";
45
46 // Generates the command line of the host process.
47 const char kHostProcessCommandLineFormat[] = "\"%ls\" --channel=%ls";
48
49 // The security descriptor of the Chromoting IPC channel. It gives full access
50 // to LocalSystem and denies access by anyone else.
51 const char kChromotingChannelSecurityDescriptor[] =
52 "O:SY" "G:SY" "D:(A;;GA;;;SY)";
53
31 // Takes the process token and makes a copy of it. The returned handle will have 54 // Takes the process token and makes a copy of it. The returned handle will have
32 // |desired_access| rights. 55 // |desired_access| rights.
33 bool CopyProcessToken(DWORD desired_access, 56 bool CopyProcessToken(DWORD desired_access,
34 ScopedHandle* token_out) { 57 ScopedHandle* token_out) {
35 58
36 HANDLE handle; 59 HANDLE handle;
37 if (!OpenProcessToken(GetCurrentProcess(), 60 if (!OpenProcessToken(GetCurrentProcess(),
38 TOKEN_DUPLICATE | desired_access, 61 TOKEN_DUPLICATE | desired_access,
39 &handle)) { 62 &handle)) {
40 LOG_GETLASTERROR(ERROR) << "Failed to open process token"; 63 LOG_GETLASTERROR(ERROR) << "Failed to open process token";
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
107 sizeof(new_session_id))) { 130 sizeof(new_session_id))) {
108 LOG_GETLASTERROR(ERROR) << 131 LOG_GETLASTERROR(ERROR) <<
109 "Failed to change session ID of a token"; 132 "Failed to change session ID of a token";
110 return false; 133 return false;
111 } 134 }
112 135
113 token_out->Set(session_token.Take()); 136 token_out->Set(session_token.Take());
114 return true; 137 return true;
115 } 138 }
116 139
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
117 // Launches |binary| in the security context of the supplied |user_token|. 202 // Launches |binary| in the security context of the supplied |user_token|.
118 bool LaunchProcessAsUser(const FilePath& binary, 203 bool LaunchProcessAsUser(const FilePath& binary,
204 const string16& command_line,
119 HANDLE user_token, 205 HANDLE user_token,
120 base::Process* process_out) { 206 base::Process* process_out) {
121 string16 command_line = binary.value(); 207 string16 application_name = binary.value();
122 string16 desktop = ASCIIToUTF16(kDefaultDesktopName); 208 string16 desktop = ASCIIToUTF16(kDefaultDesktopName);
123 209
124 PROCESS_INFORMATION process_info; 210 PROCESS_INFORMATION process_info;
125 STARTUPINFOW startup_info; 211 STARTUPINFOW startup_info;
126 212
127 memset(&startup_info, 0, sizeof(startup_info)); 213 memset(&startup_info, 0, sizeof(startup_info));
128 startup_info.cb = sizeof(startup_info); 214 startup_info.cb = sizeof(startup_info);
129 startup_info.lpDesktop = const_cast<LPWSTR>(desktop.c_str()); 215 startup_info.lpDesktop = const_cast<LPWSTR>(desktop.c_str());
130 216
131 if (!CreateProcessAsUserW(user_token, 217 if (!CreateProcessAsUserW(user_token,
132 command_line.c_str(), 218 application_name.c_str(),
133 const_cast<LPWSTR>(command_line.c_str()), 219 const_cast<LPWSTR>(command_line.c_str()),
134 NULL, 220 NULL,
135 NULL, 221 NULL,
136 FALSE, 222 FALSE,
137 0, 223 0,
138 NULL, 224 NULL,
139 NULL, 225 NULL,
140 &startup_info, 226 &startup_info,
141 &process_info)) { 227 &process_info)) {
142 LOG_GETLASTERROR(ERROR) << 228 LOG_GETLASTERROR(ERROR) <<
143 "Failed to launch a process with a user token"; 229 "Failed to launch a process with a user token";
144 return false; 230 return false;
145 } 231 }
146 232
147 CloseHandle(process_info.hThread); 233 CloseHandle(process_info.hThread);
148 process_out->set_handle(process_info.hProcess); 234 process_out->set_handle(process_info.hProcess);
149 return true; 235 return true;
150 } 236 }
151 237
152 } // namespace 238 } // namespace
153 239
154 namespace remoting { 240 namespace remoting {
155 241
156 WtsSessionProcessLauncher::WtsSessionProcessLauncher( 242 WtsSessionProcessLauncher::WtsSessionProcessLauncher(
157 WtsConsoleMonitor* monitor, 243 WtsConsoleMonitor* monitor,
158 const FilePath& host_binary) 244 const FilePath& host_binary,
245 base::Thread* io_thread)
159 : host_binary_(host_binary), 246 : host_binary_(host_binary),
247 io_thread_(io_thread),
160 monitor_(monitor), 248 monitor_(monitor),
161 state_(StateDetached) { 249 state_(StateDetached) {
162 monitor_->AddWtsConsoleObserver(this); 250 monitor_->AddWtsConsoleObserver(this);
163 } 251 }
164 252
165 WtsSessionProcessLauncher::~WtsSessionProcessLauncher() { 253 WtsSessionProcessLauncher::~WtsSessionProcessLauncher() {
166 DCHECK(state_ == StateDetached); 254 DCHECK(state_ == StateDetached);
167 DCHECK(!timer_.IsRunning()); 255 DCHECK(!timer_.IsRunning());
168 DCHECK(process_.handle() == NULL); 256 DCHECK(process_.handle() == NULL);
169 DCHECK(process_watcher_.GetWatchedObject() == NULL); 257 DCHECK(process_watcher_.GetWatchedObject() == NULL);
258 DCHECK(chromoting_channel_.get() == NULL);
170 259
171 monitor_->RemoveWtsConsoleObserver(this); 260 monitor_->RemoveWtsConsoleObserver(this);
172 } 261 }
173 262
174 void WtsSessionProcessLauncher::LaunchProcess() { 263 void WtsSessionProcessLauncher::LaunchProcess() {
175 DCHECK(state_ == StateStarting); 264 DCHECK(state_ == StateStarting);
176 DCHECK(!timer_.IsRunning()); 265 DCHECK(!timer_.IsRunning());
177 DCHECK(process_.handle() == NULL); 266 DCHECK(process_.handle() == NULL);
178 DCHECK(process_watcher_.GetWatchedObject() == NULL); 267 DCHECK(process_watcher_.GetWatchedObject() == NULL);
268 DCHECK(chromoting_channel_.get() == NULL);
179 269
180 // Try to launch the process and attach an object watcher to the returned
181 // handle so that we get notified when the process terminates.
182 launch_time_ = base::Time::Now(); 270 launch_time_ = base::Time::Now();
183 if (LaunchProcessAsUser(host_binary_, session_token_, &process_)) { 271
184 if (process_watcher_.StartWatching(process_.handle(), this)) { 272 string16 channel_name;
185 state_ = StateAttached; 273 ScopedHandle pipe;
186 return; 274 if (CreatePipeForIpcChannel(this, &channel_name, &pipe)) {
187 } else { 275 // Wrap the pipe into an IPC channel.
188 LOG(ERROR) << "Failed to arm the process watcher."; 276 chromoting_channel_.reset(new IPC::ChannelProxy(
189 process_.Terminate(0); 277 IPC::ChannelHandle(pipe.Get()),
190 process_.Close(); 278 IPC::Channel::MODE_SERVER,
279 this,
280 io_thread_->message_loop_proxy().get()));
281
282 string16 command_line =
283 base::StringPrintf(ASCIIToUTF16(kHostProcessCommandLineFormat).c_str(),
284 host_binary_.value().c_str(),
285 channel_name.c_str());
286
287 // Try to launch the process and attach an object watcher to the returned
288 // handle so that we get notified when the process terminates.
289 if (LaunchProcessAsUser(host_binary_, command_line, session_token_,
290 &process_)) {
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 }
191 } 299 }
300
301 chromoting_channel_.reset();
192 } 302 }
193 303
194 // Something went wrong. Try to launch the host again later. The attempts rate 304 // Something went wrong. Try to launch the host again later. The attempts rate
195 // is limited by exponential backoff. 305 // is limited by exponential backoff.
196 launch_backoff_ = std::max(launch_backoff_ * 2, 306 launch_backoff_ = std::max(launch_backoff_ * 2,
197 TimeDelta::FromSeconds(kMinLaunchDelaySeconds)); 307 TimeDelta::FromSeconds(kMinLaunchDelaySeconds));
198 launch_backoff_ = std::min(launch_backoff_, 308 launch_backoff_ = std::min(launch_backoff_,
199 TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)); 309 TimeDelta::FromSeconds(kMaxLaunchDelaySeconds));
200 timer_.Start(FROM_HERE, launch_backoff_, 310 timer_.Start(FROM_HERE, launch_backoff_,
201 this, &WtsSessionProcessLauncher::LaunchProcess); 311 this, &WtsSessionProcessLauncher::LaunchProcess);
202 } 312 }
203 313
204 void WtsSessionProcessLauncher::OnObjectSignaled(HANDLE object) { 314 void WtsSessionProcessLauncher::OnObjectSignaled(HANDLE object) {
205 DCHECK(state_ == StateAttached); 315 DCHECK(state_ == StateAttached);
206 DCHECK(!timer_.IsRunning()); 316 DCHECK(!timer_.IsRunning());
207 DCHECK(process_.handle() != NULL); 317 DCHECK(process_.handle() != NULL);
208 DCHECK(process_watcher_.GetWatchedObject() == NULL); 318 DCHECK(process_watcher_.GetWatchedObject() == NULL);
319 DCHECK(chromoting_channel_.get() != NULL);
209 320
210 // The host process has been terminated for some reason. The handle can now be 321 // The host process has been terminated for some reason. The handle can now be
211 // closed. 322 // closed.
212 process_.Close(); 323 process_.Close();
324 chromoting_channel_.reset();
213 325
214 // Expand the backoff interval if the process has died quickly or reset it if 326 // Expand the backoff interval if the process has died quickly or reset it if
215 // it was up longer than the maximum backoff delay. 327 // it was up longer than the maximum backoff delay.
216 base::TimeDelta delta = base::Time::Now() - launch_time_; 328 base::TimeDelta delta = base::Time::Now() - launch_time_;
217 if (delta < base::TimeDelta() || 329 if (delta < base::TimeDelta() ||
218 delta >= base::TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)) { 330 delta >= base::TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)) {
219 launch_backoff_ = base::TimeDelta(); 331 launch_backoff_ = base::TimeDelta();
220 } else { 332 } else {
221 launch_backoff_ = std::max(launch_backoff_ * 2, 333 launch_backoff_ = std::max(launch_backoff_ * 2,
222 TimeDelta::FromSeconds(kMinLaunchDelaySeconds)); 334 TimeDelta::FromSeconds(kMinLaunchDelaySeconds));
223 launch_backoff_ = std::min(launch_backoff_, 335 launch_backoff_ = std::min(launch_backoff_,
224 TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)); 336 TimeDelta::FromSeconds(kMaxLaunchDelaySeconds));
225 } 337 }
226 338
227 // Try to restart the host. 339 // Try to restart the host.
228 state_ = StateStarting; 340 state_ = StateStarting;
229 timer_.Start(FROM_HERE, launch_backoff_, 341 timer_.Start(FROM_HERE, launch_backoff_,
230 this, &WtsSessionProcessLauncher::LaunchProcess); 342 this, &WtsSessionProcessLauncher::LaunchProcess);
231 } 343 }
232 344
345 bool WtsSessionProcessLauncher::OnMessageReceived(const IPC::Message& message) {
346 bool handled = true;
347 IPC_BEGIN_MESSAGE_MAP(WtsSessionProcessLauncher, message)
348 IPC_MESSAGE_HANDLER(ChromotingHostMsg_SendSasToConsole,
349 OnSendSasToConsole)
350 IPC_MESSAGE_UNHANDLED(handled = false)
351 IPC_END_MESSAGE_MAP()
352 return handled;
353 }
354
355 void WtsSessionProcessLauncher::OnSendSasToConsole() {
356 if (state_ == StateAttached) {
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 }
365 }
366
233 void WtsSessionProcessLauncher::OnSessionAttached(uint32 session_id) { 367 void WtsSessionProcessLauncher::OnSessionAttached(uint32 session_id) {
234 DCHECK(state_ == StateDetached); 368 DCHECK(state_ == StateDetached);
235 DCHECK(!timer_.IsRunning()); 369 DCHECK(!timer_.IsRunning());
236 DCHECK(process_.handle() == NULL); 370 DCHECK(process_.handle() == NULL);
237 DCHECK(process_watcher_.GetWatchedObject() == NULL); 371 DCHECK(process_watcher_.GetWatchedObject() == NULL);
372 DCHECK(chromoting_channel_.get() == NULL);
238 373
239 // Temporarily enable the SE_TCB_NAME privilege. The privileged token is 374 // Temporarily enable the SE_TCB_NAME privilege. The privileged token is
240 // created as needed and kept for later reuse. 375 // created as needed and kept for later reuse.
241 if (privileged_token_.Get() == NULL) { 376 if (privileged_token_.Get() == NULL) {
242 if (!CreatePrivilegedToken(&privileged_token_)) { 377 if (!CreatePrivilegedToken(&privileged_token_)) {
243 return; 378 return;
244 } 379 }
245 } 380 }
246 381
247 if (!ImpersonateLoggedOnUser(privileged_token_)) { 382 if (!ImpersonateLoggedOnUser(privileged_token_)) {
248 LOG_GETLASTERROR(ERROR) << 383 LOG_GETLASTERROR(ERROR) <<
249 "Failed to impersonate the privileged token"; 384 "Failed to impersonate the privileged token";
250 return; 385 return;
251 } 386 }
252 387
253 // While the SE_TCB_NAME progolege is enabled, create a session token for 388 // While the SE_TCB_NAME privilege is enabled, create a session token for
254 // the launched process. 389 // the launched process.
255 bool result = CreateSessionToken(session_id, &session_token_); 390 bool result = CreateSessionToken(session_id, &session_token_);
256 391
257 // Revert to the default token. The default token is sufficient to call 392 // Revert to the default token. The default token is sufficient to call
258 // CreateProcessAsUser() successfully. 393 // CreateProcessAsUser() successfully.
259 CHECK(RevertToSelf()); 394 CHECK(RevertToSelf());
260 395
261 if (!result) 396 if (!result)
262 return; 397 return;
263 398
264 // Now try to launch the host. 399 // Now try to launch the host.
265 state_ = StateStarting; 400 state_ = StateStarting;
266 LaunchProcess(); 401 LaunchProcess();
267 } 402 }
268 403
269 void WtsSessionProcessLauncher::OnSessionDetached() { 404 void WtsSessionProcessLauncher::OnSessionDetached() {
270 DCHECK(state_ == StateDetached || 405 DCHECK(state_ == StateDetached ||
271 state_ == StateStarting || 406 state_ == StateStarting ||
272 state_ == StateAttached); 407 state_ == StateAttached);
273 408
274 switch (state_) { 409 switch (state_) {
275 case StateDetached: 410 case StateDetached:
276 DCHECK(!timer_.IsRunning()); 411 DCHECK(!timer_.IsRunning());
277 DCHECK(process_.handle() == NULL); 412 DCHECK(process_.handle() == NULL);
278 DCHECK(process_watcher_.GetWatchedObject() == NULL); 413 DCHECK(process_watcher_.GetWatchedObject() == NULL);
414 DCHECK(chromoting_channel_.get() == NULL);
279 break; 415 break;
280 416
281 case StateStarting: 417 case StateStarting:
282 DCHECK(timer_.IsRunning()); 418 DCHECK(timer_.IsRunning());
283 DCHECK(process_.handle() == NULL); 419 DCHECK(process_.handle() == NULL);
284 DCHECK(process_watcher_.GetWatchedObject() == NULL); 420 DCHECK(process_watcher_.GetWatchedObject() == NULL);
421 DCHECK(chromoting_channel_.get() == NULL);
285 422
286 timer_.Stop(); 423 timer_.Stop();
287 launch_backoff_ = base::TimeDelta(); 424 launch_backoff_ = base::TimeDelta();
288 state_ = StateDetached; 425 state_ = StateDetached;
289 break; 426 break;
290 427
291 case StateAttached: 428 case StateAttached:
292 DCHECK(!timer_.IsRunning()); 429 DCHECK(!timer_.IsRunning());
293 DCHECK(process_.handle() != NULL); 430 DCHECK(process_.handle() != NULL);
294 DCHECK(process_watcher_.GetWatchedObject() != NULL); 431 DCHECK(process_watcher_.GetWatchedObject() != NULL);
432 DCHECK(chromoting_channel_.get() != NULL);
295 433
296 process_watcher_.StopWatching(); 434 process_watcher_.StopWatching();
297 process_.Terminate(0); 435 process_.Terminate(0);
298 process_.Close(); 436 process_.Close();
437 chromoting_channel_.reset();
299 state_ = StateDetached; 438 state_ = StateDetached;
300 break; 439 break;
301 } 440 }
302 } 441 }
303 442
304 } // namespace remoting 443 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/host/wts_session_process_launcher_win.h ('k') | remoting/remoting.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698