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" |
11 #include "base/memory/scoped_ptr.h" | 11 #include "base/memory/scoped_ptr.h" |
12 #include "base/scoped_native_library.h" | 12 #include "base/scoped_native_library.h" |
13 #include "base/stringprintf.h" | 13 #include "base/stringprintf.h" |
14 #include "base/utf_string_conversions.h" | 14 #include "base/utf_string_conversions.h" |
15 #include "base/win/scoped_handle.h" | 15 #include "base/win/scoped_handle.h" |
16 #include "base/win/scoped_process_information.h" | 16 #include "base/win/scoped_process_information.h" |
17 #include "base/win/windows_version.h" | 17 #include "base/win/windows_version.h" |
18 | 18 |
19 using base::win::ScopedHandle; | 19 using base::win::ScopedHandle; |
20 | 20 |
21 namespace { | 21 namespace { |
22 | 22 |
23 const wchar_t kCreateProcessDefaultPipeNameFormat[] = | 23 const char kCreateProcessDefaultPipeNameFormat[] = |
24 L"\\\\.\\Pipe\\TerminalServer\\SystemExecSrvr\\%d"; | 24 "\\\\.\\Pipe\\TerminalServer\\SystemExecSrvr\\%d"; |
25 | 25 |
26 // Undocumented WINSTATIONINFOCLASS value causing | 26 // Undocumented WINSTATIONINFOCLASS value causing |
27 // winsta!WinStationQueryInformationW() to return the name of the pipe for | 27 // winsta!WinStationQueryInformationW() to return the name of the pipe for |
28 // requesting cross-session process creation. | 28 // requesting cross-session process creation. |
29 const WINSTATIONINFOCLASS kCreateProcessPipeNameClass = | 29 const WINSTATIONINFOCLASS kCreateProcessPipeNameClass = |
30 static_cast<WINSTATIONINFOCLASS>(0x21); | 30 static_cast<WINSTATIONINFOCLASS>(0x21); |
31 | 31 |
32 const int kPipeBusyWaitTimeoutMs = 2000; | 32 const int kPipeBusyWaitTimeoutMs = 2000; |
33 const int kPipeConnectMaxAttempts = 3; | 33 const int kPipeConnectMaxAttempts = 3; |
34 | 34 |
35 // The minimum and maximum delays between attempts to inject host process into | 35 // The minimum and maximum delays between attempts to inject host process into |
36 // a session. | 36 // a session. |
37 const int kMaxLaunchDelaySeconds = 60; | 37 const int kMaxLaunchDelaySeconds = 60; |
38 const int kMinLaunchDelaySeconds = 1; | 38 const int kMinLaunchDelaySeconds = 1; |
39 | 39 |
40 // Name of the default session desktop. | 40 // Name of the default session desktop. |
41 wchar_t kDefaultDesktopName[] = L"winsta0\\default"; | 41 wchar_t kDefaultDesktopName[] = L"winsta0\\default"; |
42 | 42 |
43 // Requests the execution server to create a process in the specified session | 43 // Requests the execution server to create a process in the specified session |
44 // using the default (i.e. Winlogon) token. This routine relies on undocumented | 44 // using the default (i.e. Winlogon) token. This routine relies on undocumented |
45 // OS functionality and will likely not work on anything but XP or W2K3. | 45 // OS functionality and will likely not work on anything but XP or W2K3. |
46 bool CreateRemoteSessionProcess( | 46 bool CreateRemoteSessionProcess( |
47 uint32 session_id, | 47 uint32 session_id, |
48 const std::wstring& application_name, | 48 const FilePath::StringType& application_name, |
49 const std::wstring& command_line, | 49 const CommandLine::StringType& command_line, |
50 PROCESS_INFORMATION* process_information_out) | 50 PROCESS_INFORMATION* process_information_out) |
51 { | 51 { |
52 DCHECK(base::win::GetVersion() == base::win::VERSION_XP); | 52 DCHECK(base::win::GetVersion() == base::win::VERSION_XP); |
53 | 53 |
54 std::wstring pipe_name; | 54 string16 pipe_name; |
55 | 55 |
56 // Use winsta!WinStationQueryInformationW() to determine the process creation | 56 // Use winsta!WinStationQueryInformationW() to determine the process creation |
57 // pipe name for the session. | 57 // pipe name for the session. |
58 FilePath winsta_path(base::GetNativeLibraryName(UTF8ToUTF16("winsta"))); | 58 FilePath winsta_path(base::GetNativeLibraryName(UTF8ToUTF16("winsta"))); |
59 base::ScopedNativeLibrary winsta(winsta_path); | 59 base::ScopedNativeLibrary winsta(winsta_path); |
60 if (winsta.is_valid()) { | 60 if (winsta.is_valid()) { |
61 PWINSTATIONQUERYINFORMATIONW win_station_query_information = | 61 PWINSTATIONQUERYINFORMATIONW win_station_query_information = |
62 static_cast<PWINSTATIONQUERYINFORMATIONW>( | 62 static_cast<PWINSTATIONQUERYINFORMATIONW>( |
63 winsta.GetFunctionPointer("WinStationQueryInformationW")); | 63 winsta.GetFunctionPointer("WinStationQueryInformationW")); |
64 if (win_station_query_information) { | 64 if (win_station_query_information) { |
65 wchar_t name[MAX_PATH]; | 65 wchar_t name[MAX_PATH]; |
66 ULONG name_length; | 66 ULONG name_length; |
67 if (win_station_query_information(0, | 67 if (win_station_query_information(0, |
68 session_id, | 68 session_id, |
69 kCreateProcessPipeNameClass, | 69 kCreateProcessPipeNameClass, |
70 name, | 70 name, |
71 sizeof(name), | 71 sizeof(name), |
72 &name_length)) { | 72 &name_length)) { |
73 pipe_name.assign(name); | 73 pipe_name.assign(name); |
74 } | 74 } |
75 } | 75 } |
76 } | 76 } |
77 | 77 |
78 // Use the default pipe name if we couldn't query its name. | 78 // Use the default pipe name if we couldn't query its name. |
79 if (pipe_name.empty()) { | 79 if (pipe_name.empty()) { |
80 pipe_name = StringPrintf(kCreateProcessDefaultPipeNameFormat, session_id); | 80 pipe_name = UTF8ToUTF16( |
Wez
2012/08/03 21:26:15
nit: Why not have pipe_name be std::string and UTF
alexeypa (please no reviews)
2012/08/03 22:00:18
To avoid UTF8 <-> UTF16 conversion in three places
Wez
2012/08/06 17:29:38
Makes sense; I'd recommend working with std::strin
alexeypa (please no reviews)
2012/08/06 17:56:18
This will reduce number of conversions to two, not
Wez
2012/08/06 18:41:21
Of course; good point.
| |
81 StringPrintf(kCreateProcessDefaultPipeNameFormat, session_id)); | |
81 } | 82 } |
82 | 83 |
83 // Try to connect to the named pipe. | 84 // Try to connect to the named pipe. |
84 base::win::ScopedHandle pipe; | 85 base::win::ScopedHandle pipe; |
85 for (int i = 0; i < kPipeConnectMaxAttempts; ++i) { | 86 for (int i = 0; i < kPipeConnectMaxAttempts; ++i) { |
86 pipe.Set(CreateFile(pipe_name.c_str(), | 87 pipe.Set(CreateFile(pipe_name.c_str(), |
87 GENERIC_READ | GENERIC_WRITE, | 88 GENERIC_READ | GENERIC_WRITE, |
88 0, | 89 0, |
89 NULL, | 90 NULL, |
90 OPEN_EXISTING, | 91 OPEN_EXISTING, |
(...skipping 13 matching lines...) Expand all Loading... | |
104 if (!WaitNamedPipe(pipe_name.c_str(), kPipeBusyWaitTimeoutMs)) { | 105 if (!WaitNamedPipe(pipe_name.c_str(), kPipeBusyWaitTimeoutMs)) { |
105 break; | 106 break; |
106 } | 107 } |
107 } | 108 } |
108 | 109 |
109 if (!pipe.IsValid()) { | 110 if (!pipe.IsValid()) { |
110 LOG_GETLASTERROR(ERROR) << "Failed to connect to '" << pipe_name << "'"; | 111 LOG_GETLASTERROR(ERROR) << "Failed to connect to '" << pipe_name << "'"; |
111 return false; | 112 return false; |
112 } | 113 } |
113 | 114 |
114 std::wstring desktop_name(kDefaultDesktopName); | 115 string16 desktop_name(WideToUTF16(kDefaultDesktopName)); |
Wez
2012/08/03 21:26:15
nit: Why does kDefaultDesktopName need to be wide?
alexeypa (please no reviews)
2012/08/03 22:00:18
Done.
| |
115 | 116 |
116 // |CreateProcessRequest| structure passes the same parameters to | 117 // |CreateProcessRequest| structure passes the same parameters to |
117 // the execution server as CreateProcessAsUser() function does. Strings are | 118 // the execution server as CreateProcessAsUser() function does. Strings are |
118 // stored as wide strings immediately after the structure. String pointers are | 119 // stored as wide strings immediately after the structure. String pointers are |
119 // represented as byte offsets to string data from the beginning of | 120 // represented as byte offsets to string data from the beginning of |
120 // the structure. | 121 // the structure. |
121 struct CreateProcessRequest { | 122 struct CreateProcessRequest { |
122 DWORD size; | 123 DWORD size; |
123 DWORD process_id; | 124 DWORD process_id; |
124 BOOL use_default_token; | 125 BOOL use_default_token; |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
237 | 238 |
238 *process_information_out = response.process_information; | 239 *process_information_out = response.process_information; |
239 return true; | 240 return true; |
240 } | 241 } |
241 | 242 |
242 } // namespace | 243 } // namespace |
243 | 244 |
244 namespace remoting { | 245 namespace remoting { |
245 | 246 |
246 bool LaunchProcessWithToken(const FilePath& binary, | 247 bool LaunchProcessWithToken(const FilePath& binary, |
247 const std::wstring& command_line, | 248 const CommandLine::StringType& command_line, |
248 HANDLE user_token, | 249 HANDLE user_token, |
249 base::Process* process_out) { | 250 base::Process* process_out) { |
250 std::wstring application_name = binary.value(); | 251 FilePath::StringType application_name = binary.value(); |
251 | 252 |
252 base::win::ScopedProcessInformation process_info; | 253 base::win::ScopedProcessInformation process_info; |
253 STARTUPINFOW startup_info; | 254 STARTUPINFOW startup_info; |
254 | 255 |
255 memset(&startup_info, 0, sizeof(startup_info)); | 256 memset(&startup_info, 0, sizeof(startup_info)); |
256 startup_info.cb = sizeof(startup_info); | 257 startup_info.cb = sizeof(startup_info); |
257 startup_info.lpDesktop = kDefaultDesktopName; | 258 startup_info.lpDesktop = kDefaultDesktopName; |
258 | 259 |
259 BOOL result = CreateProcessAsUser(user_token, | 260 BOOL result = CreateProcessAsUser(user_token, |
260 application_name.c_str(), | 261 application_name.c_str(), |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
301 "Failed to launch a process with a user token"; | 302 "Failed to launch a process with a user token"; |
302 return false; | 303 return false; |
303 } | 304 } |
304 | 305 |
305 CHECK(process_info.IsValid()); | 306 CHECK(process_info.IsValid()); |
306 process_out->set_handle(process_info.TakeProcessHandle()); | 307 process_out->set_handle(process_info.TakeProcessHandle()); |
307 return true; | 308 return true; |
308 } | 309 } |
309 | 310 |
310 } // namespace remoting | 311 } // namespace remoting |
OLD | NEW |