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