| 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 "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 96 return true; | 96 return true; |
| 97 } | 97 } |
| 98 | 98 |
| 99 // Requests the execution server to create a process in the specified session | 99 // Requests the execution server to create a process in the specified session |
| 100 // using the default (i.e. Winlogon) token. This routine relies on undocumented | 100 // using the default (i.e. Winlogon) token. This routine relies on undocumented |
| 101 // OS functionality and will likely not work on anything but XP or W2K3. | 101 // OS functionality and will likely not work on anything but XP or W2K3. |
| 102 bool CreateRemoteSessionProcess( | 102 bool CreateRemoteSessionProcess( |
| 103 uint32 session_id, | 103 uint32 session_id, |
| 104 const FilePath::StringType& application_name, | 104 const FilePath::StringType& application_name, |
| 105 const CommandLine::StringType& command_line, | 105 const CommandLine::StringType& command_line, |
| 106 DWORD creation_flags, |
| 106 PROCESS_INFORMATION* process_information_out) | 107 PROCESS_INFORMATION* process_information_out) |
| 107 { | 108 { |
| 108 DCHECK(base::win::GetVersion() == base::win::VERSION_XP); | 109 DCHECK(base::win::GetVersion() == base::win::VERSION_XP); |
| 109 | 110 |
| 110 string16 pipe_name; | 111 string16 pipe_name; |
| 111 | 112 |
| 112 // Use winsta!WinStationQueryInformationW() to determine the process creation | 113 // Use winsta!WinStationQueryInformationW() to determine the process creation |
| 113 // pipe name for the session. | 114 // pipe name for the session. |
| 114 FilePath winsta_path(base::GetNativeLibraryName(UTF8ToUTF16("winsta"))); | 115 FilePath winsta_path(base::GetNativeLibraryName(UTF8ToUTF16("winsta"))); |
| 115 base::ScopedNativeLibrary winsta(winsta_path); | 116 base::ScopedNativeLibrary winsta(winsta_path); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 196 // and three NULL-terminated string parameters. | 197 // and three NULL-terminated string parameters. |
| 197 size_t size = sizeof(CreateProcessRequest) + sizeof(wchar_t) * | 198 size_t size = sizeof(CreateProcessRequest) + sizeof(wchar_t) * |
| 198 (application_name.size() + command_line.size() + desktop_name.size() + 3); | 199 (application_name.size() + command_line.size() + desktop_name.size() + 3); |
| 199 scoped_array<char> buffer(new char[size]); | 200 scoped_array<char> buffer(new char[size]); |
| 200 memset(buffer.get(), 0, size); | 201 memset(buffer.get(), 0, size); |
| 201 | 202 |
| 202 // Marshal the input parameters. | 203 // Marshal the input parameters. |
| 203 CreateProcessRequest* request = | 204 CreateProcessRequest* request = |
| 204 reinterpret_cast<CreateProcessRequest*>(buffer.get()); | 205 reinterpret_cast<CreateProcessRequest*>(buffer.get()); |
| 205 request->size = size; | 206 request->size = size; |
| 207 request->process_id = GetCurrentProcessId(); |
| 206 request->use_default_token = TRUE; | 208 request->use_default_token = TRUE; |
| 207 request->process_id = GetCurrentProcessId(); | 209 request->creation_flags = creation_flags; |
| 208 request->startup_info.cb = sizeof(request->startup_info); | 210 request->startup_info.cb = sizeof(request->startup_info); |
| 209 | 211 |
| 210 size_t buffer_offset = sizeof(CreateProcessRequest); | 212 size_t buffer_offset = sizeof(CreateProcessRequest); |
| 211 | 213 |
| 212 request->application_name = reinterpret_cast<LPWSTR>(buffer_offset); | 214 request->application_name = reinterpret_cast<LPWSTR>(buffer_offset); |
| 213 std::copy(application_name.begin(), | 215 std::copy(application_name.begin(), |
| 214 application_name.end(), | 216 application_name.end(), |
| 215 reinterpret_cast<wchar_t*>(buffer.get() + buffer_offset)); | 217 reinterpret_cast<wchar_t*>(buffer.get() + buffer_offset)); |
| 216 buffer_offset += (application_name.size() + 1) * sizeof(wchar_t); | 218 buffer_offset += (application_name.size() + 1) * sizeof(wchar_t); |
| 217 | 219 |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 338 // Revert to the default token. | 340 // Revert to the default token. |
| 339 CHECK(RevertToSelf()); | 341 CHECK(RevertToSelf()); |
| 340 | 342 |
| 341 *token_out = session_token.Pass(); | 343 *token_out = session_token.Pass(); |
| 342 return true; | 344 return true; |
| 343 } | 345 } |
| 344 | 346 |
| 345 bool LaunchProcessWithToken(const FilePath& binary, | 347 bool LaunchProcessWithToken(const FilePath& binary, |
| 346 const CommandLine::StringType& command_line, | 348 const CommandLine::StringType& command_line, |
| 347 HANDLE user_token, | 349 HANDLE user_token, |
| 348 ScopedHandle* process_out) { | 350 DWORD creation_flags, |
| 351 ScopedHandle* process_out, |
| 352 ScopedHandle* thread_out) { |
| 349 FilePath::StringType application_name = binary.value(); | 353 FilePath::StringType application_name = binary.value(); |
| 350 | 354 |
| 351 base::win::ScopedProcessInformation process_info; | 355 base::win::ScopedProcessInformation process_info; |
| 352 STARTUPINFOW startup_info; | 356 STARTUPINFOW startup_info; |
| 353 | 357 |
| 354 string16 desktop_name(UTF8ToUTF16(kDefaultDesktopName)); | 358 string16 desktop_name(UTF8ToUTF16(kDefaultDesktopName)); |
| 355 | 359 |
| 356 memset(&startup_info, 0, sizeof(startup_info)); | 360 memset(&startup_info, 0, sizeof(startup_info)); |
| 357 startup_info.cb = sizeof(startup_info); | 361 startup_info.cb = sizeof(startup_info); |
| 358 startup_info.lpDesktop = const_cast<char16*>(desktop_name.c_str()); | 362 startup_info.lpDesktop = const_cast<char16*>(desktop_name.c_str()); |
| 359 | 363 |
| 360 BOOL result = CreateProcessAsUser(user_token, | 364 BOOL result = CreateProcessAsUser(user_token, |
| 361 application_name.c_str(), | 365 application_name.c_str(), |
| 362 const_cast<LPWSTR>(command_line.c_str()), | 366 const_cast<LPWSTR>(command_line.c_str()), |
| 363 NULL, | 367 NULL, |
| 364 NULL, | 368 NULL, |
| 365 FALSE, | 369 FALSE, |
| 366 0, | 370 creation_flags, |
| 367 NULL, | 371 NULL, |
| 368 NULL, | 372 NULL, |
| 369 &startup_info, | 373 &startup_info, |
| 370 process_info.Receive()); | 374 process_info.Receive()); |
| 371 | 375 |
| 372 // CreateProcessAsUser will fail on XP and W2K3 with ERROR_PIPE_NOT_CONNECTED | 376 // CreateProcessAsUser will fail on XP and W2K3 with ERROR_PIPE_NOT_CONNECTED |
| 373 // if the user hasn't logged to the target session yet. In such a case | 377 // if the user hasn't logged to the target session yet. In such a case |
| 374 // we try to talk to the execution server directly emulating what | 378 // we try to talk to the execution server directly emulating what |
| 375 // the undocumented and not-exported advapi32!CreateRemoteSessionProcessW() | 379 // the undocumented and not-exported advapi32!CreateRemoteSessionProcessW() |
| 376 // function does. The created process will run under Winlogon'a token instead | 380 // function does. The created process will run under Winlogon'a token instead |
| 377 // of |user_token|. Since Winlogon runs as SYSTEM, this suits our needs. | 381 // of |user_token|. Since Winlogon runs as SYSTEM, this suits our needs. |
| 378 if (!result && | 382 if (!result && |
| 379 GetLastError() == ERROR_PIPE_NOT_CONNECTED && | 383 GetLastError() == ERROR_PIPE_NOT_CONNECTED && |
| 380 base::win::GetVersion() == base::win::VERSION_XP) { | 384 base::win::GetVersion() == base::win::VERSION_XP) { |
| 381 DWORD session_id; | 385 DWORD session_id; |
| 382 DWORD return_length; | 386 DWORD return_length; |
| 383 result = GetTokenInformation(user_token, | 387 result = GetTokenInformation(user_token, |
| 384 TokenSessionId, | 388 TokenSessionId, |
| 385 &session_id, | 389 &session_id, |
| 386 sizeof(session_id), | 390 sizeof(session_id), |
| 387 &return_length); | 391 &return_length); |
| 388 if (result && session_id != 0) { | 392 if (result && session_id != 0) { |
| 389 result = CreateRemoteSessionProcess(session_id, | 393 result = CreateRemoteSessionProcess(session_id, |
| 390 application_name, | 394 application_name, |
| 391 command_line, | 395 command_line, |
| 396 creation_flags, |
| 392 process_info.Receive()); | 397 process_info.Receive()); |
| 393 } else { | 398 } else { |
| 394 // Restore the error status returned by CreateProcessAsUser(). | 399 // Restore the error status returned by CreateProcessAsUser(). |
| 395 result = FALSE; | 400 result = FALSE; |
| 396 SetLastError(ERROR_PIPE_NOT_CONNECTED); | 401 SetLastError(ERROR_PIPE_NOT_CONNECTED); |
| 397 } | 402 } |
| 398 } | 403 } |
| 399 | 404 |
| 400 if (!result) { | 405 if (!result) { |
| 401 LOG_GETLASTERROR(ERROR) << | 406 LOG_GETLASTERROR(ERROR) << |
| 402 "Failed to launch a process with a user token"; | 407 "Failed to launch a process with a user token"; |
| 403 return false; | 408 return false; |
| 404 } | 409 } |
| 405 | 410 |
| 406 CHECK(process_info.IsValid()); | 411 CHECK(process_info.IsValid()); |
| 407 process_out->Set(process_info.TakeProcessHandle()); | 412 process_out->Set(process_info.TakeProcessHandle()); |
| 413 thread_out->Set(process_info.TakeThreadHandle()); |
| 408 return true; | 414 return true; |
| 409 } | 415 } |
| 410 | 416 |
| 411 } // namespace remoting | 417 } // namespace remoting |
| OLD | NEW |