summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Thompson <grt@chromium.org>2015-06-24 16:15:39 -0400
committerGreg Thompson <grt@chromium.org>2015-06-24 20:17:20 +0000
commiteff749242c13f3778f8507ffd5e9e91160286eee (patch)
treec9d9ae41e5a88321bc2c2556532ec0da017ec6e6
parentfe876df32cbb1b90d18266673c95cb88978a93bc (diff)
downloadchromium_src-eff749242c13f3778f8507ffd5e9e91160286eee.zip
chromium_src-eff749242c13f3778f8507ffd5e9e91160286eee.tar.gz
chromium_src-eff749242c13f3778f8507ffd5e9e91160286eee.tar.bz2
Allow Google Update to impersonate the client for on-demand update checks.
This is a speculative fix for ERROR_BAD_IMPERSONATION_LEVEL (0x80070542) errors for system-level on-demand update checks. BUG=496313 R=ganesh@chromium.org, pkasting@chromium.org Review URL: https://codereview.chromium.org/1160273006 Cr-Commit-Position: refs/heads/master@{#334055} (cherry picked from commit f2546da00c199e0bd1205fad88c2c7b61d64430c) TBR=grt@chromium.org Review URL: https://codereview.chromium.org/1211643002. Cr-Commit-Position: refs/branch-heads/2403@{#394} Cr-Branched-From: f54b8097a9c45ed4ad308133d49f05325d6c5070-refs/heads/master@{#330231}
-rw-r--r--chrome/browser/google/google_update_win.cc90
1 files changed, 62 insertions, 28 deletions
diff --git a/chrome/browser/google/google_update_win.cc b/chrome/browser/google/google_update_win.cc
index 78630f1..a5c87f3 100644
--- a/chrome/browser/google/google_update_win.cc
+++ b/chrome/browser/google/google_update_win.cc
@@ -86,28 +86,43 @@ GoogleUpdateErrorCode CanUpdateCurrentChrome(
#endif
}
-// Creates an instance of a COM Local Server class using either plain vanilla
-// CoCreateInstance, or using the Elevation moniker if running on Vista.
-// hwnd must refer to a foregound window in order to get the UAC prompt
-// showing up in the foreground if running on Vista. It can also be NULL if
-// background UAC prompts are desired.
-HRESULT CoCreateInstanceAsAdmin(REFCLSID class_id,
+// Explicitly allow the Google Update service to impersonate the client since
+// some COM code elsewhere in the browser process may have previously used
+// CoInitializeSecurity to set the impersonation level to something other than
+// the default. Ignore errors since an attempt to use Google Update may succeed
+// regardless.
+void ConfigureProxyBlanket(IUnknown* interface_pointer) {
+ ::CoSetProxyBlanket(interface_pointer,
+ RPC_C_AUTHN_DEFAULT,
+ RPC_C_AUTHZ_DEFAULT,
+ COLE_DEFAULT_PRINCIPAL,
+ RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ nullptr,
+ EOAC_DYNAMIC_CLOAKING);
+}
+
+// Creates a class factory for a COM Local Server class using either plain
+// vanilla CoGetClassObject, or using the Elevation moniker if running on
+// Vista+. |hwnd| must refer to a foregound window in order to get the UAC
+// prompt to appear in the foreground if running on Vista+. It can also be NULL
+// if background UAC prompts are desired.
+HRESULT CoGetClassObjectAsAdmin(REFCLSID class_id,
REFIID interface_id,
gfx::AcceleratedWidget hwnd,
void** interface_ptr) {
if (!interface_ptr)
return E_POINTER;
- // For Vista, need to instantiate the COM server via the elevation
+ // For Vista+, need to instantiate the class factory via the elevation
// moniker. This ensures that the UAC dialog shows up.
if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
wchar_t class_id_as_string[MAX_PATH] = {};
StringFromGUID2(class_id, class_id_as_string,
arraysize(class_id_as_string));
- base::string16 elevation_moniker_name =
- base::StringPrintf(L"Elevation:Administrator!new:%ls",
- class_id_as_string);
+ base::string16 elevation_moniker_name = base::StringPrintf(
+ L"Elevation:Administrator!clsid:%ls", class_id_as_string);
BIND_OPTS3 bind_opts;
// An explicit memset is needed rather than relying on value initialization
@@ -117,12 +132,12 @@ HRESULT CoCreateInstanceAsAdmin(REFCLSID class_id,
bind_opts.dwClassContext = CLSCTX_LOCAL_SERVER;
bind_opts.hwnd = hwnd;
- return CoGetObject(elevation_moniker_name.c_str(), &bind_opts, interface_id,
- interface_ptr);
+ return ::CoGetObject(elevation_moniker_name.c_str(), &bind_opts,
+ interface_id, interface_ptr);
}
- return CoCreateInstance(class_id, NULL, CLSCTX_LOCAL_SERVER, interface_id,
- interface_ptr);
+ return ::CoGetClassObject(class_id, CLSCTX_LOCAL_SERVER, nullptr,
+ interface_id, interface_ptr);
}
HRESULT CreateGoogleUpdate3WebClass(
@@ -133,21 +148,35 @@ HRESULT CreateGoogleUpdate3WebClass(
if (g_google_update_factory)
return g_google_update_factory->Run(google_update);
+ const CLSID& google_update_clsid = system_level_install ?
+ CLSID_GoogleUpdate3WebMachineClass :
+ CLSID_GoogleUpdate3WebUserClass;
+ base::win::ScopedComPtr<IClassFactory> class_factory;
+ HRESULT hresult = S_OK;
+
// For a user-level install, update checks and updates can both be done by a
- // normal user with the UserClass.
- if (!system_level_install)
- return google_update->CreateInstance(CLSID_GoogleUpdate3WebUserClass);
-
- // For a system-level install, update checks can be done by a normal user with
- // the MachineClass.
- if (!install_update_if_possible)
- return google_update->CreateInstance(CLSID_GoogleUpdate3WebMachineClass);
-
- // For a system-level install, an update requires Admin privileges for writing
- // to %ProgramFiles%. Elevate while instantiating the MachineClass.
- return CoCreateInstanceAsAdmin(CLSID_GoogleUpdate3WebMachineClass,
- IID_IGoogleUpdate3Web, elevation_window,
- google_update->ReceiveVoid());
+ // normal user with the UserClass. For a system-level install, update checks
+ // can be done by a normal user with the MachineClass.
+ if (!system_level_install || !install_update_if_possible) {
+ hresult = ::CoGetClassObject(google_update_clsid, CLSCTX_ALL, nullptr,
+ base::win::ScopedComPtr<IClassFactory>::iid(),
+ class_factory.ReceiveVoid());
+ } else {
+ // For a system-level install, an update requires Admin privileges for
+ // writing to %ProgramFiles%. Elevate while instantiating the MachineClass.
+ hresult = CoGetClassObjectAsAdmin(
+ google_update_clsid, base::win::ScopedComPtr<IClassFactory>::iid(),
+ elevation_window, class_factory.ReceiveVoid());
+ }
+ if (FAILED(hresult))
+ return hresult;
+
+ ConfigureProxyBlanket(class_factory.get());
+
+ return class_factory->CreateInstance(
+ nullptr,
+ base::win::ScopedComPtr<IGoogleUpdate3Web>::iid(),
+ google_update->ReceiveVoid());
}
// UpdateCheckDriver -----------------------------------------------------------
@@ -399,6 +428,8 @@ HRESULT UpdateCheckDriver::BeginUpdateCheckInternal(
return hresult;
}
+ ConfigureProxyBlanket(google_update_.get());
+
// The class was created, so all subsequent errors are reported as:
*error_code = GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR;
base::string16 app_guid =
@@ -414,6 +445,7 @@ HRESULT UpdateCheckDriver::BeginUpdateCheckInternal(
if (FAILED(hresult))
return hresult;
}
+ ConfigureProxyBlanket(app_bundle_.get());
if (!locale_.empty()) {
// Ignore the result of this since, while setting the display language is
@@ -443,6 +475,7 @@ HRESULT UpdateCheckDriver::BeginUpdateCheckInternal(
hresult = dispatch.QueryInterface(app_.Receive());
if (FAILED(hresult))
return hresult;
+ ConfigureProxyBlanket(app_.get());
return app_bundle_->checkForUpdate();
}
@@ -457,6 +490,7 @@ bool UpdateCheckDriver::GetCurrentState(
*hresult = dispatch.QueryInterface(current_state->Receive());
if (FAILED(*hresult))
return false;
+ ConfigureProxyBlanket(current_state->get());
LONG value = 0;
*hresult = (*current_state)->get_stateValue(&value);
if (FAILED(*hresult))