Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1361)

Side by Side Diff: remoting/host/win/launch_process_with_token.cc

Issue 810133003: replace NULL->nullptr in src/remoting. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « remoting/host/win/host_service.cc ('k') | remoting/host/win/rdp_client.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 23 matching lines...) Expand all
34 static_cast<WINSTATIONINFOCLASS>(0x21); 34 static_cast<WINSTATIONINFOCLASS>(0x21);
35 35
36 const int kPipeBusyWaitTimeoutMs = 2000; 36 const int kPipeBusyWaitTimeoutMs = 2000;
37 const int kPipeConnectMaxAttempts = 3; 37 const int kPipeConnectMaxAttempts = 3;
38 38
39 // Terminates the process and closes process and thread handles in 39 // Terminates the process and closes process and thread handles in
40 // |process_information| structure. 40 // |process_information| structure.
41 void CloseHandlesAndTerminateProcess(PROCESS_INFORMATION* process_information) { 41 void CloseHandlesAndTerminateProcess(PROCESS_INFORMATION* process_information) {
42 if (process_information->hThread) { 42 if (process_information->hThread) {
43 CloseHandle(process_information->hThread); 43 CloseHandle(process_information->hThread);
44 process_information->hThread = NULL; 44 process_information->hThread = nullptr;
45 } 45 }
46 46
47 if (process_information->hProcess) { 47 if (process_information->hProcess) {
48 TerminateProcess(process_information->hProcess, CONTROL_C_EXIT); 48 TerminateProcess(process_information->hProcess, CONTROL_C_EXIT);
49 CloseHandle(process_information->hProcess); 49 CloseHandle(process_information->hProcess);
50 process_information->hProcess = NULL; 50 process_information->hProcess = nullptr;
51 } 51 }
52 } 52 }
53 53
54 // Connects to the executor server corresponding to |session_id|. 54 // Connects to the executor server corresponding to |session_id|.
55 bool ConnectToExecutionServer(uint32 session_id, 55 bool ConnectToExecutionServer(uint32 session_id,
56 base::win::ScopedHandle* pipe_out) { 56 base::win::ScopedHandle* pipe_out) {
57 base::string16 pipe_name; 57 base::string16 pipe_name;
58 58
59 // Use winsta!WinStationQueryInformationW() to determine the process creation 59 // Use winsta!WinStationQueryInformationW() to determine the process creation
60 // pipe name for the session. 60 // pipe name for the session.
(...skipping 23 matching lines...) Expand all
84 pipe_name = base::UTF8ToUTF16( 84 pipe_name = base::UTF8ToUTF16(
85 base::StringPrintf(kCreateProcessDefaultPipeNameFormat, session_id)); 85 base::StringPrintf(kCreateProcessDefaultPipeNameFormat, session_id));
86 } 86 }
87 87
88 // Try to connect to the named pipe. 88 // Try to connect to the named pipe.
89 base::win::ScopedHandle pipe; 89 base::win::ScopedHandle pipe;
90 for (int i = 0; i < kPipeConnectMaxAttempts; ++i) { 90 for (int i = 0; i < kPipeConnectMaxAttempts; ++i) {
91 pipe.Set(CreateFile(pipe_name.c_str(), 91 pipe.Set(CreateFile(pipe_name.c_str(),
92 GENERIC_READ | GENERIC_WRITE, 92 GENERIC_READ | GENERIC_WRITE,
93 0, 93 0,
94 NULL, 94 nullptr,
95 OPEN_EXISTING, 95 OPEN_EXISTING,
96 0, 96 0,
97 NULL)); 97 nullptr));
98 if (pipe.IsValid()) { 98 if (pipe.IsValid()) {
99 break; 99 break;
100 } 100 }
101 101
102 // Cannot continue retrying if error is something other than 102 // Cannot continue retrying if error is something other than
103 // ERROR_PIPE_BUSY. 103 // ERROR_PIPE_BUSY.
104 if (GetLastError() != ERROR_PIPE_BUSY) { 104 if (GetLastError() != ERROR_PIPE_BUSY) {
105 break; 105 break;
106 } 106 }
107 107
(...skipping 19 matching lines...) Expand all
127 if (!OpenProcessToken(GetCurrentProcess(), 127 if (!OpenProcessToken(GetCurrentProcess(),
128 TOKEN_DUPLICATE | desired_access, 128 TOKEN_DUPLICATE | desired_access,
129 &temp_handle)) { 129 &temp_handle)) {
130 PLOG(ERROR) << "Failed to open process token"; 130 PLOG(ERROR) << "Failed to open process token";
131 return false; 131 return false;
132 } 132 }
133 ScopedHandle process_token(temp_handle); 133 ScopedHandle process_token(temp_handle);
134 134
135 if (!DuplicateTokenEx(process_token.Get(), 135 if (!DuplicateTokenEx(process_token.Get(),
136 desired_access, 136 desired_access,
137 NULL, 137 nullptr,
138 SecurityImpersonation, 138 SecurityImpersonation,
139 TokenPrimary, 139 TokenPrimary,
140 &temp_handle)) { 140 &temp_handle)) {
141 PLOG(ERROR) << "Failed to duplicate the process token"; 141 PLOG(ERROR) << "Failed to duplicate the process token";
142 return false; 142 return false;
143 } 143 }
144 144
145 token_out->Set(temp_handle); 145 token_out->Set(temp_handle);
146 return true; 146 return true;
147 } 147 }
148 148
149 // Creates a copy of the current process with SE_TCB_NAME privilege enabled. 149 // Creates a copy of the current process with SE_TCB_NAME privilege enabled.
150 bool CreatePrivilegedToken(ScopedHandle* token_out) { 150 bool CreatePrivilegedToken(ScopedHandle* token_out) {
151 ScopedHandle privileged_token; 151 ScopedHandle privileged_token;
152 DWORD desired_access = TOKEN_ADJUST_PRIVILEGES | TOKEN_IMPERSONATE | 152 DWORD desired_access = TOKEN_ADJUST_PRIVILEGES | TOKEN_IMPERSONATE |
153 TOKEN_DUPLICATE | TOKEN_QUERY; 153 TOKEN_DUPLICATE | TOKEN_QUERY;
154 if (!CopyProcessToken(desired_access, &privileged_token)) { 154 if (!CopyProcessToken(desired_access, &privileged_token)) {
155 return false; 155 return false;
156 } 156 }
157 157
158 // Get the LUID for the SE_TCB_NAME privilege. 158 // Get the LUID for the SE_TCB_NAME privilege.
159 TOKEN_PRIVILEGES state; 159 TOKEN_PRIVILEGES state;
160 state.PrivilegeCount = 1; 160 state.PrivilegeCount = 1;
161 state.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 161 state.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
162 if (!LookupPrivilegeValue(NULL, SE_TCB_NAME, &state.Privileges[0].Luid)) { 162 if (!LookupPrivilegeValue(nullptr, SE_TCB_NAME, &state.Privileges[0].Luid)) {
163 PLOG(ERROR) << "Failed to lookup the LUID for the SE_TCB_NAME privilege"; 163 PLOG(ERROR) << "Failed to lookup the LUID for the SE_TCB_NAME privilege";
164 return false; 164 return false;
165 } 165 }
166 166
167 // Enable the SE_TCB_NAME privilege. 167 // Enable the SE_TCB_NAME privilege.
168 if (!AdjustTokenPrivileges(privileged_token.Get(), FALSE, &state, 0, NULL, 168 if (!AdjustTokenPrivileges(privileged_token.Get(), FALSE, &state, 0, nullptr,
169 0)) { 169 0)) {
170 PLOG(ERROR) << "Failed to enable SE_TCB_NAME privilege in a token"; 170 PLOG(ERROR) << "Failed to enable SE_TCB_NAME privilege in a token";
171 return false; 171 return false;
172 } 172 }
173 173
174 *token_out = privileged_token.Pass(); 174 *token_out = privileged_token.Pass();
175 return true; 175 return true;
176 } 176 }
177 177
178 // Fills the process and thread handles in the passed |process_information| 178 // Fills the process and thread handles in the passed |process_information|
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
256 PROCESS_INFORMATION* process_information_out) { 256 PROCESS_INFORMATION* process_information_out) {
257 struct CreateProcessResponse { 257 struct CreateProcessResponse {
258 DWORD size; 258 DWORD size;
259 BOOL success; 259 BOOL success;
260 DWORD last_error; 260 DWORD last_error;
261 PROCESS_INFORMATION process_information; 261 PROCESS_INFORMATION process_information;
262 }; 262 };
263 263
264 DWORD bytes; 264 DWORD bytes;
265 CreateProcessResponse response; 265 CreateProcessResponse response;
266 if (!ReadFile(pipe, &response, sizeof(response), &bytes, NULL)) { 266 if (!ReadFile(pipe, &response, sizeof(response), &bytes, nullptr)) {
267 PLOG(ERROR) << "Failed to receive CreateProcessAsUser response"; 267 PLOG(ERROR) << "Failed to receive CreateProcessAsUser response";
268 return false; 268 return false;
269 } 269 }
270 270
271 // The server sends the data in one chunk so if we didn't received a complete 271 // The server sends the data in one chunk so if we didn't received a complete
272 // answer something bad happend and there is no point in retrying. 272 // answer something bad happend and there is no point in retrying.
273 if (bytes != sizeof(response)) { 273 if (bytes != sizeof(response)) {
274 SetLastError(ERROR_RECEIVE_PARTIAL); 274 SetLastError(ERROR_RECEIVE_PARTIAL);
275 return false; 275 return false;
276 } 276 }
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
311 LPWSTR current_directory; 311 LPWSTR current_directory;
312 STARTUPINFOW startup_info; 312 STARTUPINFOW startup_info;
313 PROCESS_INFORMATION process_information; 313 PROCESS_INFORMATION process_information;
314 }; 314 };
315 315
316 base::string16 desktop; 316 base::string16 desktop;
317 if (desktop_name) 317 if (desktop_name)
318 desktop = desktop_name; 318 desktop = desktop_name;
319 319
320 // Allocate a large enough buffer to hold the CreateProcessRequest structure 320 // Allocate a large enough buffer to hold the CreateProcessRequest structure
321 // and three NULL-terminated string parameters. 321 // and three nullptr-terminated string parameters.
322 size_t size = sizeof(CreateProcessRequest) + sizeof(wchar_t) * 322 size_t size = sizeof(CreateProcessRequest) + sizeof(wchar_t) *
323 (application_name.size() + command_line.size() + desktop.size() + 3); 323 (application_name.size() + command_line.size() + desktop.size() + 3);
324 scoped_ptr<char[]> buffer(new char[size]); 324 scoped_ptr<char[]> buffer(new char[size]);
325 memset(buffer.get(), 0, size); 325 memset(buffer.get(), 0, size);
326 326
327 // Marshal the input parameters. 327 // Marshal the input parameters.
328 CreateProcessRequest* request = 328 CreateProcessRequest* request =
329 reinterpret_cast<CreateProcessRequest*>(buffer.get()); 329 reinterpret_cast<CreateProcessRequest*>(buffer.get());
330 request->size = size; 330 request->size = size;
331 request->process_id = GetCurrentProcessId(); 331 request->process_id = GetCurrentProcessId();
(...skipping 18 matching lines...) Expand all
350 buffer_offset += (command_line.size() + 1) * sizeof(wchar_t); 350 buffer_offset += (command_line.size() + 1) * sizeof(wchar_t);
351 351
352 request->startup_info.lpDesktop = 352 request->startup_info.lpDesktop =
353 reinterpret_cast<LPWSTR>(buffer_offset); 353 reinterpret_cast<LPWSTR>(buffer_offset);
354 std::copy(desktop.begin(), 354 std::copy(desktop.begin(),
355 desktop.end(), 355 desktop.end(),
356 reinterpret_cast<wchar_t*>(buffer.get() + buffer_offset)); 356 reinterpret_cast<wchar_t*>(buffer.get() + buffer_offset));
357 357
358 // Pass the request to create a process in the target session. 358 // Pass the request to create a process in the target session.
359 DWORD bytes; 359 DWORD bytes;
360 if (!WriteFile(pipe, buffer.get(), size, &bytes, NULL)) { 360 if (!WriteFile(pipe, buffer.get(), size, &bytes, nullptr)) {
361 PLOG(ERROR) << "Failed to send CreateProcessAsUser request"; 361 PLOG(ERROR) << "Failed to send CreateProcessAsUser request";
362 return false; 362 return false;
363 } 363 }
364 364
365 return true; 365 return true;
366 } 366 }
367 367
368 // Requests the execution server to create a process in the specified session 368 // Requests the execution server to create a process in the specified session
369 // using the default (i.e. Winlogon) token. This routine relies on undocumented 369 // using the default (i.e. Winlogon) token. This routine relies on undocumented
370 // OS functionality and will likely not work on anything but XP or W2K3. 370 // OS functionality and will likely not work on anything but XP or W2K3.
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
466 startup_info.lpDesktop = const_cast<base::char16*>(desktop_name); 466 startup_info.lpDesktop = const_cast<base::char16*>(desktop_name);
467 467
468 PROCESS_INFORMATION temp_process_info = {}; 468 PROCESS_INFORMATION temp_process_info = {};
469 BOOL result = CreateProcessAsUser(user_token, 469 BOOL result = CreateProcessAsUser(user_token,
470 application_name.c_str(), 470 application_name.c_str(),
471 const_cast<LPWSTR>(command_line.c_str()), 471 const_cast<LPWSTR>(command_line.c_str()),
472 process_attributes, 472 process_attributes,
473 thread_attributes, 473 thread_attributes,
474 inherit_handles, 474 inherit_handles,
475 creation_flags, 475 creation_flags,
476 NULL, 476 nullptr,
477 NULL, 477 nullptr,
478 &startup_info, 478 &startup_info,
479 &temp_process_info); 479 &temp_process_info);
480 480
481 // CreateProcessAsUser will fail on XP and W2K3 with ERROR_PIPE_NOT_CONNECTED 481 // CreateProcessAsUser will fail on XP and W2K3 with ERROR_PIPE_NOT_CONNECTED
482 // if the user hasn't logged to the target session yet. In such a case 482 // if the user hasn't logged to the target session yet. In such a case
483 // we try to talk to the execution server directly emulating what 483 // we try to talk to the execution server directly emulating what
484 // the undocumented and not-exported advapi32!CreateRemoteSessionProcessW() 484 // the undocumented and not-exported advapi32!CreateRemoteSessionProcessW()
485 // function does. The created process will run under Winlogon'a token instead 485 // function does. The created process will run under Winlogon'a token instead
486 // of |user_token|. Since Winlogon runs as SYSTEM, this suits our needs. 486 // of |user_token|. Since Winlogon runs as SYSTEM, this suits our needs.
487 if (!result && 487 if (!result &&
(...skipping 27 matching lines...) Expand all
515 515
516 base::win::ScopedProcessInformation process_info(temp_process_info); 516 base::win::ScopedProcessInformation process_info(temp_process_info);
517 517
518 CHECK(process_info.IsValid()); 518 CHECK(process_info.IsValid());
519 process_out->Set(process_info.TakeProcessHandle()); 519 process_out->Set(process_info.TakeProcessHandle());
520 thread_out->Set(process_info.TakeThreadHandle()); 520 thread_out->Set(process_info.TakeThreadHandle());
521 return true; 521 return true;
522 } 522 }
523 523
524 } // namespace remoting 524 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/host/win/host_service.cc ('k') | remoting/host/win/rdp_client.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698