| 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/win/wts_session_process_launcher.h" | 8 #include "remoting/host/win/wts_session_process_launcher.h" |
| 9 | 9 |
| 10 #include <windows.h> | 10 #include <windows.h> |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 55 // The command line parameters that should be copied from the service's command | 55 // The command line parameters that should be copied from the service's command |
| 56 // line to the host process. | 56 // line to the host process. |
| 57 const char* kCopiedSwitchNames[] = { | 57 const char* kCopiedSwitchNames[] = { |
| 58 "auth-config", "host-config", switches::kV, switches::kVModule }; | 58 "auth-config", "host-config", switches::kV, switches::kVModule }; |
| 59 | 59 |
| 60 // The security descriptor of the Chromoting IPC channel. It gives full access | 60 // The security descriptor of the Chromoting IPC channel. It gives full access |
| 61 // to LocalSystem and denies access by anyone else. | 61 // to LocalSystem and denies access by anyone else. |
| 62 const wchar_t kChromotingChannelSecurityDescriptor[] = | 62 const wchar_t kChromotingChannelSecurityDescriptor[] = |
| 63 L"O:SYG:SYD:(A;;GA;;;SY)"; | 63 L"O:SYG:SYD:(A;;GA;;;SY)"; |
| 64 | 64 |
| 65 // Takes the process token and makes a copy of it. The returned handle will have | |
| 66 // |desired_access| rights. | |
| 67 bool CopyProcessToken(DWORD desired_access, | |
| 68 ScopedHandle* token_out) { | |
| 69 | |
| 70 HANDLE handle; | |
| 71 if (!OpenProcessToken(GetCurrentProcess(), | |
| 72 TOKEN_DUPLICATE | desired_access, | |
| 73 &handle)) { | |
| 74 LOG_GETLASTERROR(ERROR) << "Failed to open process token"; | |
| 75 return false; | |
| 76 } | |
| 77 | |
| 78 ScopedHandle process_token(handle); | |
| 79 | |
| 80 if (!DuplicateTokenEx(process_token, | |
| 81 desired_access, | |
| 82 NULL, | |
| 83 SecurityImpersonation, | |
| 84 TokenPrimary, | |
| 85 &handle)) { | |
| 86 LOG_GETLASTERROR(ERROR) << "Failed to duplicate the process token"; | |
| 87 return false; | |
| 88 } | |
| 89 | |
| 90 token_out->Set(handle); | |
| 91 return true; | |
| 92 } | |
| 93 | |
| 94 // Creates a copy of the current process with SE_TCB_NAME privilege enabled. | |
| 95 bool CreatePrivilegedToken(ScopedHandle* token_out) { | |
| 96 ScopedHandle privileged_token; | |
| 97 DWORD desired_access = TOKEN_ADJUST_PRIVILEGES | TOKEN_IMPERSONATE | | |
| 98 TOKEN_DUPLICATE | TOKEN_QUERY; | |
| 99 if (!CopyProcessToken(desired_access, &privileged_token)) { | |
| 100 return false; | |
| 101 } | |
| 102 | |
| 103 // Get the LUID for the SE_TCB_NAME privilege. | |
| 104 TOKEN_PRIVILEGES state; | |
| 105 state.PrivilegeCount = 1; | |
| 106 state.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; | |
| 107 if (!LookupPrivilegeValue(NULL, SE_TCB_NAME, &state.Privileges[0].Luid)) { | |
| 108 LOG_GETLASTERROR(ERROR) << | |
| 109 "Failed to lookup the LUID for the SE_TCB_NAME privilege"; | |
| 110 return false; | |
| 111 } | |
| 112 | |
| 113 // Enable the SE_TCB_NAME privilege. | |
| 114 if (!AdjustTokenPrivileges(privileged_token, FALSE, &state, 0, NULL, 0)) { | |
| 115 LOG_GETLASTERROR(ERROR) << | |
| 116 "Failed to enable SE_TCB_NAME privilege in a token"; | |
| 117 return false; | |
| 118 } | |
| 119 | |
| 120 token_out->Set(privileged_token.Take()); | |
| 121 return true; | |
| 122 } | |
| 123 | |
| 124 // Creates a copy of the current process token for the given |session_id| so | |
| 125 // it can be used to launch a process in that session. | |
| 126 bool CreateSessionToken(uint32 session_id, | |
| 127 ScopedHandle* token_out) { | |
| 128 | |
| 129 ScopedHandle session_token; | |
| 130 DWORD desired_access = TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID | | |
| 131 TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY; | |
| 132 if (!CopyProcessToken(desired_access, &session_token)) { | |
| 133 return false; | |
| 134 } | |
| 135 | |
| 136 // Change the session ID of the token. | |
| 137 DWORD new_session_id = session_id; | |
| 138 if (!SetTokenInformation(session_token, | |
| 139 TokenSessionId, | |
| 140 &new_session_id, | |
| 141 sizeof(new_session_id))) { | |
| 142 LOG_GETLASTERROR(ERROR) << | |
| 143 "Failed to change session ID of a token"; | |
| 144 return false; | |
| 145 } | |
| 146 | |
| 147 token_out->Set(session_token.Take()); | |
| 148 return true; | |
| 149 } | |
| 150 | |
| 151 // Generates random channel ID. | 65 // Generates random channel ID. |
| 152 // N.B. Stolen from src/content/common/child_process_host_impl.cc | 66 // N.B. Stolen from src/content/common/child_process_host_impl.cc |
| 153 std::wstring GenerateRandomChannelId(void* instance) { | 67 std::wstring GenerateRandomChannelId(void* instance) { |
| 154 return base::StringPrintf(L"%d.%p.%d", | 68 return base::StringPrintf(L"%d.%p.%d", |
| 155 base::GetCurrentProcId(), instance, | 69 base::GetCurrentProcId(), instance, |
| 156 base::RandInt(0, std::numeric_limits<int>::max())); | 70 base::RandInt(0, std::numeric_limits<int>::max())); |
| 157 } | 71 } |
| 158 | 72 |
| 159 // Creates the server end of the Chromoting IPC channel. | 73 // Creates the server end of the Chromoting IPC channel. |
| 160 // N.B. This code is based on IPC::Channel's implementation. | 74 // N.B. This code is based on IPC::Channel's implementation. |
| (...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 399 if (stoppable_state() != Stoppable::kRunning) { | 313 if (stoppable_state() != Stoppable::kRunning) { |
| 400 return; | 314 return; |
| 401 } | 315 } |
| 402 | 316 |
| 403 DCHECK(state_ == StateDetached); | 317 DCHECK(state_ == StateDetached); |
| 404 DCHECK(!timer_.IsRunning()); | 318 DCHECK(!timer_.IsRunning()); |
| 405 DCHECK(process_.handle() == NULL); | 319 DCHECK(process_.handle() == NULL); |
| 406 DCHECK(process_watcher_.GetWatchedObject() == NULL); | 320 DCHECK(process_watcher_.GetWatchedObject() == NULL); |
| 407 DCHECK(chromoting_channel_.get() == NULL); | 321 DCHECK(chromoting_channel_.get() == NULL); |
| 408 | 322 |
| 409 // Temporarily enable the SE_TCB_NAME privilege. The privileged token is | 323 // Create a session token for the launched process. |
| 410 // created as needed and kept for later reuse. | 324 if (!CreateSessionToken(session_id, session_token_.Receive())) |
| 411 if (privileged_token_.Get() == NULL) { | |
| 412 if (!CreatePrivilegedToken(&privileged_token_)) { | |
| 413 return; | |
| 414 } | |
| 415 } | |
| 416 | |
| 417 if (!ImpersonateLoggedOnUser(privileged_token_)) { | |
| 418 LOG_GETLASTERROR(ERROR) << | |
| 419 "Failed to impersonate the privileged token"; | |
| 420 return; | |
| 421 } | |
| 422 | |
| 423 // While the SE_TCB_NAME privilege is enabled, create a session token for | |
| 424 // the launched process. | |
| 425 bool result = CreateSessionToken(session_id, &session_token_); | |
| 426 | |
| 427 // Revert to the default token. The default token is sufficient to call | |
| 428 // CreateProcessAsUser() successfully. | |
| 429 CHECK(RevertToSelf()); | |
| 430 | |
| 431 if (!result) | |
| 432 return; | 325 return; |
| 433 | 326 |
| 434 // Now try to launch the host. | 327 // Now try to launch the host. |
| 435 state_ = StateStarting; | 328 state_ = StateStarting; |
| 436 LaunchProcess(); | 329 LaunchProcess(); |
| 437 } | 330 } |
| 438 | 331 |
| 439 void WtsSessionProcessLauncher::OnSessionDetached() { | 332 void WtsSessionProcessLauncher::OnSessionDetached() { |
| 440 DCHECK(main_message_loop_->BelongsToCurrentThread()); | 333 DCHECK(main_message_loop_->BelongsToCurrentThread()); |
| 441 DCHECK(state_ == StateDetached || | 334 DCHECK(state_ == StateDetached || |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 479 | 372 |
| 480 void WtsSessionProcessLauncher::DoStop() { | 373 void WtsSessionProcessLauncher::DoStop() { |
| 481 if (state_ != StateDetached) { | 374 if (state_ != StateDetached) { |
| 482 OnSessionDetached(); | 375 OnSessionDetached(); |
| 483 } | 376 } |
| 484 | 377 |
| 485 CompleteStopping(); | 378 CompleteStopping(); |
| 486 } | 379 } |
| 487 | 380 |
| 488 } // namespace remoting | 381 } // namespace remoting |
| OLD | NEW |