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 |