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 |