| 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 #include "remoting/host/win/launch_process_with_token.h" | 5 #include "remoting/host/win/launch_process_with_token.h" |
| 6 | 6 |
| 7 #include <windows.h> | 7 #include <windows.h> |
| 8 #include <winternl.h> | 8 #include <winternl.h> |
| 9 | 9 |
| 10 #include <limits> | 10 #include <limits> |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 115 return false; | 115 return false; |
| 116 } | 116 } |
| 117 | 117 |
| 118 *pipe_out = pipe.Pass(); | 118 *pipe_out = pipe.Pass(); |
| 119 return true; | 119 return true; |
| 120 } | 120 } |
| 121 | 121 |
| 122 // Copies the process token making it a primary impersonation token. | 122 // Copies the process token making it a primary impersonation token. |
| 123 // The returned handle will have |desired_access| rights. | 123 // The returned handle will have |desired_access| rights. |
| 124 bool CopyProcessToken(DWORD desired_access, ScopedHandle* token_out) { | 124 bool CopyProcessToken(DWORD desired_access, ScopedHandle* token_out) { |
| 125 ScopedHandle process_token; | 125 HANDLE temp_handle; |
| 126 if (!OpenProcessToken(GetCurrentProcess(), | 126 if (!OpenProcessToken(GetCurrentProcess(), |
| 127 TOKEN_DUPLICATE | desired_access, | 127 TOKEN_DUPLICATE | desired_access, |
| 128 process_token.Receive())) { | 128 &temp_handle)) { |
| 129 LOG_GETLASTERROR(ERROR) << "Failed to open process token"; | 129 LOG_GETLASTERROR(ERROR) << "Failed to open process token"; |
| 130 return false; | 130 return false; |
| 131 } | 131 } |
| 132 ScopedHandle process_token; |
| 133 process_token.Set(temp_handle); |
| 132 | 134 |
| 133 ScopedHandle copied_token; | |
| 134 if (!DuplicateTokenEx(process_token, | 135 if (!DuplicateTokenEx(process_token, |
| 135 desired_access, | 136 desired_access, |
| 136 NULL, | 137 NULL, |
| 137 SecurityImpersonation, | 138 SecurityImpersonation, |
| 138 TokenPrimary, | 139 TokenPrimary, |
| 139 copied_token.Receive())) { | 140 &temp_handle)) { |
| 140 LOG_GETLASTERROR(ERROR) << "Failed to duplicate the process token"; | 141 LOG_GETLASTERROR(ERROR) << "Failed to duplicate the process token"; |
| 141 return false; | 142 return false; |
| 142 } | 143 } |
| 143 | 144 |
| 144 *token_out = copied_token.Pass(); | 145 token_out->Set(temp_handle); |
| 145 return true; | 146 return true; |
| 146 } | 147 } |
| 147 | 148 |
| 148 // Creates a copy of the current process with SE_TCB_NAME privilege enabled. | 149 // Creates a copy of the current process with SE_TCB_NAME privilege enabled. |
| 149 bool CreatePrivilegedToken(ScopedHandle* token_out) { | 150 bool CreatePrivilegedToken(ScopedHandle* token_out) { |
| 150 ScopedHandle privileged_token; | 151 ScopedHandle privileged_token; |
| 151 DWORD desired_access = TOKEN_ADJUST_PRIVILEGES | TOKEN_IMPERSONATE | | 152 DWORD desired_access = TOKEN_ADJUST_PRIVILEGES | TOKEN_IMPERSONATE | |
| 152 TOKEN_DUPLICATE | TOKEN_QUERY; | 153 TOKEN_DUPLICATE | TOKEN_QUERY; |
| 153 if (!CopyProcessToken(desired_access, &privileged_token)) { | 154 if (!CopyProcessToken(desired_access, &privileged_token)) { |
| 154 return false; | 155 return false; |
| (...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 460 ScopedHandle* process_out, | 461 ScopedHandle* process_out, |
| 461 ScopedHandle* thread_out) { | 462 ScopedHandle* thread_out) { |
| 462 base::FilePath::StringType application_name = binary.value(); | 463 base::FilePath::StringType application_name = binary.value(); |
| 463 | 464 |
| 464 STARTUPINFOW startup_info; | 465 STARTUPINFOW startup_info; |
| 465 memset(&startup_info, 0, sizeof(startup_info)); | 466 memset(&startup_info, 0, sizeof(startup_info)); |
| 466 startup_info.cb = sizeof(startup_info); | 467 startup_info.cb = sizeof(startup_info); |
| 467 if (desktop_name) | 468 if (desktop_name) |
| 468 startup_info.lpDesktop = const_cast<char16*>(desktop_name); | 469 startup_info.lpDesktop = const_cast<char16*>(desktop_name); |
| 469 | 470 |
| 470 base::win::ScopedProcessInformation process_info; | 471 PROCESS_INFORMATION temp_process_info; |
| 471 BOOL result = CreateProcessAsUser(user_token, | 472 BOOL result = CreateProcessAsUser(user_token, |
| 472 application_name.c_str(), | 473 application_name.c_str(), |
| 473 const_cast<LPWSTR>(command_line.c_str()), | 474 const_cast<LPWSTR>(command_line.c_str()), |
| 474 process_attributes, | 475 process_attributes, |
| 475 thread_attributes, | 476 thread_attributes, |
| 476 inherit_handles, | 477 inherit_handles, |
| 477 creation_flags, | 478 creation_flags, |
| 478 NULL, | 479 NULL, |
| 479 NULL, | 480 NULL, |
| 480 &startup_info, | 481 &startup_info, |
| 481 process_info.Receive()); | 482 &temp_process_info); |
| 482 | 483 |
| 483 // CreateProcessAsUser will fail on XP and W2K3 with ERROR_PIPE_NOT_CONNECTED | 484 // CreateProcessAsUser will fail on XP and W2K3 with ERROR_PIPE_NOT_CONNECTED |
| 484 // if the user hasn't logged to the target session yet. In such a case | 485 // if the user hasn't logged to the target session yet. In such a case |
| 485 // we try to talk to the execution server directly emulating what | 486 // we try to talk to the execution server directly emulating what |
| 486 // the undocumented and not-exported advapi32!CreateRemoteSessionProcessW() | 487 // the undocumented and not-exported advapi32!CreateRemoteSessionProcessW() |
| 487 // function does. The created process will run under Winlogon'a token instead | 488 // function does. The created process will run under Winlogon'a token instead |
| 488 // of |user_token|. Since Winlogon runs as SYSTEM, this suits our needs. | 489 // of |user_token|. Since Winlogon runs as SYSTEM, this suits our needs. |
| 489 if (!result && | 490 if (!result && |
| 490 GetLastError() == ERROR_PIPE_NOT_CONNECTED && | 491 GetLastError() == ERROR_PIPE_NOT_CONNECTED && |
| 491 base::win::GetVersion() < base::win::VERSION_VISTA) { | 492 base::win::GetVersion() < base::win::VERSION_VISTA) { |
| 492 DWORD session_id; | 493 DWORD session_id; |
| 493 DWORD return_length; | 494 DWORD return_length; |
| 494 result = GetTokenInformation(user_token, | 495 result = GetTokenInformation(user_token, |
| 495 TokenSessionId, | 496 TokenSessionId, |
| 496 &session_id, | 497 &session_id, |
| 497 sizeof(session_id), | 498 sizeof(session_id), |
| 498 &return_length); | 499 &return_length); |
| 499 if (result && session_id != 0) { | 500 if (result && session_id != 0) { |
| 500 result = CreateRemoteSessionProcess(session_id, | 501 result = CreateRemoteSessionProcess(session_id, |
| 501 application_name, | 502 application_name, |
| 502 command_line, | 503 command_line, |
| 503 creation_flags, | 504 creation_flags, |
| 504 desktop_name, | 505 desktop_name, |
| 505 process_info.Receive()); | 506 &temp_process_info); |
| 506 } else { | 507 } else { |
| 507 // Restore the error status returned by CreateProcessAsUser(). | 508 // Restore the error status returned by CreateProcessAsUser(). |
| 508 result = FALSE; | 509 result = FALSE; |
| 509 SetLastError(ERROR_PIPE_NOT_CONNECTED); | 510 SetLastError(ERROR_PIPE_NOT_CONNECTED); |
| 510 } | 511 } |
| 511 } | 512 } |
| 512 | 513 |
| 513 if (!result) { | 514 if (!result) { |
| 514 LOG_GETLASTERROR(ERROR) << | 515 LOG_GETLASTERROR(ERROR) << |
| 515 "Failed to launch a process with a user token"; | 516 "Failed to launch a process with a user token"; |
| 516 return false; | 517 return false; |
| 517 } | 518 } |
| 518 | 519 |
| 520 base::win::ScopedProcessInformation process_info; |
| 521 process_info.Set(temp_process_info); |
| 522 |
| 519 CHECK(process_info.IsValid()); | 523 CHECK(process_info.IsValid()); |
| 520 process_out->Set(process_info.TakeProcessHandle()); | 524 process_out->Set(process_info.TakeProcessHandle()); |
| 521 thread_out->Set(process_info.TakeThreadHandle()); | 525 thread_out->Set(process_info.TakeThreadHandle()); |
| 522 return true; | 526 return true; |
| 523 } | 527 } |
| 524 | 528 |
| 525 } // namespace remoting | 529 } // namespace remoting |
| OLD | NEW |