Chromium Code Reviews| 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/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 | 11 |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/threading/thread.h" | |
| 13 #include "base/utf_string_conversions.h" | 14 #include "base/utf_string_conversions.h" |
| 14 #include "base/win/scoped_handle.h" | 15 #include "base/win/scoped_handle.h" |
| 16 #include "ipc/ipc_channel_proxy.h" | |
| 17 #include "ipc/ipc_message.h" | |
| 18 #include "ipc/ipc_message_macros.h" | |
| 15 | 19 |
| 20 #include "remoting/host/chromoting_service_messages.h" | |
| 21 #include "remoting/host/sas_sender_win.h" | |
| 16 #include "remoting/host/wts_console_monitor_win.h" | 22 #include "remoting/host/wts_console_monitor_win.h" |
| 17 | 23 |
| 18 using base::win::ScopedHandle; | 24 using base::win::ScopedHandle; |
| 19 using base::TimeDelta; | 25 using base::TimeDelta; |
| 20 | 26 |
| 21 namespace { | 27 namespace { |
| 22 | 28 |
| 23 // The minimum and maximum delays between attempts to inject host process into | 29 // The minimum and maximum delays between attempts to inject host process into |
| 24 // a session. | 30 // a session. |
| 25 const int kMaxLaunchDelaySeconds = 60; | 31 const int kMaxLaunchDelaySeconds = 60; |
| 26 const int kMinLaunchDelaySeconds = 1; | 32 const int kMinLaunchDelaySeconds = 1; |
| 27 | 33 |
| 28 // Name of the default session desktop. | 34 // Name of the default session desktop. |
| 29 const char kDefaultDesktopName[] = "winsta0\\default"; | 35 const char kDefaultDesktopName[] = "winsta0\\default"; |
| 30 | 36 |
| 37 // Name of the chromoting service IPC channel. | |
| 38 const char kChromotingServiceChannelName[] = "chromoting_service"; | |
| 39 | |
| 31 // Takes the process token and makes a copy of it. The returned handle will have | 40 // Takes the process token and makes a copy of it. The returned handle will have |
| 32 // |desired_access| rights. | 41 // |desired_access| rights. |
| 33 bool CopyProcessToken(DWORD desired_access, | 42 bool CopyProcessToken(DWORD desired_access, |
| 34 ScopedHandle* token_out) { | 43 ScopedHandle* token_out) { |
| 35 | 44 |
| 36 HANDLE handle; | 45 HANDLE handle; |
| 37 if (!OpenProcessToken(GetCurrentProcess(), | 46 if (!OpenProcessToken(GetCurrentProcess(), |
| 38 TOKEN_DUPLICATE | desired_access, | 47 TOKEN_DUPLICATE | desired_access, |
| 39 &handle)) { | 48 &handle)) { |
| 40 LOG_GETLASTERROR(ERROR) << "Failed to open process token"; | 49 LOG_GETLASTERROR(ERROR) << "Failed to open process token"; |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 148 process_out->set_handle(process_info.hProcess); | 157 process_out->set_handle(process_info.hProcess); |
| 149 return true; | 158 return true; |
| 150 } | 159 } |
| 151 | 160 |
| 152 } // namespace | 161 } // namespace |
| 153 | 162 |
| 154 namespace remoting { | 163 namespace remoting { |
| 155 | 164 |
| 156 WtsSessionProcessLauncher::WtsSessionProcessLauncher( | 165 WtsSessionProcessLauncher::WtsSessionProcessLauncher( |
| 157 WtsConsoleMonitor* monitor, | 166 WtsConsoleMonitor* monitor, |
| 158 const FilePath& host_binary) | 167 const FilePath& host_binary, |
| 168 base::Thread* io_thread) | |
| 159 : host_binary_(host_binary), | 169 : host_binary_(host_binary), |
| 170 io_thread_(io_thread), | |
| 160 monitor_(monitor), | 171 monitor_(monitor), |
| 161 state_(StateDetached) { | 172 state_(StateDetached) { |
| 162 monitor_->AddWtsConsoleObserver(this); | 173 monitor_->AddWtsConsoleObserver(this); |
| 163 } | 174 } |
| 164 | 175 |
| 165 WtsSessionProcessLauncher::~WtsSessionProcessLauncher() { | 176 WtsSessionProcessLauncher::~WtsSessionProcessLauncher() { |
| 166 DCHECK(state_ == StateDetached); | 177 DCHECK(state_ == StateDetached); |
| 167 DCHECK(!timer_.IsRunning()); | 178 DCHECK(!timer_.IsRunning()); |
| 168 DCHECK(process_.handle() == NULL); | 179 DCHECK(process_.handle() == NULL); |
| 169 DCHECK(process_watcher_.GetWatchedObject() == NULL); | 180 DCHECK(process_watcher_.GetWatchedObject() == NULL); |
| 181 DCHECK(chromoting_service_.get() == NULL); | |
| 170 | 182 |
| 171 monitor_->RemoveWtsConsoleObserver(this); | 183 monitor_->RemoveWtsConsoleObserver(this); |
| 172 } | 184 } |
| 173 | 185 |
| 174 void WtsSessionProcessLauncher::LaunchProcess() { | 186 void WtsSessionProcessLauncher::LaunchProcess() { |
| 175 DCHECK(state_ == StateStarting); | 187 DCHECK(state_ == StateStarting); |
| 176 DCHECK(!timer_.IsRunning()); | 188 DCHECK(!timer_.IsRunning()); |
| 177 DCHECK(process_.handle() == NULL); | 189 DCHECK(process_.handle() == NULL); |
| 178 DCHECK(process_watcher_.GetWatchedObject() == NULL); | 190 DCHECK(process_watcher_.GetWatchedObject() == NULL); |
| 191 DCHECK(chromoting_service_.get() == NULL); | |
| 192 | |
| 193 launch_time_ = base::Time::Now(); | |
| 194 | |
| 195 // Create the chromoting service IPC channel on the I/O thread. | |
| 196 // N.B. IPC::Channel passes NULL security attributes pointer to | |
| 197 // CreateNamedPipe() so the pipe gets a default security descriptor. | |
| 198 // The ACLs in the default security descriptor for a named pipe grant | |
| 199 // full control to the LocalSystem account, administrators, and | |
| 200 // the creator owner. They also grant read access to members of the | |
| 201 // Everyone group and the anonymous account. | |
|
Wez
2012/03/07 01:56:13
nit: Clarify why read access is not an issue?
alexeypa (please no reviews)
2012/03/07 19:59:08
See PIPE_ACCESS_DUPLEX below
| |
| 202 // | |
| 203 // IPC::Channel also specifies the PIPE_ACCESS_DUPLEX mode for | |
| 204 // the created pipe. A client has to specify the same duplex mode in | |
| 205 // order to connect. | |
|
Wez
2012/03/07 01:56:13
nit: How is this comment relevant to "the result",
alexeypa (please no reviews)
2012/03/07 19:59:08
Yes. I rephrased the comment to articulate it bett
| |
| 206 // | |
| 207 // In our case the result is that only processes running under | |
| 208 // LocalSystem account will be able to connect to this channel. | |
| 209 chromoting_service_.reset(new IPC::ChannelProxy( | |
| 210 kChromotingServiceChannelName, | |
| 211 IPC::Channel::MODE_SERVER, | |
| 212 this, | |
| 213 io_thread_->message_loop_proxy().get())); | |
| 179 | 214 |
| 180 // Try to launch the process and attach an object watcher to the returned | 215 // Try to launch the process and attach an object watcher to the returned |
| 181 // handle so that we get notified when the process terminates. | 216 // handle so that we get notified when the process terminates. |
| 182 launch_time_ = base::Time::Now(); | |
| 183 if (LaunchProcessAsUser(host_binary_, session_token_, &process_)) { | 217 if (LaunchProcessAsUser(host_binary_, session_token_, &process_)) { |
| 184 if (process_watcher_.StartWatching(process_.handle(), this)) { | 218 if (process_watcher_.StartWatching(process_.handle(), this)) { |
| 185 state_ = StateAttached; | 219 state_ = StateAttached; |
| 186 return; | 220 return; |
| 187 } else { | 221 } else { |
| 188 LOG(ERROR) << "Failed to arm the process watcher."; | 222 LOG(ERROR) << "Failed to arm the process watcher."; |
| 189 process_.Terminate(0); | 223 process_.Terminate(0); |
| 190 process_.Close(); | 224 process_.Close(); |
| 225 chromoting_service_.reset(); | |
| 191 } | 226 } |
| 192 } | 227 } |
| 193 | 228 |
| 194 // Something went wrong. Try to launch the host again later. The attempts rate | 229 // Something went wrong. Try to launch the host again later. The attempts rate |
| 195 // is limited by exponential backoff. | 230 // is limited by exponential backoff. |
| 196 launch_backoff_ = std::max(launch_backoff_ * 2, | 231 launch_backoff_ = std::max(launch_backoff_ * 2, |
| 197 TimeDelta::FromSeconds(kMinLaunchDelaySeconds)); | 232 TimeDelta::FromSeconds(kMinLaunchDelaySeconds)); |
| 198 launch_backoff_ = std::min(launch_backoff_, | 233 launch_backoff_ = std::min(launch_backoff_, |
| 199 TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)); | 234 TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)); |
| 200 timer_.Start(FROM_HERE, launch_backoff_, | 235 timer_.Start(FROM_HERE, launch_backoff_, |
| 201 this, &WtsSessionProcessLauncher::LaunchProcess); | 236 this, &WtsSessionProcessLauncher::LaunchProcess); |
| 202 } | 237 } |
| 203 | 238 |
| 204 void WtsSessionProcessLauncher::OnObjectSignaled(HANDLE object) { | 239 void WtsSessionProcessLauncher::OnObjectSignaled(HANDLE object) { |
| 205 DCHECK(state_ == StateAttached); | 240 DCHECK(state_ == StateAttached); |
| 206 DCHECK(!timer_.IsRunning()); | 241 DCHECK(!timer_.IsRunning()); |
| 207 DCHECK(process_.handle() != NULL); | 242 DCHECK(process_.handle() != NULL); |
| 208 DCHECK(process_watcher_.GetWatchedObject() == NULL); | 243 DCHECK(process_watcher_.GetWatchedObject() == NULL); |
| 244 DCHECK(chromoting_service_.get() != NULL); | |
| 209 | 245 |
| 210 // The host process has been terminated for some reason. The handle can now be | 246 // The host process has been terminated for some reason. The handle can now be |
| 211 // closed. | 247 // closed. |
| 212 process_.Close(); | 248 process_.Close(); |
| 249 chromoting_service_.reset(); | |
| 213 | 250 |
| 214 // Expand the backoff interval if the process has died quickly or reset it if | 251 // Expand the backoff interval if the process has died quickly or reset it if |
| 215 // it was up longer than the maximum backoff delay. | 252 // it was up longer than the maximum backoff delay. |
| 216 base::TimeDelta delta = base::Time::Now() - launch_time_; | 253 base::TimeDelta delta = base::Time::Now() - launch_time_; |
| 217 if (delta < base::TimeDelta() || | 254 if (delta < base::TimeDelta() || |
| 218 delta >= base::TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)) { | 255 delta >= base::TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)) { |
| 219 launch_backoff_ = base::TimeDelta(); | 256 launch_backoff_ = base::TimeDelta(); |
| 220 } else { | 257 } else { |
| 221 launch_backoff_ = std::max(launch_backoff_ * 2, | 258 launch_backoff_ = std::max(launch_backoff_ * 2, |
| 222 TimeDelta::FromSeconds(kMinLaunchDelaySeconds)); | 259 TimeDelta::FromSeconds(kMinLaunchDelaySeconds)); |
| 223 launch_backoff_ = std::min(launch_backoff_, | 260 launch_backoff_ = std::min(launch_backoff_, |
| 224 TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)); | 261 TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)); |
| 225 } | 262 } |
| 226 | 263 |
| 227 // Try to restart the host. | 264 // Try to restart the host. |
| 228 state_ = StateStarting; | 265 state_ = StateStarting; |
| 229 timer_.Start(FROM_HERE, launch_backoff_, | 266 timer_.Start(FROM_HERE, launch_backoff_, |
| 230 this, &WtsSessionProcessLauncher::LaunchProcess); | 267 this, &WtsSessionProcessLauncher::LaunchProcess); |
| 231 } | 268 } |
| 232 | 269 |
| 270 bool WtsSessionProcessLauncher::OnMessageReceived(const IPC::Message& message) { | |
| 271 bool handled = true; | |
| 272 IPC_BEGIN_MESSAGE_MAP(WtsSessionProcessLauncher, message) | |
| 273 IPC_MESSAGE_HANDLER(ChromotingServiceMsg_SendSas, OnSendSas) | |
| 274 IPC_MESSAGE_UNHANDLED(handled = false) | |
| 275 IPC_END_MESSAGE_MAP() | |
| 276 return handled; | |
| 277 } | |
| 278 | |
| 279 void WtsSessionProcessLauncher::OnSendSas() { | |
| 280 if (state_ == StateAttached) { | |
| 281 if (sas_sender_.get() == NULL) { | |
| 282 sas_sender_ = SasSender::Create(); | |
| 283 } | |
| 284 | |
| 285 if (sas_sender_.get() != NULL) { | |
| 286 sas_sender_->Send(); | |
| 287 } | |
| 288 } | |
| 289 } | |
| 290 | |
| 233 void WtsSessionProcessLauncher::OnSessionAttached(uint32 session_id) { | 291 void WtsSessionProcessLauncher::OnSessionAttached(uint32 session_id) { |
| 234 DCHECK(state_ == StateDetached); | 292 DCHECK(state_ == StateDetached); |
| 235 DCHECK(!timer_.IsRunning()); | 293 DCHECK(!timer_.IsRunning()); |
| 236 DCHECK(process_.handle() == NULL); | 294 DCHECK(process_.handle() == NULL); |
| 237 DCHECK(process_watcher_.GetWatchedObject() == NULL); | 295 DCHECK(process_watcher_.GetWatchedObject() == NULL); |
| 296 DCHECK(chromoting_service_.get() == NULL); | |
| 238 | 297 |
| 239 // Temporarily enable the SE_TCB_NAME privilege. The privileged token is | 298 // Temporarily enable the SE_TCB_NAME privilege. The privileged token is |
| 240 // created as needed and kept for later reuse. | 299 // created as needed and kept for later reuse. |
| 241 if (privileged_token_.Get() == NULL) { | 300 if (privileged_token_.Get() == NULL) { |
| 242 if (!CreatePrivilegedToken(&privileged_token_)) { | 301 if (!CreatePrivilegedToken(&privileged_token_)) { |
| 243 return; | 302 return; |
| 244 } | 303 } |
| 245 } | 304 } |
| 246 | 305 |
| 247 if (!ImpersonateLoggedOnUser(privileged_token_)) { | 306 if (!ImpersonateLoggedOnUser(privileged_token_)) { |
| 248 LOG_GETLASTERROR(ERROR) << | 307 LOG_GETLASTERROR(ERROR) << |
| 249 "Failed to impersonate the privileged token"; | 308 "Failed to impersonate the privileged token"; |
| 250 return; | 309 return; |
| 251 } | 310 } |
| 252 | 311 |
| 253 // While the SE_TCB_NAME progolege is enabled, create a session token for | 312 // While the SE_TCB_NAME privilege is enabled, create a session token for |
| 254 // the launched process. | 313 // the launched process. |
| 255 bool result = CreateSessionToken(session_id, &session_token_); | 314 bool result = CreateSessionToken(session_id, &session_token_); |
| 256 | 315 |
| 257 // Revert to the default token. The default token is sufficient to call | 316 // Revert to the default token. The default token is sufficient to call |
| 258 // CreateProcessAsUser() successfully. | 317 // CreateProcessAsUser() successfully. |
| 259 CHECK(RevertToSelf()); | 318 CHECK(RevertToSelf()); |
| 260 | 319 |
| 261 if (!result) | 320 if (!result) |
| 262 return; | 321 return; |
| 263 | 322 |
| 264 // Now try to launch the host. | 323 // Now try to launch the host. |
| 265 state_ = StateStarting; | 324 state_ = StateStarting; |
| 266 LaunchProcess(); | 325 LaunchProcess(); |
| 267 } | 326 } |
| 268 | 327 |
| 269 void WtsSessionProcessLauncher::OnSessionDetached() { | 328 void WtsSessionProcessLauncher::OnSessionDetached() { |
| 270 DCHECK(state_ == StateDetached || | 329 DCHECK(state_ == StateDetached || |
| 271 state_ == StateStarting || | 330 state_ == StateStarting || |
| 272 state_ == StateAttached); | 331 state_ == StateAttached); |
| 273 | 332 |
| 274 switch (state_) { | 333 switch (state_) { |
| 275 case StateDetached: | 334 case StateDetached: |
| 276 DCHECK(!timer_.IsRunning()); | 335 DCHECK(!timer_.IsRunning()); |
| 277 DCHECK(process_.handle() == NULL); | 336 DCHECK(process_.handle() == NULL); |
| 278 DCHECK(process_watcher_.GetWatchedObject() == NULL); | 337 DCHECK(process_watcher_.GetWatchedObject() == NULL); |
| 338 DCHECK(chromoting_service_.get() == NULL); | |
| 279 break; | 339 break; |
| 280 | 340 |
| 281 case StateStarting: | 341 case StateStarting: |
| 282 DCHECK(timer_.IsRunning()); | 342 DCHECK(timer_.IsRunning()); |
| 283 DCHECK(process_.handle() == NULL); | 343 DCHECK(process_.handle() == NULL); |
| 284 DCHECK(process_watcher_.GetWatchedObject() == NULL); | 344 DCHECK(process_watcher_.GetWatchedObject() == NULL); |
| 345 DCHECK(chromoting_service_.get() == NULL); | |
| 285 | 346 |
| 286 timer_.Stop(); | 347 timer_.Stop(); |
| 287 launch_backoff_ = base::TimeDelta(); | 348 launch_backoff_ = base::TimeDelta(); |
| 288 state_ = StateDetached; | 349 state_ = StateDetached; |
| 289 break; | 350 break; |
| 290 | 351 |
| 291 case StateAttached: | 352 case StateAttached: |
| 292 DCHECK(!timer_.IsRunning()); | 353 DCHECK(!timer_.IsRunning()); |
| 293 DCHECK(process_.handle() != NULL); | 354 DCHECK(process_.handle() != NULL); |
| 294 DCHECK(process_watcher_.GetWatchedObject() != NULL); | 355 DCHECK(process_watcher_.GetWatchedObject() != NULL); |
| 356 DCHECK(chromoting_service_.get() != NULL); | |
| 295 | 357 |
| 296 process_watcher_.StopWatching(); | 358 process_watcher_.StopWatching(); |
| 297 process_.Terminate(0); | 359 process_.Terminate(0); |
| 298 process_.Close(); | 360 process_.Close(); |
| 361 chromoting_service_.reset(); | |
| 299 state_ = StateDetached; | 362 state_ = StateDetached; |
| 300 break; | 363 break; |
| 301 } | 364 } |
| 302 } | 365 } |
| 303 | 366 |
| 304 } // namespace remoting | 367 } // namespace remoting |
| OLD | NEW |