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

Side by Side Diff: base/vista_utils.cc

Issue 624713003: Keep only base/extractor.[cc|h]. (Closed) Base URL: https://chromium.googlesource.com/external/omaha.git@master
Patch Set: Created 6 years, 2 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 | « base/vista_utils.h ('k') | base/vista_utils_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2006-2009 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 // ========================================================================
15
16 #include "omaha/base/vista_utils.h"
17
18 #include <vector>
19 #include "base/scoped_ptr.h"
20 #include "omaha/base/commontypes.h"
21 #include "omaha/base/const_utils.h"
22 #include "omaha/base/constants.h"
23 #include "omaha/base/debug.h"
24 #include "omaha/base/error.h"
25 #include "omaha/base/proc_utils.h"
26 #include "omaha/base/process.h"
27 #include "omaha/base/reg_key.h"
28 #include "omaha/base/scope_guard.h"
29 #include "omaha/base/scoped_any.h"
30 #include "omaha/base/smart_handle.h"
31 #include "omaha/base/synchronized.h"
32 #include "omaha/base/system.h"
33 #include "omaha/base/system_info.h"
34 #include "omaha/base/user_info.h"
35 #include "omaha/base/user_rights.h"
36 #include "omaha/base/utils.h"
37
38 #define LOW_INTEGRITY_SDDL_SACL_A NOTRANSL("S:(ML;;NW;;;LW)")
39 #define LOW_INTEGRITY_SID_W NOTRANSL(L"S-1-16-4096")
40
41 namespace omaha {
42
43 namespace vista {
44
45 namespace {
46
47 // TODO(Omaha): Unit test for this method.
48 HRESULT RunAsUser(const CString& command_line,
49 HANDLE user_token,
50 bool run_as_current_user) {
51 if (INVALID_HANDLE_VALUE == user_token) {
52 return E_INVALIDARG;
53 }
54
55 CString cmd(command_line);
56
57 STARTUPINFO startup_info = { sizeof(startup_info) };
58 PROCESS_INFORMATION process_info = {0};
59
60 DWORD creation_flags(0);
61 void* environment_block(NULL);
62 ON_SCOPE_EXIT(::DestroyEnvironmentBlock, environment_block);
63 if (::CreateEnvironmentBlock(&environment_block, user_token, FALSE)) {
64 creation_flags |= CREATE_UNICODE_ENVIRONMENT;
65 } else {
66 ASSERT(false, (_T("::CreateEnvironmentBlock failed %d"), ::GetLastError()));
67 environment_block = NULL;
68 }
69
70 // ::CreateProcessAsUser() does not work unless the caller is SYSTEM. Does not
71 // matter if the user token is for the current user.
72 BOOL success = run_as_current_user ?
73 ::CreateProcess(0, CStrBuf(cmd, MAX_PATH), 0, 0, false, creation_flags,
74 environment_block, 0, &startup_info, &process_info) :
75 ::CreateProcessAsUser(user_token, 0, CStrBuf(cmd, MAX_PATH), 0, 0, false,
76 creation_flags, environment_block, 0, &startup_info,
77 &process_info);
78
79 if (!success) {
80 HRESULT hr(HRESULTFromLastError());
81 UTIL_LOG(LE, (_T("[RunAsUser failed][cmd=%s][hresult=0x%x]"), cmd, hr));
82 return hr;
83 }
84
85 VERIFY1(::CloseHandle(process_info.hThread));
86 VERIFY1(::CloseHandle(process_info.hProcess));
87
88 return S_OK;
89 }
90
91 } // namespace
92
93 bool IsProcessProtected() {
94 if (!SystemInfo::IsRunningOnVistaOrLater()) {
95 return false;
96 }
97
98 AutoHandle token;
99 VERIFY1(::OpenProcessToken(GetCurrentProcess(),
100 TOKEN_QUERY | TOKEN_QUERY_SOURCE,
101 &token.receive()));
102
103 // Get the Integrity level.
104 DWORD length_needed;
105 BOOL b = ::GetTokenInformation(token,
106 TokenIntegrityLevel,
107 NULL,
108 0,
109 &length_needed);
110 ASSERT1(b == FALSE);
111 if (b) {
112 return false;
113 }
114
115 // The first call to GetTokenInformation is just to get the buffer size
116 if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
117 return false;
118 }
119
120 scoped_ptr<TOKEN_MANDATORY_LABEL> integration_level;
121
122 integration_level.reset(reinterpret_cast<TOKEN_MANDATORY_LABEL*>(
123 new char[length_needed]));
124 if (integration_level.get() == NULL) {
125 return false;
126 }
127
128 if (!::GetTokenInformation(token,
129 TokenIntegrityLevel,
130 integration_level.get(),
131 length_needed,
132 &length_needed)) {
133 return false;
134 }
135
136 wchar_t* sid_str = NULL;
137 VERIFY1(::ConvertSidToStringSid(integration_level->Label.Sid, &sid_str));
138 bool ret = ::lstrcmpW(sid_str, LOW_INTEGRITY_SID_W) == 0;
139 ::LocalFree(sid_str);
140
141 return ret;
142 }
143
144 HRESULT AllowProtectedProcessAccessToSharedObject(const TCHAR* name) {
145 if (!SystemInfo::IsRunningOnVistaOrLater()) {
146 return S_FALSE;
147 }
148
149 ASSERT1(name != NULL);
150
151 PSECURITY_DESCRIPTOR psd = NULL;
152 VERIFY1(::ConvertStringSecurityDescriptorToSecurityDescriptorA(
153 LOW_INTEGRITY_SDDL_SACL_A,
154 SDDL_REVISION_1,
155 &psd,
156 NULL));
157
158 BOOL sacl_present = FALSE;
159 BOOL sacl_defaulted = FALSE;
160 PACL sacl = NULL;
161 VERIFY1(::GetSecurityDescriptorSacl(psd,
162 &sacl_present,
163 &sacl,
164 &sacl_defaulted));
165
166 DWORD ret = ::SetNamedSecurityInfoW(const_cast<TCHAR*>(name),
167 SE_KERNEL_OBJECT,
168 LABEL_SECURITY_INFORMATION,
169 NULL,
170 NULL,
171 NULL,
172 sacl);
173
174 ::LocalFree(psd);
175
176 return HRESULT_FROM_WIN32(ret);
177 }
178
179 HRESULT RunAsCurrentUser(const CString& command_line) {
180 scoped_handle token;
181 if (!::OpenProcessToken(::GetCurrentProcess(),
182 TOKEN_QUERY | TOKEN_DUPLICATE,
183 address(token))) {
184 HRESULT hr = HRESULTFromLastError();
185 UTIL_LOG(LE, (_T("[RunAsCurrentUser: OpenProcessToken failed][0x%x]"), hr));
186 return hr;
187 }
188
189 return RunAsUser(command_line, get(token), true);
190 }
191
192 static HRESULT StartInternetExplorerAsUser(HANDLE user_token,
193 const CString& options) {
194 // Internet Explorer path
195 CString ie_file_path;
196 HRESULT result = RegKey::GetValue(kRegKeyIeClass,
197 kRegValueIeClass,
198 &ie_file_path);
199 ASSERT1(SUCCEEDED(result));
200
201 if (SUCCEEDED(result)) {
202 CString command_line(ie_file_path);
203 command_line += _T(' ');
204 command_line += options;
205 UTIL_LOG(L5, (_T("[StartInternetExplorerAsUser]")
206 _T("[Running IExplore with command line][%s]"),
207 command_line));
208 result = RunAsUser(command_line, user_token, false);
209 }
210 return result;
211 }
212
213 //
214 // Constants used by RestartIEUser()
215 //
216 // The IEUser executable name
217 const TCHAR* kIEUser = _T("IEUSER.EXE");
218
219 // The maximum number of simultaneous
220 // logged on users in FUS that we support
221 const int kMaximumUsers = 16;
222
223
224 // Restart IEUser processs. This is to allow for
225 // IEUser.exe to refresh it's ElevationPolicy cache. Due to a bug
226 // within IE7, IEUser.exe does not refresh it's cache unless it
227 // is restarted in the manner below. If the cache is not refreshed
228 // IEUser does not respect any new ElevationPolicies that a fresh
229 // setup program installs for an ActiveX control or BHO. This code
230 // is adapted from Toolbar.
231 HRESULT RestartIEUser() {
232 // Use the service to restart IEUser.
233 // This allows us to restart IEUser for:
234 // (a) Multiple users for the first-install case
235 // (we currently only restart IEUser for the current interactive user)
236 // (b) Even if we are started in an elevated mode
237
238 if (!SystemInfo::IsRunningOnVistaOrLater()) {
239 UTIL_LOG(L5, (_T("[RestartIEUser - not running on Vista - Exiting]")));
240 return S_OK;
241 }
242
243 // The restart should be attempted from the system account
244 bool is_system_process = false;
245 if (FAILED(IsSystemProcess(&is_system_process)) || !is_system_process) {
246 ASSERT1(false);
247 return E_ACCESSDENIED;
248 }
249
250 // Get the list of users currently running IEUser.exe processes.
251 scoped_handle ieuser_users[kMaximumUsers];
252 int number_of_users = 0;
253 Process::GetUsersOfProcesses(kIEUser, kMaximumUsers, ieuser_users,
254 &number_of_users);
255
256 UTIL_LOG(L5, (_T("[RestartIEUser]")
257 _T("[number_of_users running IEUser %d]"), number_of_users));
258
259 if (!number_of_users) {
260 UTIL_LOG(L5, (_T("[RestartIEUser][No IEUser processes running]")));
261 return S_OK;
262 }
263
264 // Kill current IEUser processes.
265 ProcessTerminator pt(kIEUser);
266 const int kKillWaitTimeoutMs = 5000;
267 bool found = false;
268 const int kill_method = (ProcessTerminator::KILL_METHOD_4_TERMINATE_PROCESS);
269
270 RET_IF_FAILED(pt.KillTheProcess(kKillWaitTimeoutMs,
271 &found,
272 kill_method,
273 false));
274
275 // Restart them.
276 HRESULT result = S_OK;
277 for (int i = 0; i < number_of_users; i++) {
278 // To start a new ieuser.exe, simply start iexplore.exe as a normal user
279 // The -embedding prevents IE from opening a window
280 HRESULT restart_result = StartInternetExplorerAsUser(get(ieuser_users[i]),
281 _T("-embedding"));
282 if (FAILED(restart_result)) {
283 UTIL_LOG(LEVEL_ERROR, (_T("[StartInternetExplorerAsUser failed][0x%x]"),
284 restart_result));
285 result = restart_result;
286 }
287 }
288
289 return result;
290 }
291
292 HRESULT GetExplorerPidForCurrentUserOrSession(uint32* pid) {
293 ASSERT1(pid);
294 std::vector<uint32> pids;
295 HRESULT hr = GetProcessPidsForActiveUserOrSession(kExplorer, &pids);
296 if (FAILED(hr)) {
297 CORE_LOG(LW, (_T("[Did not find explorer.exe processes][0x%x]"), hr));
298 return hr;
299 }
300
301 CORE_LOG(L1, (_T("[Found %u instance(s) of explorer.exe]"), pids.size()));
302
303 *pid = pids[0]; // Return only the first instance of explorer.exe.
304 return S_OK;
305 }
306
307 HRESULT GetExplorerTokenForLoggedInUser(HANDLE* token) {
308 UTIL_LOG(L3, (_T("[GetExplorerTokenForLoggedInUser]")));
309 ASSERT1(token);
310
311 // TODO(omaha): One can set the windows shell to be other than
312 // explorer.exe, handle this case. One way to handle this is to
313 // read the regkey
314 // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon
315 // The only problem with this is it can be overriden with the user reg keys.
316 // Need to figure out a method to do this.
317 // Also consider using the interactive user before picking the first explorer
318 // process i.e. the active user.
319 std::vector<uint32> processes;
320 DWORD flags = EXCLUDE_CURRENT_PROCESS;
321 std::vector<CString> command_lines;
322 CString explorer_file_name(kExplorer);
323 CString user_sid;
324
325 HRESULT hr = Process::FindProcesses(flags,
326 explorer_file_name,
327 true,
328 user_sid,
329 command_lines,
330 &processes);
331 if (FAILED(hr)) {
332 CORE_LOG(LEVEL_ERROR, (_T("[FindProcesses failed][0x%08x]"), hr));
333 return hr;
334 }
335
336 std::vector<uint32>::const_iterator iter = processes.begin();
337 for (; iter != processes.end(); ++iter) {
338 uint32 explorer_pid = *iter;
339 scoped_handle exp(::OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
340 false,
341 explorer_pid));
342 if (exp) {
343 if (::OpenProcessToken(get(exp),
344 TOKEN_DUPLICATE | TOKEN_QUERY | TOKEN_IMPERSONATE,
345 token)) {
346 // TODO(omaha): Consider using the GetWindowsAccountDomainSid
347 // method here. This method returns the domain SID associated
348 // with the passed in SID. This allows us to detect if the user is a
349 // domain user. We should prefer domain users over normal users,
350 // as in corporate environments, these users will be more likely to
351 // allow to be tunneled through a proxy.
352 return S_OK;
353 } else {
354 hr = HRESULTFromLastError();
355 CORE_LOG(LEVEL_WARNING, (_T("[OpenProcessToken failed][0x%08x]"), hr));
356 }
357 } else {
358 hr = HRESULTFromLastError();
359 CORE_LOG(LEVEL_WARNING, (_T("[OpenProcess failed][0x%08x]"), hr));
360 }
361 }
362
363 return hr;
364 }
365
366 HRESULT GetPidsInSession(const TCHAR* exe_name,
367 const TCHAR* user_sid,
368 DWORD session_id,
369 std::vector<uint32>* pids) {
370 ASSERT1(pids);
371 ASSERT1(exe_name);
372 ASSERT1(*exe_name);
373 UTIL_LOG(L3, (_T("[GetPidsInSession][%s][sid=%s][session=%d]"),
374 exe_name, user_sid, session_id));
375
376 pids->clear();
377
378 DWORD flags = EXCLUDE_CURRENT_PROCESS;
379 if (user_sid != NULL) {
380 flags |= INCLUDE_ONLY_PROCESS_OWNED_BY_USER;
381 }
382 std::vector<CString> command_lines;
383 HRESULT hr = Process::FindProcessesInSession(session_id,
384 flags,
385 exe_name,
386 true,
387 user_sid,
388 command_lines,
389 pids);
390 if (FAILED(hr)) {
391 return hr;
392 }
393 return pids->empty() ? HRESULT_FROM_WIN32(ERROR_NOT_FOUND) : S_OK;
394 }
395
396 HRESULT GetProcessPidsForActiveUserOrSession(const TCHAR* exe_name,
397 std::vector<uint32>* pids) {
398 bool is_system = false;
399 HRESULT hr = IsSystemProcess(&is_system);
400 if (FAILED(hr)) {
401 NET_LOG(LE, (_T("[IsSystemProcess failed][0x%x]"), hr));
402 return hr;
403 }
404
405 if (is_system) {
406 return vista::GetPidsInSession(exe_name,
407 NULL,
408 System::GetActiveSessionId(),
409 pids);
410 }
411
412 CString user_sid;
413 // If this call fails, we are still ok.
414 omaha::user_info::GetProcessUser(NULL, NULL, &user_sid);
415 DWORD current_session = System::GetCurrentSessionId();
416 if (FAILED(vista::GetPidsInSession(exe_name,
417 user_sid,
418 current_session,
419 pids))) {
420 // In the case of RunAs, the processes may be under a different identity
421 // than the current sid. So if we are unable to find a process under the
422 // current user's sid, we search for processes running in the current
423 // session regardless of the sid they are running under.
424 return vista::GetPidsInSession(exe_name,
425 NULL,
426 current_session,
427 pids);
428 }
429
430 return S_OK;
431 }
432
433
434
435 HRESULT StartProcessWithTokenOfProcess(uint32 pid,
436 const CString& command_line) {
437 UTIL_LOG(L5, (_T("[StartProcessWithTokenOfProcess]")
438 _T("[pid %u][command_line '%s']"), pid, command_line));
439
440 // Get the token from process.
441 scoped_handle user_token;
442 HRESULT hr = Process::GetImpersonationToken(pid, address(user_token));
443 if (FAILED(hr)) {
444 CORE_LOG(LEVEL_ERROR, (_T("[GetImpersonationToken failed][0x%08x]"), hr));
445 return hr;
446 }
447
448 // Start process using the token.
449 UTIL_LOG(L5, (_T("[StartProcessWithTokenOfProcess][Running process %s]"),
450 command_line));
451 hr = RunAsUser(command_line, get(user_token), false);
452
453 if (FAILED(hr)) {
454 UTIL_LOG(LEVEL_ERROR,
455 (_T("[Vista::StartProcessWithTokenOfProcess - RunAsUser failed][0x%x]"),
456 hr));
457 }
458
459 return hr;
460 }
461
462 HRESULT GetLoggedOnUserToken(HANDLE* token) {
463 ASSERT1(token);
464 *token = NULL;
465
466 uint32 pid = 0;
467 HRESULT hr = GetExplorerPidForCurrentUserOrSession(&pid);
468 if (FAILED(hr)) {
469 return hr;
470 }
471 hr = Process::GetImpersonationToken(pid, token);
472 if (FAILED(hr)) {
473 return hr;
474 }
475
476 ASSERT1(*token);
477 return S_OK;
478 }
479
480 } // namespace vista
481
482 } // namespace omaha
483
OLDNEW
« no previous file with comments | « base/vista_utils.h ('k') | base/vista_utils_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698