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_session_messages.h" | |
21 #include "remoting/host/sas_injector_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 kChromotingSessionChannelName[] = "chromoting_session"; | |
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_session_.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_session_.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 as the security attributes pointer to | |
197 // CreateNamedPipe() so the pipe gets the 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. | |
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. Which means that clients with read-only access | |
206 // (Everyone and anonymous) will not be able to connect. | |
Wez
2012/03/08 00:01:33
nit: ... to connect, which means ...
The comment
alexeypa (please no reviews)
2012/03/08 01:52:54
Actually, there is much more serious problem with
| |
207 chromoting_session_.reset(new IPC::ChannelProxy( | |
208 kChromotingSessionChannelName, | |
209 IPC::Channel::MODE_SERVER, | |
210 this, | |
211 io_thread_->message_loop_proxy().get())); | |
179 | 212 |
180 // Try to launch the process and attach an object watcher to the returned | 213 // Try to launch the process and attach an object watcher to the returned |
181 // handle so that we get notified when the process terminates. | 214 // handle so that we get notified when the process terminates. |
182 launch_time_ = base::Time::Now(); | |
183 if (LaunchProcessAsUser(host_binary_, session_token_, &process_)) { | 215 if (LaunchProcessAsUser(host_binary_, session_token_, &process_)) { |
184 if (process_watcher_.StartWatching(process_.handle(), this)) { | 216 if (process_watcher_.StartWatching(process_.handle(), this)) { |
185 state_ = StateAttached; | 217 state_ = StateAttached; |
186 return; | 218 return; |
187 } else { | 219 } else { |
188 LOG(ERROR) << "Failed to arm the process watcher."; | 220 LOG(ERROR) << "Failed to arm the process watcher."; |
189 process_.Terminate(0); | 221 process_.Terminate(0); |
190 process_.Close(); | 222 process_.Close(); |
223 chromoting_session_.reset(); | |
191 } | 224 } |
192 } | 225 } |
193 | 226 |
194 // Something went wrong. Try to launch the host again later. The attempts rate | 227 // Something went wrong. Try to launch the host again later. The attempts rate |
195 // is limited by exponential backoff. | 228 // is limited by exponential backoff. |
196 launch_backoff_ = std::max(launch_backoff_ * 2, | 229 launch_backoff_ = std::max(launch_backoff_ * 2, |
197 TimeDelta::FromSeconds(kMinLaunchDelaySeconds)); | 230 TimeDelta::FromSeconds(kMinLaunchDelaySeconds)); |
198 launch_backoff_ = std::min(launch_backoff_, | 231 launch_backoff_ = std::min(launch_backoff_, |
199 TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)); | 232 TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)); |
200 timer_.Start(FROM_HERE, launch_backoff_, | 233 timer_.Start(FROM_HERE, launch_backoff_, |
201 this, &WtsSessionProcessLauncher::LaunchProcess); | 234 this, &WtsSessionProcessLauncher::LaunchProcess); |
202 } | 235 } |
203 | 236 |
204 void WtsSessionProcessLauncher::OnObjectSignaled(HANDLE object) { | 237 void WtsSessionProcessLauncher::OnObjectSignaled(HANDLE object) { |
205 DCHECK(state_ == StateAttached); | 238 DCHECK(state_ == StateAttached); |
206 DCHECK(!timer_.IsRunning()); | 239 DCHECK(!timer_.IsRunning()); |
207 DCHECK(process_.handle() != NULL); | 240 DCHECK(process_.handle() != NULL); |
208 DCHECK(process_watcher_.GetWatchedObject() == NULL); | 241 DCHECK(process_watcher_.GetWatchedObject() == NULL); |
242 DCHECK(chromoting_session_.get() != NULL); | |
209 | 243 |
210 // The host process has been terminated for some reason. The handle can now be | 244 // The host process has been terminated for some reason. The handle can now be |
211 // closed. | 245 // closed. |
212 process_.Close(); | 246 process_.Close(); |
247 chromoting_session_.reset(); | |
213 | 248 |
214 // Expand the backoff interval if the process has died quickly or reset it if | 249 // Expand the backoff interval if the process has died quickly or reset it if |
215 // it was up longer than the maximum backoff delay. | 250 // it was up longer than the maximum backoff delay. |
216 base::TimeDelta delta = base::Time::Now() - launch_time_; | 251 base::TimeDelta delta = base::Time::Now() - launch_time_; |
217 if (delta < base::TimeDelta() || | 252 if (delta < base::TimeDelta() || |
218 delta >= base::TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)) { | 253 delta >= base::TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)) { |
219 launch_backoff_ = base::TimeDelta(); | 254 launch_backoff_ = base::TimeDelta(); |
220 } else { | 255 } else { |
221 launch_backoff_ = std::max(launch_backoff_ * 2, | 256 launch_backoff_ = std::max(launch_backoff_ * 2, |
222 TimeDelta::FromSeconds(kMinLaunchDelaySeconds)); | 257 TimeDelta::FromSeconds(kMinLaunchDelaySeconds)); |
223 launch_backoff_ = std::min(launch_backoff_, | 258 launch_backoff_ = std::min(launch_backoff_, |
224 TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)); | 259 TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)); |
225 } | 260 } |
226 | 261 |
227 // Try to restart the host. | 262 // Try to restart the host. |
228 state_ = StateStarting; | 263 state_ = StateStarting; |
229 timer_.Start(FROM_HERE, launch_backoff_, | 264 timer_.Start(FROM_HERE, launch_backoff_, |
230 this, &WtsSessionProcessLauncher::LaunchProcess); | 265 this, &WtsSessionProcessLauncher::LaunchProcess); |
231 } | 266 } |
232 | 267 |
268 bool WtsSessionProcessLauncher::OnMessageReceived(const IPC::Message& message) { | |
269 bool handled = true; | |
270 IPC_BEGIN_MESSAGE_MAP(WtsSessionProcessLauncher, message) | |
271 IPC_MESSAGE_HANDLER(ChromotingSessionMsg_SendSasToConsole, | |
272 OnSendSasToConsole) | |
273 IPC_MESSAGE_UNHANDLED(handled = false) | |
274 IPC_END_MESSAGE_MAP() | |
275 return handled; | |
276 } | |
277 | |
278 void WtsSessionProcessLauncher::OnSendSasToConsole() { | |
279 if (state_ == StateAttached) { | |
280 if (sas_injector_.get() == NULL) { | |
281 sas_injector_ = SasInjector::Create(); | |
282 } | |
283 | |
284 if (sas_injector_.get() != NULL) { | |
285 sas_injector_->InjectSas(); | |
286 } | |
287 } | |
288 } | |
289 | |
233 void WtsSessionProcessLauncher::OnSessionAttached(uint32 session_id) { | 290 void WtsSessionProcessLauncher::OnSessionAttached(uint32 session_id) { |
234 DCHECK(state_ == StateDetached); | 291 DCHECK(state_ == StateDetached); |
235 DCHECK(!timer_.IsRunning()); | 292 DCHECK(!timer_.IsRunning()); |
236 DCHECK(process_.handle() == NULL); | 293 DCHECK(process_.handle() == NULL); |
237 DCHECK(process_watcher_.GetWatchedObject() == NULL); | 294 DCHECK(process_watcher_.GetWatchedObject() == NULL); |
295 DCHECK(chromoting_session_.get() == NULL); | |
238 | 296 |
239 // Temporarily enable the SE_TCB_NAME privilege. The privileged token is | 297 // Temporarily enable the SE_TCB_NAME privilege. The privileged token is |
240 // created as needed and kept for later reuse. | 298 // created as needed and kept for later reuse. |
241 if (privileged_token_.Get() == NULL) { | 299 if (privileged_token_.Get() == NULL) { |
242 if (!CreatePrivilegedToken(&privileged_token_)) { | 300 if (!CreatePrivilegedToken(&privileged_token_)) { |
243 return; | 301 return; |
244 } | 302 } |
245 } | 303 } |
246 | 304 |
247 if (!ImpersonateLoggedOnUser(privileged_token_)) { | 305 if (!ImpersonateLoggedOnUser(privileged_token_)) { |
248 LOG_GETLASTERROR(ERROR) << | 306 LOG_GETLASTERROR(ERROR) << |
249 "Failed to impersonate the privileged token"; | 307 "Failed to impersonate the privileged token"; |
250 return; | 308 return; |
251 } | 309 } |
252 | 310 |
253 // While the SE_TCB_NAME progolege is enabled, create a session token for | 311 // While the SE_TCB_NAME privilege is enabled, create a session token for |
254 // the launched process. | 312 // the launched process. |
255 bool result = CreateSessionToken(session_id, &session_token_); | 313 bool result = CreateSessionToken(session_id, &session_token_); |
256 | 314 |
257 // Revert to the default token. The default token is sufficient to call | 315 // Revert to the default token. The default token is sufficient to call |
258 // CreateProcessAsUser() successfully. | 316 // CreateProcessAsUser() successfully. |
259 CHECK(RevertToSelf()); | 317 CHECK(RevertToSelf()); |
260 | 318 |
261 if (!result) | 319 if (!result) |
262 return; | 320 return; |
263 | 321 |
264 // Now try to launch the host. | 322 // Now try to launch the host. |
265 state_ = StateStarting; | 323 state_ = StateStarting; |
266 LaunchProcess(); | 324 LaunchProcess(); |
267 } | 325 } |
268 | 326 |
269 void WtsSessionProcessLauncher::OnSessionDetached() { | 327 void WtsSessionProcessLauncher::OnSessionDetached() { |
270 DCHECK(state_ == StateDetached || | 328 DCHECK(state_ == StateDetached || |
271 state_ == StateStarting || | 329 state_ == StateStarting || |
272 state_ == StateAttached); | 330 state_ == StateAttached); |
273 | 331 |
274 switch (state_) { | 332 switch (state_) { |
275 case StateDetached: | 333 case StateDetached: |
276 DCHECK(!timer_.IsRunning()); | 334 DCHECK(!timer_.IsRunning()); |
277 DCHECK(process_.handle() == NULL); | 335 DCHECK(process_.handle() == NULL); |
278 DCHECK(process_watcher_.GetWatchedObject() == NULL); | 336 DCHECK(process_watcher_.GetWatchedObject() == NULL); |
337 DCHECK(chromoting_session_.get() == NULL); | |
279 break; | 338 break; |
280 | 339 |
281 case StateStarting: | 340 case StateStarting: |
282 DCHECK(timer_.IsRunning()); | 341 DCHECK(timer_.IsRunning()); |
283 DCHECK(process_.handle() == NULL); | 342 DCHECK(process_.handle() == NULL); |
284 DCHECK(process_watcher_.GetWatchedObject() == NULL); | 343 DCHECK(process_watcher_.GetWatchedObject() == NULL); |
344 DCHECK(chromoting_session_.get() == NULL); | |
285 | 345 |
286 timer_.Stop(); | 346 timer_.Stop(); |
287 launch_backoff_ = base::TimeDelta(); | 347 launch_backoff_ = base::TimeDelta(); |
288 state_ = StateDetached; | 348 state_ = StateDetached; |
289 break; | 349 break; |
290 | 350 |
291 case StateAttached: | 351 case StateAttached: |
292 DCHECK(!timer_.IsRunning()); | 352 DCHECK(!timer_.IsRunning()); |
293 DCHECK(process_.handle() != NULL); | 353 DCHECK(process_.handle() != NULL); |
294 DCHECK(process_watcher_.GetWatchedObject() != NULL); | 354 DCHECK(process_watcher_.GetWatchedObject() != NULL); |
355 DCHECK(chromoting_session_.get() != NULL); | |
295 | 356 |
296 process_watcher_.StopWatching(); | 357 process_watcher_.StopWatching(); |
297 process_.Terminate(0); | 358 process_.Terminate(0); |
298 process_.Close(); | 359 process_.Close(); |
360 chromoting_session_.reset(); | |
299 state_ = StateDetached; | 361 state_ = StateDetached; |
300 break; | 362 break; |
301 } | 363 } |
302 } | 364 } |
303 | 365 |
304 } // namespace remoting | 366 } // namespace remoting |
OLD | NEW |