Index: base/vista_utils.cc |
diff --git a/base/vista_utils.cc b/base/vista_utils.cc |
deleted file mode 100644 |
index 8a21507652045aed12c1baf68b31177915586258..0000000000000000000000000000000000000000 |
--- a/base/vista_utils.cc |
+++ /dev/null |
@@ -1,483 +0,0 @@ |
-// Copyright 2006-2009 Google Inc. |
-// |
-// Licensed under the Apache License, Version 2.0 (the "License"); |
-// you may not use this file except in compliance with the License. |
-// You may obtain a copy of the License at |
-// |
-// http://www.apache.org/licenses/LICENSE-2.0 |
-// |
-// Unless required by applicable law or agreed to in writing, software |
-// distributed under the License is distributed on an "AS IS" BASIS, |
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
-// See the License for the specific language governing permissions and |
-// limitations under the License. |
-// ======================================================================== |
- |
-#include "omaha/base/vista_utils.h" |
- |
-#include <vector> |
-#include "base/scoped_ptr.h" |
-#include "omaha/base/commontypes.h" |
-#include "omaha/base/const_utils.h" |
-#include "omaha/base/constants.h" |
-#include "omaha/base/debug.h" |
-#include "omaha/base/error.h" |
-#include "omaha/base/proc_utils.h" |
-#include "omaha/base/process.h" |
-#include "omaha/base/reg_key.h" |
-#include "omaha/base/scope_guard.h" |
-#include "omaha/base/scoped_any.h" |
-#include "omaha/base/smart_handle.h" |
-#include "omaha/base/synchronized.h" |
-#include "omaha/base/system.h" |
-#include "omaha/base/system_info.h" |
-#include "omaha/base/user_info.h" |
-#include "omaha/base/user_rights.h" |
-#include "omaha/base/utils.h" |
- |
-#define LOW_INTEGRITY_SDDL_SACL_A NOTRANSL("S:(ML;;NW;;;LW)") |
-#define LOW_INTEGRITY_SID_W NOTRANSL(L"S-1-16-4096") |
- |
-namespace omaha { |
- |
-namespace vista { |
- |
-namespace { |
- |
-// TODO(Omaha): Unit test for this method. |
-HRESULT RunAsUser(const CString& command_line, |
- HANDLE user_token, |
- bool run_as_current_user) { |
- if (INVALID_HANDLE_VALUE == user_token) { |
- return E_INVALIDARG; |
- } |
- |
- CString cmd(command_line); |
- |
- STARTUPINFO startup_info = { sizeof(startup_info) }; |
- PROCESS_INFORMATION process_info = {0}; |
- |
- DWORD creation_flags(0); |
- void* environment_block(NULL); |
- ON_SCOPE_EXIT(::DestroyEnvironmentBlock, environment_block); |
- if (::CreateEnvironmentBlock(&environment_block, user_token, FALSE)) { |
- creation_flags |= CREATE_UNICODE_ENVIRONMENT; |
- } else { |
- ASSERT(false, (_T("::CreateEnvironmentBlock failed %d"), ::GetLastError())); |
- environment_block = NULL; |
- } |
- |
- // ::CreateProcessAsUser() does not work unless the caller is SYSTEM. Does not |
- // matter if the user token is for the current user. |
- BOOL success = run_as_current_user ? |
- ::CreateProcess(0, CStrBuf(cmd, MAX_PATH), 0, 0, false, creation_flags, |
- environment_block, 0, &startup_info, &process_info) : |
- ::CreateProcessAsUser(user_token, 0, CStrBuf(cmd, MAX_PATH), 0, 0, false, |
- creation_flags, environment_block, 0, &startup_info, |
- &process_info); |
- |
- if (!success) { |
- HRESULT hr(HRESULTFromLastError()); |
- UTIL_LOG(LE, (_T("[RunAsUser failed][cmd=%s][hresult=0x%x]"), cmd, hr)); |
- return hr; |
- } |
- |
- VERIFY1(::CloseHandle(process_info.hThread)); |
- VERIFY1(::CloseHandle(process_info.hProcess)); |
- |
- return S_OK; |
-} |
- |
-} // namespace |
- |
-bool IsProcessProtected() { |
- if (!SystemInfo::IsRunningOnVistaOrLater()) { |
- return false; |
- } |
- |
- AutoHandle token; |
- VERIFY1(::OpenProcessToken(GetCurrentProcess(), |
- TOKEN_QUERY | TOKEN_QUERY_SOURCE, |
- &token.receive())); |
- |
- // Get the Integrity level. |
- DWORD length_needed; |
- BOOL b = ::GetTokenInformation(token, |
- TokenIntegrityLevel, |
- NULL, |
- 0, |
- &length_needed); |
- ASSERT1(b == FALSE); |
- if (b) { |
- return false; |
- } |
- |
- // The first call to GetTokenInformation is just to get the buffer size |
- if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER) { |
- return false; |
- } |
- |
- scoped_ptr<TOKEN_MANDATORY_LABEL> integration_level; |
- |
- integration_level.reset(reinterpret_cast<TOKEN_MANDATORY_LABEL*>( |
- new char[length_needed])); |
- if (integration_level.get() == NULL) { |
- return false; |
- } |
- |
- if (!::GetTokenInformation(token, |
- TokenIntegrityLevel, |
- integration_level.get(), |
- length_needed, |
- &length_needed)) { |
- return false; |
- } |
- |
- wchar_t* sid_str = NULL; |
- VERIFY1(::ConvertSidToStringSid(integration_level->Label.Sid, &sid_str)); |
- bool ret = ::lstrcmpW(sid_str, LOW_INTEGRITY_SID_W) == 0; |
- ::LocalFree(sid_str); |
- |
- return ret; |
-} |
- |
-HRESULT AllowProtectedProcessAccessToSharedObject(const TCHAR* name) { |
- if (!SystemInfo::IsRunningOnVistaOrLater()) { |
- return S_FALSE; |
- } |
- |
- ASSERT1(name != NULL); |
- |
- PSECURITY_DESCRIPTOR psd = NULL; |
- VERIFY1(::ConvertStringSecurityDescriptorToSecurityDescriptorA( |
- LOW_INTEGRITY_SDDL_SACL_A, |
- SDDL_REVISION_1, |
- &psd, |
- NULL)); |
- |
- BOOL sacl_present = FALSE; |
- BOOL sacl_defaulted = FALSE; |
- PACL sacl = NULL; |
- VERIFY1(::GetSecurityDescriptorSacl(psd, |
- &sacl_present, |
- &sacl, |
- &sacl_defaulted)); |
- |
- DWORD ret = ::SetNamedSecurityInfoW(const_cast<TCHAR*>(name), |
- SE_KERNEL_OBJECT, |
- LABEL_SECURITY_INFORMATION, |
- NULL, |
- NULL, |
- NULL, |
- sacl); |
- |
- ::LocalFree(psd); |
- |
- return HRESULT_FROM_WIN32(ret); |
-} |
- |
-HRESULT RunAsCurrentUser(const CString& command_line) { |
- scoped_handle token; |
- if (!::OpenProcessToken(::GetCurrentProcess(), |
- TOKEN_QUERY | TOKEN_DUPLICATE, |
- address(token))) { |
- HRESULT hr = HRESULTFromLastError(); |
- UTIL_LOG(LE, (_T("[RunAsCurrentUser: OpenProcessToken failed][0x%x]"), hr)); |
- return hr; |
- } |
- |
- return RunAsUser(command_line, get(token), true); |
-} |
- |
-static HRESULT StartInternetExplorerAsUser(HANDLE user_token, |
- const CString& options) { |
- // Internet Explorer path |
- CString ie_file_path; |
- HRESULT result = RegKey::GetValue(kRegKeyIeClass, |
- kRegValueIeClass, |
- &ie_file_path); |
- ASSERT1(SUCCEEDED(result)); |
- |
- if (SUCCEEDED(result)) { |
- CString command_line(ie_file_path); |
- command_line += _T(' '); |
- command_line += options; |
- UTIL_LOG(L5, (_T("[StartInternetExplorerAsUser]") |
- _T("[Running IExplore with command line][%s]"), |
- command_line)); |
- result = RunAsUser(command_line, user_token, false); |
- } |
- return result; |
-} |
- |
-// |
-// Constants used by RestartIEUser() |
-// |
-// The IEUser executable name |
-const TCHAR* kIEUser = _T("IEUSER.EXE"); |
- |
-// The maximum number of simultaneous |
-// logged on users in FUS that we support |
-const int kMaximumUsers = 16; |
- |
- |
-// Restart IEUser processs. This is to allow for |
-// IEUser.exe to refresh it's ElevationPolicy cache. Due to a bug |
-// within IE7, IEUser.exe does not refresh it's cache unless it |
-// is restarted in the manner below. If the cache is not refreshed |
-// IEUser does not respect any new ElevationPolicies that a fresh |
-// setup program installs for an ActiveX control or BHO. This code |
-// is adapted from Toolbar. |
-HRESULT RestartIEUser() { |
- // Use the service to restart IEUser. |
- // This allows us to restart IEUser for: |
- // (a) Multiple users for the first-install case |
- // (we currently only restart IEUser for the current interactive user) |
- // (b) Even if we are started in an elevated mode |
- |
- if (!SystemInfo::IsRunningOnVistaOrLater()) { |
- UTIL_LOG(L5, (_T("[RestartIEUser - not running on Vista - Exiting]"))); |
- return S_OK; |
- } |
- |
- // The restart should be attempted from the system account |
- bool is_system_process = false; |
- if (FAILED(IsSystemProcess(&is_system_process)) || !is_system_process) { |
- ASSERT1(false); |
- return E_ACCESSDENIED; |
- } |
- |
- // Get the list of users currently running IEUser.exe processes. |
- scoped_handle ieuser_users[kMaximumUsers]; |
- int number_of_users = 0; |
- Process::GetUsersOfProcesses(kIEUser, kMaximumUsers, ieuser_users, |
- &number_of_users); |
- |
- UTIL_LOG(L5, (_T("[RestartIEUser]") |
- _T("[number_of_users running IEUser %d]"), number_of_users)); |
- |
- if (!number_of_users) { |
- UTIL_LOG(L5, (_T("[RestartIEUser][No IEUser processes running]"))); |
- return S_OK; |
- } |
- |
- // Kill current IEUser processes. |
- ProcessTerminator pt(kIEUser); |
- const int kKillWaitTimeoutMs = 5000; |
- bool found = false; |
- const int kill_method = (ProcessTerminator::KILL_METHOD_4_TERMINATE_PROCESS); |
- |
- RET_IF_FAILED(pt.KillTheProcess(kKillWaitTimeoutMs, |
- &found, |
- kill_method, |
- false)); |
- |
- // Restart them. |
- HRESULT result = S_OK; |
- for (int i = 0; i < number_of_users; i++) { |
- // To start a new ieuser.exe, simply start iexplore.exe as a normal user |
- // The -embedding prevents IE from opening a window |
- HRESULT restart_result = StartInternetExplorerAsUser(get(ieuser_users[i]), |
- _T("-embedding")); |
- if (FAILED(restart_result)) { |
- UTIL_LOG(LEVEL_ERROR, (_T("[StartInternetExplorerAsUser failed][0x%x]"), |
- restart_result)); |
- result = restart_result; |
- } |
- } |
- |
- return result; |
-} |
- |
-HRESULT GetExplorerPidForCurrentUserOrSession(uint32* pid) { |
- ASSERT1(pid); |
- std::vector<uint32> pids; |
- HRESULT hr = GetProcessPidsForActiveUserOrSession(kExplorer, &pids); |
- if (FAILED(hr)) { |
- CORE_LOG(LW, (_T("[Did not find explorer.exe processes][0x%x]"), hr)); |
- return hr; |
- } |
- |
- CORE_LOG(L1, (_T("[Found %u instance(s) of explorer.exe]"), pids.size())); |
- |
- *pid = pids[0]; // Return only the first instance of explorer.exe. |
- return S_OK; |
-} |
- |
-HRESULT GetExplorerTokenForLoggedInUser(HANDLE* token) { |
- UTIL_LOG(L3, (_T("[GetExplorerTokenForLoggedInUser]"))); |
- ASSERT1(token); |
- |
- // TODO(omaha): One can set the windows shell to be other than |
- // explorer.exe, handle this case. One way to handle this is to |
- // read the regkey |
- // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon |
- // The only problem with this is it can be overriden with the user reg keys. |
- // Need to figure out a method to do this. |
- // Also consider using the interactive user before picking the first explorer |
- // process i.e. the active user. |
- std::vector<uint32> processes; |
- DWORD flags = EXCLUDE_CURRENT_PROCESS; |
- std::vector<CString> command_lines; |
- CString explorer_file_name(kExplorer); |
- CString user_sid; |
- |
- HRESULT hr = Process::FindProcesses(flags, |
- explorer_file_name, |
- true, |
- user_sid, |
- command_lines, |
- &processes); |
- if (FAILED(hr)) { |
- CORE_LOG(LEVEL_ERROR, (_T("[FindProcesses failed][0x%08x]"), hr)); |
- return hr; |
- } |
- |
- std::vector<uint32>::const_iterator iter = processes.begin(); |
- for (; iter != processes.end(); ++iter) { |
- uint32 explorer_pid = *iter; |
- scoped_handle exp(::OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, |
- false, |
- explorer_pid)); |
- if (exp) { |
- if (::OpenProcessToken(get(exp), |
- TOKEN_DUPLICATE | TOKEN_QUERY | TOKEN_IMPERSONATE, |
- token)) { |
- // TODO(omaha): Consider using the GetWindowsAccountDomainSid |
- // method here. This method returns the domain SID associated |
- // with the passed in SID. This allows us to detect if the user is a |
- // domain user. We should prefer domain users over normal users, |
- // as in corporate environments, these users will be more likely to |
- // allow to be tunneled through a proxy. |
- return S_OK; |
- } else { |
- hr = HRESULTFromLastError(); |
- CORE_LOG(LEVEL_WARNING, (_T("[OpenProcessToken failed][0x%08x]"), hr)); |
- } |
- } else { |
- hr = HRESULTFromLastError(); |
- CORE_LOG(LEVEL_WARNING, (_T("[OpenProcess failed][0x%08x]"), hr)); |
- } |
- } |
- |
- return hr; |
-} |
- |
-HRESULT GetPidsInSession(const TCHAR* exe_name, |
- const TCHAR* user_sid, |
- DWORD session_id, |
- std::vector<uint32>* pids) { |
- ASSERT1(pids); |
- ASSERT1(exe_name); |
- ASSERT1(*exe_name); |
- UTIL_LOG(L3, (_T("[GetPidsInSession][%s][sid=%s][session=%d]"), |
- exe_name, user_sid, session_id)); |
- |
- pids->clear(); |
- |
- DWORD flags = EXCLUDE_CURRENT_PROCESS; |
- if (user_sid != NULL) { |
- flags |= INCLUDE_ONLY_PROCESS_OWNED_BY_USER; |
- } |
- std::vector<CString> command_lines; |
- HRESULT hr = Process::FindProcessesInSession(session_id, |
- flags, |
- exe_name, |
- true, |
- user_sid, |
- command_lines, |
- pids); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- return pids->empty() ? HRESULT_FROM_WIN32(ERROR_NOT_FOUND) : S_OK; |
-} |
- |
-HRESULT GetProcessPidsForActiveUserOrSession(const TCHAR* exe_name, |
- std::vector<uint32>* pids) { |
- bool is_system = false; |
- HRESULT hr = IsSystemProcess(&is_system); |
- if (FAILED(hr)) { |
- NET_LOG(LE, (_T("[IsSystemProcess failed][0x%x]"), hr)); |
- return hr; |
- } |
- |
- if (is_system) { |
- return vista::GetPidsInSession(exe_name, |
- NULL, |
- System::GetActiveSessionId(), |
- pids); |
- } |
- |
- CString user_sid; |
- // If this call fails, we are still ok. |
- omaha::user_info::GetProcessUser(NULL, NULL, &user_sid); |
- DWORD current_session = System::GetCurrentSessionId(); |
- if (FAILED(vista::GetPidsInSession(exe_name, |
- user_sid, |
- current_session, |
- pids))) { |
- // In the case of RunAs, the processes may be under a different identity |
- // than the current sid. So if we are unable to find a process under the |
- // current user's sid, we search for processes running in the current |
- // session regardless of the sid they are running under. |
- return vista::GetPidsInSession(exe_name, |
- NULL, |
- current_session, |
- pids); |
- } |
- |
- return S_OK; |
-} |
- |
- |
- |
-HRESULT StartProcessWithTokenOfProcess(uint32 pid, |
- const CString& command_line) { |
- UTIL_LOG(L5, (_T("[StartProcessWithTokenOfProcess]") |
- _T("[pid %u][command_line '%s']"), pid, command_line)); |
- |
- // Get the token from process. |
- scoped_handle user_token; |
- HRESULT hr = Process::GetImpersonationToken(pid, address(user_token)); |
- if (FAILED(hr)) { |
- CORE_LOG(LEVEL_ERROR, (_T("[GetImpersonationToken failed][0x%08x]"), hr)); |
- return hr; |
- } |
- |
- // Start process using the token. |
- UTIL_LOG(L5, (_T("[StartProcessWithTokenOfProcess][Running process %s]"), |
- command_line)); |
- hr = RunAsUser(command_line, get(user_token), false); |
- |
- if (FAILED(hr)) { |
- UTIL_LOG(LEVEL_ERROR, |
- (_T("[Vista::StartProcessWithTokenOfProcess - RunAsUser failed][0x%x]"), |
- hr)); |
- } |
- |
- return hr; |
-} |
- |
-HRESULT GetLoggedOnUserToken(HANDLE* token) { |
- ASSERT1(token); |
- *token = NULL; |
- |
- uint32 pid = 0; |
- HRESULT hr = GetExplorerPidForCurrentUserOrSession(&pid); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- hr = Process::GetImpersonationToken(pid, token); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- ASSERT1(*token); |
- return S_OK; |
-} |
- |
-} // namespace vista |
- |
-} // namespace omaha |
- |