1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/google/google_update.h"
6
7 #include <atlbase.h>
8 #include <atlcom.h>
9
10 #include "base/file_path.h"
11 #include "base/message_loop.h"
12 #include "base/path_service.h"
13 #include "base/string_util.h"
14 #include "base/task.h"
15 #include "base/threading/thread.h"
16 #include "base/win/registry.h"
17 #include "base/win/scoped_comptr.h"
18 #include "base/win/windows_version.h"
19 #include "chrome/installer/util/browser_distribution.h"
20 #include "chrome/installer/util/google_update_constants.h"
21 #include "chrome/installer/util/helper.h"
22 #include "chrome/installer/util/install_util.h"
23 #include "content/browser/browser_thread.h"
24 #include "google_update_idl_i.c"
25 #include "views/window/window.h"
26
27 using views::Window;
28
29 namespace {
30
31 // The registry location of the Google Update policies.
32 const wchar_t kGUPolicyRegistrySubKey[] =
33 L"SOFTWARE\\Policies\\Google\\Update";
34 const wchar_t kGUPolicyGlobalValue[] = L"UpdateDefault";
35 const wchar_t kGUPolicyAppValuePrefix[] = L"Update";
36 const DWORD kGUPolicyUpdatesDisabled = 0;
37
38 // Checks if the updates have been disabled by policy.
IsUpdateDisabledByPolicy(const std::wstring & guid)39 bool IsUpdateDisabledByPolicy(const std::wstring& guid) {
40 #if !defined(GOOGLE_CHROME_BUILD)
41 return true;
42 #else
43 std::wstring value_name(kGUPolicyAppValuePrefix);
44 value_name.append(guid);
45 DWORD value = 0;
46 base::win::RegKey policy(HKEY_LOCAL_MACHINE,
47 kGUPolicyRegistrySubKey, KEY_READ);
48 // Per application settings override global setting.
49 if ((policy.ReadValueDW(value_name.c_str(), &value) == ERROR_SUCCESS) ||
50 (policy.ReadValueDW(kGUPolicyGlobalValue, &value) == ERROR_SUCCESS)) {
51 return value == kGUPolicyUpdatesDisabled;
52 }
53 return false;
54 #endif // defined(GOOGLE_CHROME_BUILD)
55 }
56
57 // Check if the currently running instance can be updated by Google Update.
58 // Returns true only if the instance running is a Google Chrome
59 // distribution installed in a standard location.
CanUpdateCurrentChrome(const std::wstring & chrome_exe_path)60 GoogleUpdateErrorCode CanUpdateCurrentChrome(
61 const std::wstring& chrome_exe_path) {
62 #if !defined(GOOGLE_CHROME_BUILD)
63 return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY;
64 #else
65 // TODO(tommi): Check if using the default distribution is always the right
66 // thing to do.
67 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
68 std::wstring user_exe_path =
69 installer::GetChromeInstallPath(false, dist).value();
70 std::wstring machine_exe_path =
71 installer::GetChromeInstallPath(true, dist).value();
72 std::transform(user_exe_path.begin(), user_exe_path.end(),
73 user_exe_path.begin(), tolower);
74 std::transform(machine_exe_path.begin(), machine_exe_path.end(),
75 machine_exe_path.begin(), tolower);
76 if (chrome_exe_path != user_exe_path &&
77 chrome_exe_path != machine_exe_path ) {
78 LOG(ERROR) << L"Google Update cannot update Chrome installed in a "
79 << L"non-standard location: " << chrome_exe_path.c_str()
80 << L". The standard location is: " << user_exe_path.c_str()
81 << L" or " << machine_exe_path.c_str() << L".";
82 return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY;
83 }
84
85 std::wstring app_guid = installer::GetAppGuidForUpdates(
86 !InstallUtil::IsPerUserInstall(chrome_exe_path.c_str()));
87 DCHECK(!app_guid.empty());
88
89 if (IsUpdateDisabledByPolicy(app_guid))
90 return GOOGLE_UPDATE_DISABLED_BY_POLICY;
91
92 return GOOGLE_UPDATE_NO_ERROR;
93 #endif
94 }
95
96 // Creates an instance of a COM Local Server class using either plain vanilla
97 // CoCreateInstance, or using the Elevation moniker if running on Vista.
98 // hwnd must refer to a foregound window in order to get the UAC prompt
99 // showing up in the foreground if running on Vista. It can also be NULL if
100 // background UAC prompts are desired.
CoCreateInstanceAsAdmin(REFCLSID class_id,REFIID interface_id,HWND hwnd,void ** interface_ptr)101 HRESULT CoCreateInstanceAsAdmin(REFCLSID class_id, REFIID interface_id,
102 HWND hwnd, void** interface_ptr) {
103 if (!interface_ptr)
104 return E_POINTER;
105
106 // For Vista we need to instantiate the COM server via the elevation
107 // moniker. This ensures that the UAC dialog shows up.
108 if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
109 wchar_t class_id_as_string[MAX_PATH] = {0};
110 StringFromGUID2(class_id, class_id_as_string,
111 arraysize(class_id_as_string));
112
113 std::wstring elevation_moniker_name =
114 StringPrintf(L"Elevation:Administrator!new:%ls", class_id_as_string);
115
116 BIND_OPTS3 bind_opts;
117 memset(&bind_opts, 0, sizeof(bind_opts));
118 bind_opts.cbStruct = sizeof(bind_opts);
119 bind_opts.dwClassContext = CLSCTX_LOCAL_SERVER;
120 bind_opts.hwnd = hwnd;
121
122 return CoGetObject(elevation_moniker_name.c_str(), &bind_opts,
123 interface_id, reinterpret_cast<void**>(interface_ptr));
124 }
125
126 return CoCreateInstance(class_id, NULL, CLSCTX_LOCAL_SERVER,
127 interface_id,
128 reinterpret_cast<void**>(interface_ptr));
129 }
130
131
132 } // namespace
133
134 ////////////////////////////////////////////////////////////////////////////////
135 //
136 // The GoogleUpdateJobObserver COM class is responsible for receiving status
137 // reports from google Update. It keeps track of the progress as Google Update
138 // notifies us and ends the message loop we are spinning in once Google Update
139 // reports that it is done.
140 //
141 ////////////////////////////////////////////////////////////////////////////////
142 class GoogleUpdateJobObserver
143 : public CComObjectRootEx<CComSingleThreadModel>,
144 public IJobObserver {
145 public:
146 BEGIN_COM_MAP(GoogleUpdateJobObserver)
COM_INTERFACE_ENTRY(IJobObserver)147 COM_INTERFACE_ENTRY(IJobObserver)
148 END_COM_MAP()
149
150 GoogleUpdateJobObserver()
151 : result_(UPGRADE_ERROR) {
152 }
~GoogleUpdateJobObserver()153 virtual ~GoogleUpdateJobObserver() {}
154
155 // Notifications from Google Update:
STDMETHOD(OnShow)156 STDMETHOD(OnShow)() {
157 return S_OK;
158 }
STDMETHOD(OnCheckingForUpdate)159 STDMETHOD(OnCheckingForUpdate)() {
160 result_ = UPGRADE_CHECK_STARTED;
161 return S_OK;
162 }
STDMETHOD(OnUpdateAvailable)163 STDMETHOD(OnUpdateAvailable)(const TCHAR* version_string) {
164 result_ = UPGRADE_IS_AVAILABLE;
165 new_version_ = version_string;
166 return S_OK;
167 }
STDMETHOD(OnWaitingToDownload)168 STDMETHOD(OnWaitingToDownload)() {
169 return S_OK;
170 }
STDMETHOD(OnDownloading)171 STDMETHOD(OnDownloading)(int time_remaining_ms, int pos) {
172 return S_OK;
173 }
STDMETHOD(OnWaitingToInstall)174 STDMETHOD(OnWaitingToInstall)() {
175 return S_OK;
176 }
STDMETHOD(OnInstalling)177 STDMETHOD(OnInstalling)() {
178 result_ = UPGRADE_STARTED;
179 return S_OK;
180 }
STDMETHOD(OnPause)181 STDMETHOD(OnPause)() {
182 return S_OK;
183 }
STDMETHOD(OnComplete)184 STDMETHOD(OnComplete)(CompletionCodes code, const TCHAR* text) {
185 switch (code) {
186 case COMPLETION_CODE_SUCCESS_CLOSE_UI:
187 case COMPLETION_CODE_SUCCESS: {
188 if (result_ == UPGRADE_STARTED)
189 result_ = UPGRADE_SUCCESSFUL;
190 else if (result_ == UPGRADE_CHECK_STARTED)
191 result_ = UPGRADE_ALREADY_UP_TO_DATE;
192 break;
193 }
194 default: {
195 NOTREACHED();
196 result_ = UPGRADE_ERROR;
197 break;
198 }
199 }
200
201 event_sink_ = NULL;
202
203 // We no longer need to spin the message loop that we started spinning in
204 // InitiateGoogleUpdateCheck.
205 MessageLoop::current()->Quit();
206 return S_OK;
207 }
STDMETHOD(SetEventSink)208 STDMETHOD(SetEventSink)(IProgressWndEvents* event_sink) {
209 event_sink_ = event_sink;
210 return S_OK;
211 }
212
213 // Returns the results of the update operation.
STDMETHOD(GetResult)214 STDMETHOD(GetResult)(GoogleUpdateUpgradeResult* result) {
215 // Intermediary steps should never be reported to the client.
216 DCHECK(result_ != UPGRADE_STARTED && result_ != UPGRADE_CHECK_STARTED);
217
218 *result = result_;
219 return S_OK;
220 }
221
222 // Returns which version Google Update found on the server (if a more
223 // recent version was found). Otherwise, this will be blank.
STDMETHOD(GetVersionInfo)224 STDMETHOD(GetVersionInfo)(std::wstring* version_string) {
225 *version_string = new_version_;
226 return S_OK;
227 }
228
229 private:
230 // The status/result of the Google Update operation.
231 GoogleUpdateUpgradeResult result_;
232
233 // The version string Google Update found.
234 std::wstring new_version_;
235
236 // Allows us control the upgrade process to a small degree. After OnComplete
237 // has been called, this object can not be used.
238 base::win::ScopedComPtr<IProgressWndEvents> event_sink_;
239 };
240
241 ////////////////////////////////////////////////////////////////////////////////
242 // GoogleUpdate, public:
243
GoogleUpdate()244 GoogleUpdate::GoogleUpdate()
245 : listener_(NULL) {
246 }
247
~GoogleUpdate()248 GoogleUpdate::~GoogleUpdate() {
249 }
250
251 ////////////////////////////////////////////////////////////////////////////////
252 // GoogleUpdate, views::DialogDelegate implementation:
253
CheckForUpdate(bool install_if_newer,Window * window)254 void GoogleUpdate::CheckForUpdate(bool install_if_newer, Window* window) {
255 // We need to shunt this request over to InitiateGoogleUpdateCheck and have
256 // it run in the file thread.
257 BrowserThread::PostTask(
258 BrowserThread::FILE, FROM_HERE,
259 NewRunnableMethod(
260 this, &GoogleUpdate::InitiateGoogleUpdateCheck, install_if_newer,
261 window, MessageLoop::current()));
262 }
263
264 ////////////////////////////////////////////////////////////////////////////////
265 // GoogleUpdate, private:
266
InitiateGoogleUpdateCheck(bool install_if_newer,Window * window,MessageLoop * main_loop)267 bool GoogleUpdate::InitiateGoogleUpdateCheck(bool install_if_newer,
268 Window* window,
269 MessageLoop* main_loop) {
270 FilePath chrome_exe_path;
271 if (!PathService::Get(base::DIR_EXE, &chrome_exe_path)) {
272 NOTREACHED();
273 return false;
274 }
275 std::wstring chrome_exe = chrome_exe_path.value();
276
277 std::transform(chrome_exe.begin(), chrome_exe.end(),
278 chrome_exe.begin(), tolower);
279
280 GoogleUpdateErrorCode error_code = CanUpdateCurrentChrome(chrome_exe);
281 if (error_code != GOOGLE_UPDATE_NO_ERROR) {
282 main_loop->PostTask(FROM_HERE, NewRunnableMethod(this,
283 &GoogleUpdate::ReportResults, UPGRADE_ERROR, error_code));
284 return false;
285 }
286
287 CComObject<GoogleUpdateJobObserver>* job_observer;
288 HRESULT hr =
289 CComObject<GoogleUpdateJobObserver>::CreateInstance(&job_observer);
290 if (hr != S_OK) {
291 return ReportFailure(hr, GOOGLE_UPDATE_JOB_SERVER_CREATION_FAILED,
292 main_loop);
293 }
294
295 base::win::ScopedComPtr<IJobObserver> job_holder(job_observer);
296
297 base::win::ScopedComPtr<IGoogleUpdate> on_demand;
298
299 bool system_level = false;
300
301 if (InstallUtil::IsPerUserInstall(chrome_exe.c_str())) {
302 hr = on_demand.CreateInstance(CLSID_OnDemandUserAppsClass);
303 } else {
304 // The Update operation needs Admin privileges for writing
305 // to %ProgramFiles%. On Vista we need to elevate before instantiating
306 // the updater instance.
307 if (!install_if_newer) {
308 hr = on_demand.CreateInstance(CLSID_OnDemandMachineAppsClass);
309 } else {
310 HWND foreground_hwnd = NULL;
311 if (window != NULL) {
312 foreground_hwnd = window->GetNativeWindow();
313 }
314
315 hr = CoCreateInstanceAsAdmin(CLSID_OnDemandMachineAppsClass,
316 IID_IGoogleUpdate, foreground_hwnd,
317 reinterpret_cast<void**>(on_demand.Receive()));
318 }
319 system_level = true;
320 }
321
322 if (hr != S_OK)
323 return ReportFailure(hr, GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND, main_loop);
324
325 std::wstring app_guid = installer::GetAppGuidForUpdates(system_level);
326 DCHECK(!app_guid.empty());
327
328 if (!install_if_newer)
329 hr = on_demand->CheckForUpdate(app_guid.c_str(), job_observer);
330 else
331 hr = on_demand->Update(app_guid.c_str(), job_observer);
332
333 if (hr != S_OK)
334 return ReportFailure(hr, GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR,
335 main_loop);
336
337 // We need to spin the message loop while Google Update is running so that it
338 // can report back to us through GoogleUpdateJobObserver. This message loop
339 // will terminate once Google Update sends us the completion status
340 // (success/error). See OnComplete().
341 MessageLoop::current()->Run();
342
343 GoogleUpdateUpgradeResult results;
344 hr = job_observer->GetResult(&results);
345 if (hr != S_OK)
346 return ReportFailure(hr, GOOGLE_UPDATE_GET_RESULT_CALL_FAILED, main_loop);
347
348 if (results == UPGRADE_ERROR)
349 return ReportFailure(hr, GOOGLE_UPDATE_ERROR_UPDATING, main_loop);
350
351 hr = job_observer->GetVersionInfo(&version_available_);
352 if (hr != S_OK)
353 return ReportFailure(hr, GOOGLE_UPDATE_GET_VERSION_INFO_FAILED, main_loop);
354
355 main_loop->PostTask(FROM_HERE, NewRunnableMethod(this,
356 &GoogleUpdate::ReportResults, results, GOOGLE_UPDATE_NO_ERROR));
357 job_holder = NULL;
358 on_demand = NULL;
359 return true;
360 }
361
ReportResults(GoogleUpdateUpgradeResult results,GoogleUpdateErrorCode error_code)362 void GoogleUpdate::ReportResults(GoogleUpdateUpgradeResult results,
363 GoogleUpdateErrorCode error_code) {
364 // If we get an error, then error code must not be blank, and vice versa.
365 DCHECK(results == UPGRADE_ERROR ? error_code != GOOGLE_UPDATE_NO_ERROR :
366 error_code == GOOGLE_UPDATE_NO_ERROR);
367 if (listener_)
368 listener_->OnReportResults(results, error_code, version_available_);
369 }
370
ReportFailure(HRESULT hr,GoogleUpdateErrorCode error_code,MessageLoop * main_loop)371 bool GoogleUpdate::ReportFailure(HRESULT hr, GoogleUpdateErrorCode error_code,
372 MessageLoop* main_loop) {
373 NOTREACHED() << "Communication with Google Update failed: " << hr
374 << " error: " << error_code;
375 main_loop->PostTask(FROM_HERE, NewRunnableMethod(this,
376 &GoogleUpdate::ReportResults, UPGRADE_ERROR, error_code));
377 return false;
378 }
379