Index: common/goopdate_utils.cc |
diff --git a/common/goopdate_utils.cc b/common/goopdate_utils.cc |
deleted file mode 100644 |
index bb350af7946e7c607709577719addba7bbb71403..0000000000000000000000000000000000000000 |
--- a/common/goopdate_utils.cc |
+++ /dev/null |
@@ -1,1393 +0,0 @@ |
-// Copyright 2007-2010 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/common/goopdate_utils.h" |
-#include <atlsecurity.h> |
-#include "omaha/base/app_util.h" |
-#include "omaha/base/const_addresses.h" |
-#include "omaha/base/const_object_names.h" |
-#include "omaha/base/const_utils.h" |
-#include "omaha/base/debug.h" |
-#include "omaha/base/error.h" |
-#include "omaha/base/file.h" |
-#include "omaha/base/logging.h" |
-#include "omaha/base/omaha_version.h" |
-#include "omaha/base/path.h" |
-#include "omaha/base/proc_utils.h" |
-#include "omaha/base/process.h" |
-#include "omaha/base/reg_key.h" |
-#include "omaha/base/safe_format.h" |
-#include "omaha/base/scope_guard.h" |
-#include "omaha/base/scoped_impersonation.h" |
-#include "omaha/base/service_utils.h" |
-#include "omaha/base/string.h" |
-#include "omaha/base/system.h" |
-#include "omaha/base/system_info.h" |
-#include "omaha/base/user_info.h" |
-#include "omaha/base/utils.h" |
-#include "omaha/base/vista_utils.h" |
-#include "omaha/base/vistautil.h" |
-#include "omaha/common/command_line_builder.h" |
-#include "omaha/common/config_manager.h" |
-#include "omaha/common/const_cmd_line.h" |
-#include "omaha/common/const_goopdate.h" |
-#include "omaha/common/oem_install_utils.h" |
-#include "omaha/statsreport/metrics.h" |
-#include "goopdate/omaha3_idl.h" |
- |
-namespace omaha { |
- |
-namespace goopdate_utils { |
- |
-namespace { |
- |
-const int kTerminateBrowserTimeoutMs = 60000; |
- |
-bool IsMachineProcessWithoutPrivileges(bool is_machine_process) { |
- return is_machine_process && !vista_util::IsUserAdmin(); |
-} |
- |
-HRESULT LaunchImpersonatedCmdLine(const CString& cmd_line) { |
- CORE_LOG(L3, (_T("[LaunchImpersonatedCmdLine][%s]"), cmd_line)); |
- |
- scoped_handle impersonation_token; |
- HRESULT hr = vista::GetLoggedOnUserToken(address(impersonation_token)); |
- if (FAILED(hr)) { |
- UTIL_LOG(LE, (_T("[GetLoggedOnUserToken failed][0x%x]"), hr)); |
- return hr; |
- } |
- |
- scoped_impersonation impersonate_user(get(impersonation_token)); |
- hr = HRESULT_FROM_WIN32(impersonate_user.result()); |
- if (FAILED(hr)) { |
- UTIL_LOG(LE, (_T("[impersonation failed][0x%x]"), hr)); |
- return hr; |
- } |
- |
- CComPtr<IProcessLauncher> launcher; |
- hr = launcher.CoCreateInstance(CLSID_ProcessLauncherClass, |
- NULL, |
- CLSCTX_LOCAL_SERVER); |
- if (FAILED(hr)) { |
- UTIL_LOG(LE, (_T("[CoCreateInstance IProcessLauncher failed][0x%x]"), hr)); |
- return hr; |
- } |
- |
- hr = launcher->LaunchCmdLine(cmd_line); |
- if (FAILED(hr)) { |
- UTIL_LOG(LE, (_T("[IProcessLauncher.LaunchBrowser failed][0x%x]"), hr)); |
- return hr; |
- } |
- |
- return S_OK; |
-} |
- |
-HRESULT LaunchImpersonatedBrowser(BrowserType type, const CString& url) { |
- CORE_LOG(L3, (_T("[LaunchImpersonatedBrowser][%u][%s]"), type, url)); |
- |
- scoped_handle impersonation_token; |
- HRESULT hr = vista::GetLoggedOnUserToken(address(impersonation_token)); |
- if (FAILED(hr)) { |
- UTIL_LOG(LE, (_T("[GetLoggedOnUserToken failed][0x%x]"), hr)); |
- return hr; |
- } |
- |
- scoped_impersonation impersonate_user(get(impersonation_token)); |
- hr = HRESULT_FROM_WIN32(impersonate_user.result()); |
- if (FAILED(hr)) { |
- UTIL_LOG(LE, (_T("[impersonation failed][0x%x]"), hr)); |
- return hr; |
- } |
- |
- CComPtr<IProcessLauncher> launcher; |
- hr = launcher.CoCreateInstance(CLSID_ProcessLauncherClass, |
- NULL, |
- CLSCTX_LOCAL_SERVER); |
- if (FAILED(hr)) { |
- UTIL_LOG(LE, (_T("[CoCreateInstance IProcessLauncher failed][0x%x]"), hr)); |
- return hr; |
- } |
- |
- hr = launcher->LaunchBrowser(type, url); |
- if (FAILED(hr)) { |
- UTIL_LOG(LE, (_T("[IProcessLauncher.LaunchBrowser failed][0x%x]"), hr)); |
- return hr; |
- } |
- |
- return S_OK; |
-} |
- |
-} // namespace |
- |
-HRESULT LaunchCmdLine(bool is_machine, const CString& cmd_line) { |
- CORE_LOG(L3, (_T("[LaunchCmdLine][%d][%s]"), is_machine, cmd_line)); |
- |
- if (is_machine && vista_util::IsVistaOrLater() && vista_util::IsUserAdmin()) { |
- return LaunchImpersonatedCmdLine(cmd_line); |
- } |
- |
- HRESULT hr = System::ShellExecuteCommandLine(cmd_line, NULL, NULL); |
- if (FAILED(hr)) { |
- UTIL_LOG(LE, (_T("[ShellExecuteCommandLine failed][0x%x]"), hr)); |
- return hr; |
- } |
- |
- return S_OK; |
-} |
- |
-HRESULT LaunchBrowser(bool is_machine, BrowserType type, const CString& url) { |
- CORE_LOG(L3, (_T("[LaunchBrowser][%d][%u][%s]"), is_machine, type, url)); |
- |
- if (is_machine && vista_util::IsVistaOrLater() && vista_util::IsUserAdmin()) { |
- // Other than having a service launch the browser using CreateProcessAsUser, |
- // there is no easy solution if we are unable to launch the browser |
- // impersonated. |
- return LaunchImpersonatedBrowser(type, url); |
- } |
- |
- HRESULT hr = RunBrowser(type, url); |
- if (FAILED(hr)) { |
- UTIL_LOG(LE, (_T("[RunBrowser failed][0x%x]"), hr)); |
- return hr; |
- } |
- |
- return S_OK; |
-} |
- |
-CString BuildGoogleUpdateExeDir(bool is_machine) { |
- ConfigManager& cm = *ConfigManager::Instance(); |
- return is_machine ? cm.GetMachineGoopdateInstallDir() : |
- cm.GetUserGoopdateInstallDir(); |
-} |
- |
-CString BuildGoogleUpdateExePath(bool is_machine) { |
- CORE_LOG(L3, (_T("[BuildGoogleUpdateExePath][%d]"), is_machine)); |
- |
- CPath full_file_path(BuildGoogleUpdateExeDir(is_machine)); |
- VERIFY1(full_file_path.Append(kOmahaShellFileName)); |
- |
- return full_file_path; |
-} |
- |
-CString BuildGoogleUpdateServicesPath(bool is_machine) { |
- CORE_LOG(L3, (_T("[BuildGoogleUpdateServicesPath][%d]"), is_machine)); |
- |
- CPath full_file_path(BuildInstallDirectory(is_machine, GetVersionString())); |
- VERIFY1(full_file_path.Append(kCrashHandlerFileName)); |
- |
- return full_file_path; |
-} |
- |
-HRESULT StartElevatedSelfWithArgsAndWait(const TCHAR* args, DWORD* exit_code) { |
- ASSERT1(args); |
- ASSERT1(exit_code); |
- CORE_LOG(L3, (_T("[StartElevatedSelfWithArgsAndWait]"))); |
- |
- // Get the process executable. |
- TCHAR filename[MAX_PATH] = {0}; |
- if (::GetModuleFileName(NULL, filename, MAX_PATH) == 0) { |
- HRESULT hr = HRESULTFromLastError(); |
- CORE_LOG(LEVEL_ERROR, (_T("[GetModuleFileName failed][0x%08x]"), hr)); |
- return hr; |
- } |
- |
- // Launch self elevated and wait. |
- *exit_code = 0; |
- CORE_LOG(L1, |
- (_T("[RunElevated filename='%s'][arguments='%s']"), filename, args)); |
- // According to the MSDN documentation for ::ShowWindow: "nCmdShow. This |
- // parameter is ignored the first time an application calls ShowWindow, if |
- // the program that launched the application provides a STARTUPINFO |
- // structure.". We want to force showing the UI window. So we pass in |
- // SW_SHOWNORMAL. |
- HRESULT hr(vista_util::RunElevated(filename, args, SW_SHOWNORMAL, exit_code)); |
- CORE_LOG(L2, (_T("[elevated instance exit code][%u]"), *exit_code)); |
- if (FAILED(hr)) { |
- CORE_LOG(LEVEL_ERROR, (_T("[RunElevated failed][0x%08x]"), hr)); |
- return hr; |
- } |
- |
- return S_OK; |
-} |
- |
-HRESULT StartGoogleUpdateWithArgs(bool is_machine, |
- const TCHAR* args, |
- HANDLE* process) { |
- CORE_LOG(L3, (_T("[StartGoogleUpdateWithArgs][%d][%s]"), |
- is_machine, args ? args : _T(""))); |
- |
- CString exe_path = BuildGoogleUpdateExePath(is_machine); |
- |
- CORE_LOG(L3, (_T("[command line][%s][%s]"), exe_path, args ? args : _T(""))); |
- |
- HRESULT hr = System::ShellExecuteProcess(exe_path, args, NULL, process); |
- if (FAILED(hr)) { |
- CORE_LOG(LE, (_T("[can't start process][%s][0x%08x]"), exe_path, hr)); |
- return hr; |
- } |
- return S_OK; |
-} |
- |
-HRESULT StartCrashHandler(bool is_machine) { |
- CORE_LOG(L3, (_T("[StartCrashHandler]"))); |
- |
- ASSERT1(!is_machine || user_info::IsRunningAsSystem()); |
- |
- CString exe_path = BuildGoogleUpdateServicesPath(is_machine); |
- CommandLineBuilder builder(COMMANDLINE_MODE_CRASH_HANDLER); |
- CString cmd_line = builder.GetCommandLineArgs(); |
- return System::StartProcessWithArgs(exe_path, cmd_line); |
-} |
- |
-bool IsRunningFromOfficialGoopdateDir(bool is_machine) { |
- const ConfigManager& cm = *ConfigManager::Instance(); |
- bool is_official_dir = is_machine ? |
- cm.IsRunningFromMachineGoopdateInstallDir() : |
- cm.IsRunningFromUserGoopdateInstallDir(); |
- CORE_LOG(L3, (_T("[running from official dir][%d]"), is_official_dir)); |
- return is_official_dir; |
-} |
- |
-CString GetHKRoot() { |
- return IsRunningFromOfficialGoopdateDir(true) ? _T("HKLM") : _T("HKCU"); |
-} |
- |
-HRESULT InitializeSecurity() { |
- // Creates a security descriptor in absolute format and includes the owner |
- // and the primary group. We grant access to admins and system. |
- CSecurityDesc security_descriptor; |
- if (SystemInfo::IsRunningOnVistaOrLater()) { |
- // To allow for low-integrity IE to call into IGoogleUpdate. |
- security_descriptor.FromString(LOW_INTEGRITY_SDDL_SACL); |
- } |
- security_descriptor.SetOwner(Sids::Admins()); |
- security_descriptor.SetGroup(Sids::Admins()); |
- CDacl dacl; |
- dacl.AddAllowedAce(Sids::System(), COM_RIGHTS_EXECUTE); |
- dacl.AddAllowedAce(Sids::Admins(), COM_RIGHTS_EXECUTE); |
- dacl.AddAllowedAce(Sids::AuthenticatedUser(), COM_RIGHTS_EXECUTE); |
- |
- security_descriptor.SetDacl(dacl); |
- security_descriptor.MakeAbsolute(); |
- |
- SECURITY_DESCRIPTOR* sd = const_cast<SECURITY_DESCRIPTOR*>( |
- security_descriptor.GetPSECURITY_DESCRIPTOR()); |
- |
- return ::CoInitializeSecurity( |
- sd, |
- -1, |
- NULL, // Let COM choose what authentication services to register. |
- NULL, |
- RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // Data integrity and encryption. |
- RPC_C_IMP_LEVEL_IDENTIFY, // Only allow a server to identify. |
- NULL, |
- EOAC_DYNAMIC_CLOAKING | EOAC_NO_CUSTOM_MARSHAL, |
- NULL); |
-} |
- |
-// This is only used for legacy handoff support. |
-CString GetProductName(const CString& app_guid) { |
- const TCHAR* product_name = NULL; |
- const TCHAR gears_guid[] = _T("{283EAF47-8817-4c2b-A801-AD1FADFB7BAA}"); |
- const TCHAR google_talk_plugin[] = |
- _T("{D0AB2EBC-931B-4013-9FEB-C9C4C2225C8C}"); |
- const TCHAR youtube_uploader_guid[] = |
- _T("{A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}"); |
- |
- if (app_guid.CompareNoCase(gears_guid) == 0) { |
- product_name = _T("Gears"); |
- } else if (app_guid.CompareNoCase(google_talk_plugin) == 0) { |
- product_name = _T("Google Talk Plugin"); |
- } else if (app_guid.CompareNoCase(youtube_uploader_guid) == 0) { |
- product_name = _T("YouTube Uploader"); |
- } else { |
- product_name = _T("Google App"); |
- } |
- return product_name; |
-} |
- |
-HRESULT RedirectHKCR(bool is_machine) { |
- RegKey classes_key; |
- HRESULT hr = classes_key.Open(is_machine ? |
- HKEY_LOCAL_MACHINE : |
- HKEY_CURRENT_USER, |
- _T("Software\\Classes"), |
- KEY_ALL_ACCESS); |
- if (FAILED(hr)) { |
- ASSERT(FALSE, (_T("RedirectHKCR - key.Open(%d) fail %d"), is_machine, hr)); |
- return hr; |
- } |
- |
- LONG result = ::RegOverridePredefKey(HKEY_CLASSES_ROOT, classes_key.Key()); |
- if (result != ERROR_SUCCESS) { |
- ASSERT(false, (_T("RedirectHKCR - RegOverridePredefKey fail %d"), result)); |
- return HRESULT_FROM_WIN32(result); |
- } |
- |
- return S_OK; |
-} |
- |
-HRESULT RemoveRedirectHKCR() { |
- LONG result = ::RegOverridePredefKey(HKEY_CLASSES_ROOT, NULL); |
- if (result != ERROR_SUCCESS) { |
- ASSERT(FALSE, (_T("RemoveRedirectHKCR - RegOverridePredefKey %d"), result)); |
- return HRESULT_FROM_WIN32(result); |
- } |
- |
- return S_OK; |
-} |
- |
-HRESULT RegisterTypeLib(bool is_admin, |
- const CComBSTR& path, |
- ITypeLib* type_lib) { |
- // Typelib registration. |
- CORE_LOG(L3, (_T("[Registering TypeLib]"))); |
- HRESULT hr = S_OK; |
- if (!is_admin && |
- SUCCEEDED(goopdate_utils::RegisterTypeLibForUser(type_lib, path, NULL))) { |
- return S_OK; |
- } |
- |
- // For Admin cases, we use ::RegisterTypeLib(). |
- // For platforms where ::RegisterTypeLibForUser is not available, we register |
- // with ::RegisterTypeLib, and rely on HKCR=>HKCU redirection. |
- hr = ::RegisterTypeLib(type_lib, path, NULL); |
- ASSERT(SUCCEEDED(hr), (_T("[TypeLib registration failed][0x%08x]"), hr)); |
- return hr; |
-} |
- |
-HRESULT UnRegisterTypeLib(bool is_admin, const CComBSTR&, ITypeLib* type_lib) { |
- // Typelib unregistration. |
- CORE_LOG(L3, (_T("[Unregistering Typelib]"))); |
- TLIBATTR* tlib_attr = NULL; |
- HRESULT hr = type_lib->GetLibAttr(&tlib_attr); |
- ASSERT(SUCCEEDED(hr), (_T("[GetLibAttr failed][0x%08x]"), hr)); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- ON_SCOPE_EXIT_OBJ(*type_lib, &ITypeLib::ReleaseTLibAttr, tlib_attr); |
- |
- if (!is_admin && |
- SUCCEEDED(goopdate_utils::UnRegisterTypeLibForUser( |
- tlib_attr->guid, |
- tlib_attr->wMajorVerNum, |
- tlib_attr->wMinorVerNum, |
- tlib_attr->lcid, |
- tlib_attr->syskind))) { |
- return S_OK; |
- } |
- |
- // For Admin cases, we use ::UnRegisterTypeLib(). |
- // For platforms where ::UnRegisterTypeLibForUser is not available, we |
- // unregister with ::UnRegisterTypeLib, and rely on HKCR=>HKCU redirection. |
- hr = ::UnRegisterTypeLib(tlib_attr->guid, |
- tlib_attr->wMajorVerNum, |
- tlib_attr->wMinorVerNum, |
- tlib_attr->lcid, |
- tlib_attr->syskind); |
- |
- // We assert before the check for TYPE_E_REGISTRYACCESS below because we want |
- // to catch the case where we're trying to unregister more than once because |
- // that would be a bug. |
- ASSERT(SUCCEEDED(hr), |
- (_T("[UnRegisterTypeLib failed. ") |
- _T("This is likely a multiple unregister bug.][0x%08x]"), hr)); |
- |
- // If you try to unregister a type library that's already unregistered, |
- // it will return with this failure, which is OK. |
- if (hr == TYPE_E_REGISTRYACCESS) { |
- hr = S_OK; |
- } |
- |
- return hr; |
-} |
- |
-HRESULT RegisterOrUnregisterModule(bool is_machine, |
- bool register_server, |
- RegisterOrUnregisterFunction registrar, |
- void* data) { |
- ASSERT1(registrar); |
- |
- // ATL by default registers the control to HKCR and we want to register |
- // either in HKLM, or in HKCU, depending on whether we are laying down |
- // the system googleupdate, or the user googleupdate. |
- // We solve this for the user goopdate case by: |
- // * Having the RGS file take a HKROOT parameter that translates to either |
- // HKLM or HKCU. |
- // * Redirecting HKCR to HKCU\software\classes, for a user installation, to |
- // cover Proxy registration. |
- // For the machine case, we still redirect HKCR to HKLM\\Software\\Classes, |
- // to ensure that Proxy registration happens in HKLM. |
- HRESULT hr = RedirectHKCR(is_machine); |
- ASSERT1(SUCCEEDED(hr)); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- // We need to stop redirecting at the end of this function. |
- ON_SCOPE_EXIT(RemoveRedirectHKCR); |
- |
- hr = (*registrar)(data, register_server); |
- if (FAILED(hr)) { |
- CORE_LOG(LW, (_T("[RegisterOrUnregisterModule failed][%d][0x%08x]"), |
- register_server, hr)); |
- ASSERT1(!register_server); |
- } |
- |
- return hr; |
-} |
- |
-HRESULT RegisterOrUnregisterModuleWithTypelib( |
- bool is_machine, |
- bool register_server, |
- RegisterOrUnregisterFunction registrar, |
- void* data) { |
- ASSERT1(registrar); |
- |
- // By default, ATL registers the control to HKCR and we want to register |
- // either in HKLM, or in HKCU, depending on whether we are laying down |
- // the machine googleupdate, or the user googleupdate. |
- // We solve this for the user goopdate case by: |
- // * Having the RGS file take a HKROOT parameter that translates to either |
- // HKLM or HKCU. |
- // * Redirecting HKCR to HKCU\software\classes, for a user installation, to |
- // cover AppId and TypeLib registration |
- // * All the above makes ATL work correctly for 2K/XP. However on Win2K3 |
- // and Vista, redirection does not work by itself, because in these |
- // platforms, RegisterTypeLib writes explicitly to HKLM\Software\Classes. |
- // We need to specifically call the new RegisterTypeLibForUser() API. |
- // So, we do that as well. |
- // For the machine case, we still redirect HKCR to HKLM\\Software\\Classes, |
- // because otherwise RegisterTypeLib ends up overwriting HKCU if the key |
- // already exists in HKCU. |
- HRESULT hr = RedirectHKCR(is_machine); |
- ASSERT1(SUCCEEDED(hr)); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- // We need to stop redirecting at the end of this function. |
- ON_SCOPE_EXIT(RemoveRedirectHKCR); |
- |
- // load the type library. |
- CComPtr<ITypeLib> type_lib; |
- CComBSTR path; |
- hr = ::AtlLoadTypeLib(_AtlBaseModule.GetModuleInstance(), NULL, &path, |
- &type_lib); |
- if (FAILED(hr)) { |
- ASSERT(false, (_T("[AtlLoadTypeLib failed][0x%08x]"), hr)); |
- return hr; |
- } |
- |
- if (register_server) { |
- hr = (*registrar)(data, register_server); |
- if (FAILED(hr)) { |
- ASSERT(false, (_T("[Module registration failed][0x%08x]"), hr)); |
- return hr; |
- } |
- |
- return RegisterTypeLib(is_machine, path, type_lib); |
- } else { |
- hr = UnRegisterTypeLib(is_machine, path, type_lib); |
- if (FAILED(hr)) { |
- ASSERT(false, (_T("[UnRegisterTypeLib failed][0x%08x]"), hr)); |
- return hr; |
- } |
- |
- return (*registrar)(data, register_server); |
- } |
-} |
- |
-HRESULT RegisterTypeLibForUser(ITypeLib* lib, |
- OLECHAR* path, |
- OLECHAR* help_dir) { |
- CORE_LOG(L3, (_T("[RegisterTypeLibForUser]"))); |
- ASSERT1(lib); |
- ASSERT1(path); |
- // help_dir can be NULL. |
- |
- const TCHAR* library_name = _T("oleaut32.dll"); |
- scoped_library module(static_cast<HINSTANCE>(::LoadLibrary(library_name))); |
- if (!module) { |
- HRESULT hr = HRESULTFromLastError(); |
- CORE_LOG(LEVEL_ERROR, |
- (_T("[LoadLibrary failed][%s][0x%08x]"), library_name, hr)); |
- return hr; |
- } |
- |
- // RegisterTypeLibForUser function from oleaut32.dll. |
- typedef HRESULT(__stdcall *PF)(ITypeLib*, OLECHAR*, OLECHAR*); |
- |
- const char* function_name = "RegisterTypeLibForUser"; |
- PF fp = reinterpret_cast<PF>(::GetProcAddress(get(module), function_name)); |
- if (!fp) { |
- HRESULT hr = HRESULTFromLastError(); |
- CORE_LOG(LEVEL_ERROR, |
- (_T("[GetProcAddress failed][%s][0x%08x]"), |
- function_name, library_name, hr)); |
- return hr; |
- } |
- |
- CORE_LOG(L3, (_T("[Calling RegisterTypelibForUser in oleaut]"))); |
- HRESULT hr = fp(lib, path, help_dir); |
- if (FAILED(hr)) { |
- CORE_LOG(LEVEL_ERROR, (_T("[regtypelib_for_user failed][0x%08x]"), hr)); |
- return hr; |
- } |
- |
- return S_OK; |
-} |
- |
-HRESULT UnRegisterTypeLibForUser(REFGUID lib_id, |
- WORD major_ver_num, |
- WORD minor_ver_num, |
- LCID lcid, |
- SYSKIND syskind) { |
- CORE_LOG(L3, (_T("[UnRegisterTypeLibForUser]"))); |
- |
- const TCHAR* library_name = _T("oleaut32.dll"); |
- scoped_library module(static_cast<HINSTANCE>(::LoadLibrary(library_name))); |
- if (!module) { |
- HRESULT hr = HRESULTFromLastError(); |
- CORE_LOG(LEVEL_ERROR, |
- (_T("[LoadLibrary failed][%s][0x%08x]"), library_name, hr)); |
- return hr; |
- } |
- |
- // UnRegisterTypeLibForUser function from oleaut32.dll. |
- typedef HRESULT (__stdcall *PF)(REFGUID, WORD, WORD, LCID, SYSKIND); |
- |
- const char* function_name = "UnRegisterTypeLibForUser"; |
- PF fp = reinterpret_cast<PF>(::GetProcAddress(get(module), function_name)); |
- if (!fp) { |
- HRESULT hr = HRESULTFromLastError(); |
- CORE_LOG(LEVEL_ERROR, |
- (_T("[GetProcAddress failed][%s][0x%08x]"), |
- function_name, library_name, hr)); |
- return hr; |
- } |
- |
- CORE_LOG(L3, (_T("[Calling UnRegisterTypeLibForUser in oleaut]"))); |
- HRESULT hr = fp(lib_id, major_ver_num, minor_ver_num, lcid, syskind); |
- if (FAILED(hr)) { |
- CORE_LOG(LEVEL_ERROR, (_T("[unregtypelib_for_user failed][0x%08x]"), hr)); |
- return hr; |
- } |
- |
- return S_OK; |
-} |
- |
-// TODO(omaha): This method's name is much more specific than what it does. Can |
-// we just copy the code to scheduled task and service code and eliminate it? |
-// Reads the current value under {HKLM|HKCU}\Google\Update\value_name. Returns |
-// default_val if value_name does not exist. |
-CString GetCurrentVersionedName(bool is_machine, |
- const TCHAR* value_name, |
- const TCHAR* default_val) { |
- CORE_LOG(L3, (_T("[ConfigManager::GetCurrentVersionedName]"))); |
- ASSERT1(value_name && *value_name); |
- ASSERT1(default_val && *default_val); |
- |
- const TCHAR* key_name = is_machine ? MACHINE_REG_UPDATE : USER_REG_UPDATE; |
- CString name; |
- HRESULT hr(RegKey::GetValue(key_name, value_name, &name)); |
- if (FAILED(hr)) { |
- CORE_LOG(L4, (_T("[GetValue failed][%s][0x%x][Using default name][%s]"), |
- value_name, hr, default_val)); |
- name = default_val; |
- } |
- |
- CORE_LOG(L3, (_T("[Versioned Name][%s]"), name)); |
- return name; |
-} |
- |
-// Creates a unique name of the form "{prefix}1c9b3d6baf90df3" and stores it in |
-// the registry under HKLM/HKCU\Google\Update\value_name. Subsequent |
-// invocations of GetCurrentTaskName() will return this new value. |
-HRESULT CreateAndSetVersionedNameInRegistry(bool is_machine, |
- const TCHAR* prefix, |
- const TCHAR* value_name) { |
- ASSERT1(prefix && *prefix); |
- ASSERT1(value_name && *value_name); |
- |
- // TODO(omaha): Move from service_utils.h since it is used for other purposes. |
- CString name(ServiceInstall::GenerateServiceName(prefix)); |
- CORE_LOG(L3, (_T("Versioned name[%s][%s][%s]"), prefix, value_name, name)); |
- |
- const TCHAR* key_name = is_machine ? MACHINE_REG_UPDATE : USER_REG_UPDATE; |
- return RegKey::SetValue(key_name, value_name, name); |
-} |
- |
-HRESULT TerminateAllBrowsers( |
- BrowserType type, |
- TerminateBrowserResult* browser_res, |
- TerminateBrowserResult* default_res) { |
- UTIL_LOG(L3, (_T("[TerminateAllBrowsers][%d]"), type)); |
- ASSERT1(default_res); |
- ASSERT1(browser_res); |
- |
- if (type == BROWSER_UNKNOWN || |
- type == BROWSER_DEFAULT || |
- type >= BROWSER_MAX) { |
- ASSERT1(false); |
- return E_INVALIDARG; |
- } |
- |
- const BrowserType kFirstBrowser = BROWSER_IE; |
- const int kNumSupportedBrowsers = BROWSER_MAX - kFirstBrowser; |
- |
- BrowserType default_type = BROWSER_UNKNOWN; |
- HRESULT hr = GetDefaultBrowserType(&default_type); |
- if (FAILED(hr)) { |
- UTIL_LOG(LW, (_T("[GetDefaultBrowserType failed][0x%08x]"), hr)); |
- return hr; |
- } |
- |
- TerminateBrowserResult terminate_results[kNumSupportedBrowsers]; |
- |
- for (int browser = 0; browser < kNumSupportedBrowsers; ++browser) { |
- const BrowserType browser_type = |
- static_cast<BrowserType>(kFirstBrowser + browser); |
- hr = TerminateBrowserProcess(browser_type, |
- CString(), |
- 0, |
- &terminate_results[browser].found); |
- if (FAILED(hr)) { |
- UTIL_LOG(LW, (_T("[TerminateBrowserProcess failed][%u][0x%08x]"), |
- browser_type, hr)); |
- } |
- } |
- |
- // Now wait for the all browser instances to die. |
- // TODO(omaha): Wait for all processes at once rather than waiting for |
- // (kTerminateBrowserTimeoutMs * # supported browsers) ms. |
- for (int browser = 0; browser < kNumSupportedBrowsers; ++browser) { |
- const BrowserType browser_type = |
- static_cast<BrowserType>(kFirstBrowser + browser); |
- hr = WaitForBrowserToDie(browser_type, |
- CString(), |
- kTerminateBrowserTimeoutMs); |
- if (FAILED(hr)) { |
- UTIL_LOG(LW, (_T("[WaitForBrowserToDie failed][%u][0x%08x]"), |
- browser_type, hr)); |
- } else { |
- terminate_results[browser].could_terminate = true; |
- } |
- } |
- |
- *browser_res = terminate_results[type - kFirstBrowser]; |
- *default_res = terminate_results[default_type - kFirstBrowser]; |
- |
- return S_OK; |
-} |
- |
-// default_type can be BROWSER_UNKNOWN. |
-// If browsers that must be closed could not be terminated, false is returned. |
-// This method and TerminateBrowserProcesses assume the user did not shutdown |
-// the specified browser. They restart and shutdown, respectively, the default |
-// browser when the specified browser is not found. The reason for this may have |
-// been that the the specified (stamped) browser could be in a bad state on the |
-// machine and trying to start it would fail. |
-// This may also be required to support hosted cases (i.e. AOL and Maxthon). |
-// TODO(omaha): If we assume the stamped browser is okay, check whether the |
-// specified browser is installed rather than relying on whether the browser was |
-// running. It is perfectly valid for the browser to not be running. |
-// TODO(omaha): Why not try the default browser if browsers that require |
-// shutdown failed to terminate. |
-bool GetBrowserToRestart(BrowserType type, |
- BrowserType default_type, |
- const TerminateBrowserResult& res, |
- const TerminateBrowserResult& def_res, |
- BrowserType* browser_type) { |
- ASSERT1(browser_type); |
- ASSERT1(type != BROWSER_UNKNOWN && |
- type != BROWSER_DEFAULT && |
- type < BROWSER_MAX); |
- ASSERT1(default_type != BROWSER_DEFAULT && default_type < BROWSER_MAX); |
- UTIL_LOG(L3, (_T("[GetBrowserToRestart][%d]"), type)); |
- |
- *browser_type = BROWSER_UNKNOWN; |
- |
- if (res.found) { |
- switch (type) { |
- case BROWSER_IE: |
- *browser_type = BROWSER_IE; |
- return true; |
- case BROWSER_FIREFOX: // Only one process. |
- case BROWSER_CHROME: // One process per plug-in, even for upgrades. |
- if (res.could_terminate) { |
- *browser_type = type; |
- return true; |
- } |
- return false; |
- case BROWSER_UNKNOWN: |
- case BROWSER_DEFAULT: |
- case BROWSER_MAX: |
- default: |
- break; |
- } |
- } |
- |
- // We did not find the browser that we wanted to restart. Hence we need to |
- // determine if we could shutdown the default browser. |
- switch (default_type) { |
- case BROWSER_IE: |
- *browser_type = BROWSER_IE; |
- return true; |
- case BROWSER_FIREFOX: |
- case BROWSER_CHROME: |
- if (!def_res.found || def_res.found && def_res.could_terminate) { |
- *browser_type = default_type; |
- return true; |
- } |
- break; |
- case BROWSER_UNKNOWN: |
- case BROWSER_DEFAULT: |
- case BROWSER_MAX: |
- default: |
- break; |
- } |
- |
- return false; |
-} |
- |
-// See the comments about the default browser above GetBrowserToRestart. |
-HRESULT TerminateBrowserProcesses(BrowserType type, |
- TerminateBrowserResult* browser_res, |
- TerminateBrowserResult* default_res) { |
- UTIL_LOG(L3, (_T("[TerminateBrowserProcesses][%d]"), type)); |
- ASSERT1(browser_res); |
- ASSERT1(default_res); |
- |
- browser_res->could_terminate = false; |
- default_res->could_terminate = false; |
- |
- if (type == BROWSER_UNKNOWN || |
- type == BROWSER_DEFAULT || |
- type >= BROWSER_MAX) { |
- ASSERT1(false); |
- return E_UNEXPECTED; |
- } |
- |
- CString sid; |
- HRESULT hr = user_info::GetProcessUser(NULL, NULL, &sid); |
- if (FAILED(hr)) { |
- UTIL_LOG(LE, (_T("[GetProcessUser failed][0x%08x]"), hr)); |
- return hr; |
- } |
- |
- hr = TerminateBrowserProcess(type, |
- sid, |
- kTerminateBrowserTimeoutMs, |
- &browser_res->found); |
- if (FAILED(hr)) { |
- UTIL_LOG(LW, (_T("[TerminateBrowserProcess failed][0x%08x]"), hr)); |
- } else { |
- browser_res->could_terminate = true; |
- } |
- |
- // Since no instances of the browser type exist, we try to find and kill |
- // all instances of the default browser. |
- if (!browser_res->found) { |
- // We dont want to try and terminate the default browser, if it is the |
- // same as the browser that we tried above. |
- |
- BrowserType default_type = BROWSER_UNKNOWN; |
- hr = GetDefaultBrowserType(&default_type); |
- if (FAILED(hr)) { |
- UTIL_LOG(LW, (_T("[GetDefaultBrowserType failed][0x%08x]"), hr)); |
- } |
- |
- UTIL_LOG(L3, (_T("[Trying to kill the default browser %d]"), default_type)); |
- if (default_type != type) { |
- hr = TerminateBrowserProcess(BROWSER_DEFAULT, |
- sid, |
- kTerminateBrowserTimeoutMs, |
- &default_res->found); |
- if (FAILED(hr)) { |
- UTIL_LOG(LW, (_T("[TerminateBrowserProcess failed][0x%08x]"), hr)); |
- } else { |
- default_res->could_terminate = true; |
- } |
- } |
- } |
- |
- return hr; |
-} |
- |
-HRESULT GetBrowserImagePathFromProcess(BrowserType type, |
- uint32 explorer_pid, |
- CString* path) { |
- ASSERT1(path); |
- |
- if (type == BROWSER_UNKNOWN || type >= BROWSER_MAX) { |
- ASSERT1(false); |
- return E_UNEXPECTED; |
- } |
- |
- if (type == BROWSER_DEFAULT) { |
- return GetDefaultBrowserPath(path); |
- } |
- |
- CString user_sid; |
- HRESULT hr = Process::GetProcessOwner(explorer_pid, &user_sid); |
- if (FAILED(hr)) { |
- UTIL_LOG(LEVEL_WARNING, (_T("[GetProcessOwner failed.][0x%08x]"), hr)); |
- return hr; |
- } |
- |
- CString browser_name; |
- hr = BrowserTypeToProcessName(type, &browser_name); |
- if (FAILED(hr)) { |
- UTIL_LOG(LW, (_T("[BrowserTypeToProcessName failed.][0x%08x]"), hr)); |
- return hr; |
- } |
- |
- hr = Process::GetImagePath(browser_name, user_sid, path); |
- if (FAILED(hr)) { |
- UTIL_LOG(LW, (_T("[GetImagePath failed.][0x%08x]"), hr)); |
- return hr; |
- } |
- |
- return S_OK; |
-} |
- |
-HRESULT ConvertStringToBrowserType(const CString& text, BrowserType* type) { |
- ASSERT1(type != NULL); |
- |
- if (text.GetLength() != 1) { |
- return GOOPDATEUTILS_E_BROWSERTYPE; |
- } |
- |
- int browser_type = 0; |
- if (!String_StringToDecimalIntChecked(text, &browser_type)) { |
- return GOOPDATEUTILS_E_BROWSERTYPE; |
- } |
- |
- if (browser_type >= BROWSER_MAX) { |
- return GOOPDATEUTILS_E_BROWSERTYPE; |
- } |
- |
- *type = static_cast<BrowserType>(browser_type); |
- return S_OK; |
-} |
- |
-CString ConvertBrowserTypeToString(BrowserType type) { |
- CString text = itostr(static_cast<int>(type)); |
- ASSERT1(!text.IsEmpty()); |
- return text; |
-} |
- |
-HRESULT GetOSInfo(CString* os_version, CString* service_pack) { |
- ASSERT1(os_version); |
- ASSERT1(service_pack); |
- |
- OSVERSIONINFO os_version_info = { 0 }; |
- os_version_info.dwOSVersionInfoSize = sizeof(os_version_info); |
- if (!::GetVersionEx(&os_version_info)) { |
- HRESULT hr = HRESULTFromLastError(); |
- UTIL_LOG(LW, (_T("[GetVersionEx failed][0x%08x]"), hr)); |
- return hr; |
- } |
- |
- os_version->Format(_T("%d.%d"), |
- os_version_info.dwMajorVersion, |
- os_version_info.dwMinorVersion); |
- *service_pack = os_version_info.szCSDVersion; |
- return S_OK; |
-} |
- |
-CPath BuildInstallDirectory(bool is_machine, const CString& version) { |
- ConfigManager& cm = *ConfigManager::Instance(); |
- CPath install_dir(is_machine ? cm.GetMachineGoopdateInstallDir() : |
- cm.GetUserGoopdateInstallDir()); |
- VERIFY1(install_dir.Append(version)); |
- |
- return install_dir; |
-} |
- |
-// This method does a very specific job of searching for install workers, |
-// for the user and machine omaha. It also includes the on-demand updates COM |
-// server, because we treat it similar to interactive installs, and selfupdate. |
-// |
-// In machine case we search in all the accounts since the install worker can be |
-// running in any admin account and the machine update worker runs as SYSTEM. |
-// In the user case, we only search the user's account. |
-// In both cases, the Needsadmin command line parameter is checked for |
-// true/false in the machine/user case, respectively. |
-// |
-// Only adds processes to the input vector; does not clear it. |
-// |
-// TODO(omaha): For now we search for the needs_admin=true in the command |
-// line to determine a machine install. Another option of identifying omaha's |
-// is to use the presence of a named mutex. So the user omaha will create |
-// Global\<sid>\Mutex and the machine will create Global\Mutex, in here then |
-// we can test for the presence of the name to decide if an interactive |
-// omaha is running. |
-// TODO(omaha): Consider further filtering the processes based on whether |
-// the owner is elevated in case of machine omaha. |
-// Looks for the /ig command line used in Omaha 2. |
-HRESULT GetInstallWorkerProcesses(bool is_machine, |
- std::vector<uint32>* processes) { |
- ASSERT1(processes); |
- |
- CString user_sid; |
- DWORD flags = EXCLUDE_CURRENT_PROCESS | |
- EXCLUDE_PARENT_PROCESS | |
- INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING; |
- |
- std::vector<CString> command_lines; |
- CString command_line_to_include; |
- command_line_to_include.Format(_T("/%s"), kCmdLineInstall); |
- command_lines.push_back(command_line_to_include); |
- command_line_to_include.Format(_T("/%s"), kCmdLineInstallElevated); |
- command_lines.push_back(command_line_to_include); |
- command_line_to_include.Format(_T("/%s"), kCmdLineAppHandoffInstall); |
- command_lines.push_back(command_line_to_include); |
- command_line_to_include.Format(_T("/%s"), kCmdLineUpdate); |
- command_lines.push_back(command_line_to_include); |
- command_line_to_include.Format(_T("/%s"), |
- kCmdLineLegacyFinishGoogleUpdateInstall); |
- command_lines.push_back(command_line_to_include); |
- command_lines.push_back(kCmdLineComServerDash); |
- |
- if (!is_machine) { |
- // Search only the same sid as the current user. |
- flags |= INCLUDE_ONLY_PROCESS_OWNED_BY_USER; |
- |
- HRESULT hr = user_info::GetProcessUser(NULL, NULL, &user_sid); |
- if (FAILED(hr)) { |
- CORE_LOG(LE, (_T("[GetProcessUser failed][0x%08x]"), hr)); |
- return hr; |
- } |
- } |
- |
- std::vector<uint32> all_install_worker_processes; |
- HRESULT hr = Process::FindProcesses(flags, |
- kOmahaShellFileName, |
- true, |
- user_sid, |
- command_lines, |
- &all_install_worker_processes); |
- if (FAILED(hr)) { |
- CORE_LOG(LE, (_T("[FindProcesses failed][0x%08x]"), hr)); |
- return hr; |
- } |
- |
- CString official_path; |
- hr = GetFolderPath(is_machine ? CSIDL_PROGRAM_FILES : CSIDL_LOCAL_APPDATA, |
- &official_path); |
- ASSERT1(SUCCEEDED(hr)); |
- ASSERT1(!official_path.IsEmpty()); |
- |
- for (size_t i = 0; i < all_install_worker_processes.size(); ++i) { |
- CString cmd_line; |
- const uint32 process = all_install_worker_processes[i]; |
- if (SUCCEEDED(Process::GetCommandLine(process, &cmd_line))) { |
- cmd_line.MakeLower(); |
- // TODO(omaha): FindProcess method does not allow regex's to be specified |
- // along with the include command line. Change Process to allow this. |
- if (cmd_line.Find(is_machine ? kNeedsAdminYes : kNeedsAdminNo) != -1) { |
- CORE_LOG(L4, (_T("[Including process][%s]"), cmd_line)); |
- processes->push_back(process); |
- } |
- |
- // A needsadmin=prefers instance could be installing either for machine or |
- // for user. |
- if (cmd_line.Find(kNeedsAdminPrefers) != -1) { |
- CORE_LOG(L4, (_T("[Including process][%s]"), cmd_line)); |
- processes->push_back(process); |
- } |
- |
- // The -Embedding does not have a needsAdmin. Decide whether to include it |
- // if it matches the official path for the requested instance type. |
- CString exe_path; |
- if (cmd_line.Find(kCmdLineComServerDash) != -1 && |
- SUCCEEDED(GetExePathFromCommandLine(cmd_line, &exe_path)) && |
- String_StrNCmp(official_path, exe_path, official_path.GetLength(), |
- true) == 0) { |
- CORE_LOG(L4, (_T("[Including process][%s]"), cmd_line)); |
- processes->push_back(process); |
- } |
- } |
- } |
- |
- return S_OK; |
-} |
- |
-// The event name saved to the environment variable does not contain the |
-// decoration added by GetNamedObjectAttributes. |
-HRESULT CreateUniqueEventInEnvironment(const CString& var_name, |
- bool is_machine, |
- HANDLE* unique_event) { |
- ASSERT1(unique_event); |
- |
- GUID event_guid = GUID_NULL; |
- HRESULT hr = ::CoCreateGuid(&event_guid); |
- if (FAILED(hr)) { |
- CORE_LOG(LE, (_T("[::CoCreateGuid failed][0x%08x]"), hr)); |
- return hr; |
- } |
- |
- CString event_name(GuidToString(event_guid)); |
- NamedObjectAttributes attr; |
- GetNamedObjectAttributes(event_name, is_machine, &attr); |
- |
- hr = CreateEvent(&attr, unique_event); |
- if (FAILED(hr)) { |
- CORE_LOG(LW, (_T("[CreateEvent failed in CreateUniqueEventInEnvironment]"), |
- _T("[%s][0x%08x]"), var_name, hr)); |
- return hr; |
- } |
- |
- CORE_LOG(L3, (_T("[created unique event][%s][%s]"), var_name, event_name)); |
- |
- if (!::SetEnvironmentVariable(var_name, event_name)) { |
- DWORD error = ::GetLastError(); |
- CORE_LOG(LE, (_T("[::SetEnvironmentVariable failed][%d]"), error)); |
- return HRESULT_FROM_WIN32(error); |
- } |
- |
- return S_OK; |
-} |
- |
-HRESULT OpenUniqueEventFromEnvironment(const CString& var_name, |
- bool is_machine, |
- HANDLE* unique_event) { |
- ASSERT1(unique_event); |
- |
- TCHAR event_name[MAX_PATH] = {0}; |
- if (!::GetEnvironmentVariable(var_name, event_name, arraysize(event_name))) { |
- DWORD error = ::GetLastError(); |
- CORE_LOG(LW, (_T("[Failed to read environment variable][%s][%d]"), |
- var_name, error)); |
- return HRESULT_FROM_WIN32(error); |
- } |
- |
- CORE_LOG(L3, (_T("[read unique event][%s][%s]"), var_name, event_name)); |
- |
- NamedObjectAttributes attr; |
- GetNamedObjectAttributes(event_name, is_machine, &attr); |
- *unique_event = ::OpenEvent(EVENT_ALL_ACCESS, false, attr.name); |
- |
- if (!*unique_event) { |
- DWORD error = ::GetLastError(); |
- CORE_LOG(LW, (_T("[::OpenEvent failed][%s][%d]"), attr.name, error)); |
- return HRESULT_FROM_WIN32(error); |
- } |
- |
- return S_OK; |
-} |
- |
-// The caller is responsible for reseting the event and closing the handle. |
-HRESULT CreateEvent(NamedObjectAttributes* event_attr, HANDLE* event_handle) { |
- ASSERT1(event_handle); |
- ASSERT1(event_attr); |
- ASSERT1(!event_attr->name.IsEmpty()); |
- *event_handle = ::CreateEvent(&event_attr->sa, |
- true, // manual reset |
- false, // not signaled |
- event_attr->name); |
- |
- if (!*event_handle) { |
- DWORD error = ::GetLastError(); |
- CORE_LOG(LEVEL_ERROR, (_T("[::CreateEvent failed][%d]"), error)); |
- return HRESULT_FROM_WIN32(error); |
- } |
- |
- return S_OK; |
-} |
- |
-bool IsTestSource() { |
- return !ConfigManager::Instance()->GetTestSource().IsEmpty(); |
-} |
- |
-HRESULT ReadNameValuePairsFromFile(const CString& file_path, |
- const CString& group_name, |
- std::map<CString, CString>* pairs) { |
- ASSERT1(pairs); |
- |
- if (!File::Exists(file_path)) { |
- return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); |
- } |
- |
- pairs->clear(); |
- |
- TCHAR str_buf[32768] = {0}; |
- |
- // Retrieve all key names in the section requested. |
- DWORD buf_count = ::GetPrivateProfileString(group_name, |
- NULL, |
- NULL, |
- str_buf, |
- arraysize(str_buf), |
- file_path); |
- |
- DWORD offset = 0; |
- while (offset < buf_count) { |
- TCHAR val_buf[1024] = {0}; |
- CString current_key = &(str_buf[offset]); |
- DWORD val_count = ::GetPrivateProfileString(group_name, |
- current_key, |
- NULL, |
- val_buf, |
- arraysize(val_buf), |
- file_path); |
- (*pairs)[current_key] = val_buf; |
- offset += current_key.GetLength() + 1; |
- } |
- |
- return S_OK; |
-} |
- |
-HRESULT WriteNameValuePairsToFile(const CString& file_path, |
- const CString& group_name, |
- const std::map<CString, CString>& pairs) { |
- std::map<CString, CString>::const_iterator it = pairs.begin(); |
- for (; it != pairs.end(); ++it) { |
- if (!::WritePrivateProfileString(group_name, |
- it->first, |
- it->second, |
- file_path)) { |
- return HRESULTFromLastError(); |
- } |
- } |
- |
- return S_OK; |
-} |
- |
-bool IsAppInstallWorkerRunning(bool is_machine) { |
- CORE_LOG(L3, (_T("[IsAppInstallWorkerRunning][%d]"), is_machine)); |
- std::vector<uint32> processes; |
- VERIFY1(SUCCEEDED(GetInstallWorkerProcesses(is_machine, &processes))); |
- return !processes.empty(); |
-} |
- |
-// Returns true if the version does not begin with "1.0." or "1.1.". |
-bool IsGoogleUpdate2OrLater(const CString& version) { |
- const ULONGLONG kFirstOmaha2Version = MAKEDLLVERULL(1, 2, 0, 0); |
- ULONGLONG version_number = VersionFromString(version); |
- ASSERT1(0 != version_number); |
- |
- if (kFirstOmaha2Version <= version_number) { |
- return true; |
- } |
- |
- return false; |
-} |
- |
-HRESULT WriteInstallerDataToTempFile(const CString& installer_data, |
- CString* installer_data_file_path) { |
- ASSERT1(installer_data_file_path); |
- |
- // TODO(omaha): consider eliminating the special case and simply create an |
- // empty file. |
- CORE_LOG(L2, (_T("[WriteInstallerDataToTempFile][data=%s]"), installer_data)); |
- if (installer_data.IsEmpty()) { |
- return S_FALSE; |
- } |
- |
- CString temp_file; |
- if (!::GetTempFileName(app_util::GetTempDir(), |
- _T("gui"), |
- 0, |
- CStrBuf(temp_file, MAX_PATH))) { |
- HRESULT hr = HRESULTFromLastError(); |
- CORE_LOG(LE, (_T("[::GetTempFileName failed][0x08%x]"), hr)); |
- return hr; |
- } |
- |
- scoped_hfile file_handle(::CreateFile(temp_file, |
- GENERIC_WRITE, |
- FILE_SHARE_READ, |
- NULL, |
- CREATE_ALWAYS, |
- FILE_ATTRIBUTE_NORMAL, |
- NULL)); |
- if (!file_handle) { |
- HRESULT hr = HRESULTFromLastError(); |
- CORE_LOG(LE, (_T("[::CreateFile failed][0x08%x]"), hr)); |
- return hr; |
- } |
- |
- CStringA installer_data_utf8_bom; |
- SafeCStringAFormat(&installer_data_utf8_bom, "%c%c%c%s", |
- 0xEF, 0xBB, 0xBF, WideToUtf8(installer_data)); |
- |
- DWORD bytes_written = 0; |
- if (!::WriteFile(get(file_handle), |
- installer_data_utf8_bom, |
- installer_data_utf8_bom.GetLength(), |
- &bytes_written, |
- NULL)) { |
- HRESULT hr = HRESULTFromLastError(); |
- CORE_LOG(LE, (_T("[::WriteFile failed][0x08%x]"), hr)); |
- return hr; |
- } |
- |
- *installer_data_file_path = temp_file; |
- return S_OK; |
-} |
- |
-// Returns true if the absolute difference between time moments is greater than |
-// the interval between update checks. |
-// Deals with clocks rolling backwards, in scenarios where the clock indicates |
-// some time in the future, for example next year, last_checked_ is updated to |
-// reflect that time, and then the clock is adjusted back to present. |
-bool ShouldCheckForUpdates(bool is_machine) { |
- ConfigManager* cm = ConfigManager::Instance(); |
- bool is_period_overridden = false; |
- const int update_interval = cm->GetLastCheckPeriodSec(&is_period_overridden); |
- if (0 == update_interval) { |
- ASSERT1(is_period_overridden); |
- OPT_LOG(L1, (_T("[ShouldCheckForUpdates returned 0][checks disabled]"))); |
- return false; |
- } |
- |
- const int time_difference = cm->GetTimeSinceLastCheckedSec(is_machine); |
- |
- const bool result = time_difference >= update_interval ? true : false; |
- CORE_LOG(L3, (_T("[ShouldCheckForUpdates returned %d][%u]"), |
- result, is_period_overridden)); |
- return result; |
-} |
- |
-HRESULT UpdateLastChecked(bool is_machine) { |
- // Set the last check value to the current value. |
- DWORD now = Time64ToInt32(GetCurrent100NSTime()); |
- CORE_LOG(L3, (_T("[UpdateLastChecked][now %d]"), now)); |
- HRESULT hr = ConfigManager::Instance()->SetLastCheckedTime(is_machine, now); |
- if (FAILED(hr)) { |
- CORE_LOG(LE, (_T("[SetLastCheckedTime failed][0x%08x]"), hr)); |
- return hr; |
- } |
- return S_OK; |
-} |
- |
-HRESULT LaunchUninstallProcess(bool is_machine) { |
- CORE_LOG(L2, (_T("[LaunchUninstallProcess]"))); |
- CString exe_path = BuildGoogleUpdateExePath(is_machine); |
- CommandLineBuilder builder(COMMANDLINE_MODE_UNINSTALL); |
- CString cmd_line = builder.GetCommandLineArgs(); |
- return System::StartProcessWithArgs(exe_path, cmd_line); |
-} |
- |
-HANDLE GetImpersonationTokenForMachineProcess(bool is_machine) { |
- if (!is_machine) { |
- return NULL; |
- } |
- |
- CAccessToken access_token; |
- if (access_token.GetThreadToken(TOKEN_READ)) { |
- return NULL; |
- } |
- |
- bool is_local_system(false); |
- VERIFY1(SUCCEEDED(IsSystemProcess(&is_local_system))); |
- if (!is_local_system) { |
- return NULL; |
- } |
- |
- HANDLE handle = NULL; |
- HRESULT hr = vista::GetLoggedOnUserToken(&handle); |
- if (FAILED(hr)) { |
- UTIL_LOG(LE, (_T("[GetLoggedOnUserToken failed][0x%x]"), hr)); |
- return NULL; |
- } |
- |
- return handle; |
-} |
- |
-HRESULT EnableSEHOP(bool enable) { |
- CORE_LOG(L3, (_T("[EnableSEHOP][%d]"), enable)); |
- CString omaha_ifeo_key_path; |
- omaha_ifeo_key_path.Format(_T("%s\\%s"), |
- kRegKeyImageFileExecutionOptions, |
- kOmahaShellFileName); |
- return enable ? |
- RegKey::SetValue(omaha_ifeo_key_path, kRegKeyDisableSEHOPValue, |
- static_cast<DWORD>(0)) : |
- RegKey::DeleteValue(omaha_ifeo_key_path, kRegKeyDisableSEHOPValue); |
-} |
- |
-DEFINE_METRIC_count(opt_in_uid_generated); |
-HRESULT CreateUserId(bool is_machine) { |
- // Do not create user ID when doing OEM installation - to avoid a large |
- // number of machines have the same ID. |
- if (oem_install_utils::IsOemInstalling(is_machine)) { |
- return E_FAIL; |
- } |
- |
- GLock user_id_lock; |
- NamedObjectAttributes lock_attr; |
- GetNamedObjectAttributes(kOptUserIdLock, is_machine, &lock_attr); |
- if (!user_id_lock.InitializeWithSecAttr(lock_attr.name, &lock_attr.sa)) { |
- return E_FAIL; |
- } |
- |
- __mutexScope(user_id_lock); |
- RegKey update_key; |
- const ConfigManager& config_manager = *ConfigManager::Instance(); |
- HRESULT hr = update_key.Create(config_manager.registry_update(is_machine)); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- if (update_key.HasValue(kRegValueUserId)) { |
- return S_OK; |
- } |
- |
- CString user_id; |
- hr = GetGuid(&user_id); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- hr = update_key.SetValue(kRegValueUserId, user_id); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- ++metric_opt_in_uid_generated; |
- CORE_LOG(L3, (_T("[Create unique user ID: %s]"), user_id)); |
- return S_OK; |
-} |
- |
-void DeleteUserId(bool is_machine) { |
- RegKey::DeleteValue(ConfigManager::Instance()->registry_update(is_machine), |
- kRegValueUserId); |
-} |
- |
-CString GetUserIdLazyInit(bool is_machine) { |
- const ConfigManager& config_manager = *ConfigManager::Instance(); |
- if (oem_install_utils::IsOemInstalling(is_machine) || |
- !config_manager.CanCollectStats(is_machine)) { |
- DeleteUserId(is_machine); |
- return CString(); |
- } |
- |
- if (!RegKey::HasValue(config_manager.registry_update(is_machine), |
- kRegValueUserId)) { |
- VERIFY1(SUCCEEDED(CreateUserId(is_machine))); |
- } |
- |
- CString user_id; |
- RegKey::GetValue(config_manager.registry_update(is_machine), |
- kRegValueUserId, |
- &user_id); |
- return user_id; |
-} |
- |
-} // namespace goopdate_utils |
- |
-} // namespace omaha |