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 |