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_)) |
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 |