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
27using views::Window;
28
29namespace {
30
31// The registry location of the Google Update policies.
32const wchar_t kGUPolicyRegistrySubKey[] =
33    L"SOFTWARE\\Policies\\Google\\Update";
34const wchar_t kGUPolicyGlobalValue[] = L"UpdateDefault";
35const wchar_t kGUPolicyAppValuePrefix[] = L"Update";
36const DWORD kGUPolicyUpdatesDisabled = 0;
37
38// Checks if the updates have been disabled by policy.
39bool 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.
60GoogleUpdateErrorCode 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.
101HRESULT 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////////////////////////////////////////////////////////////////////////////////
142class GoogleUpdateJobObserver
143  : public CComObjectRootEx<CComSingleThreadModel>,
144    public IJobObserver {
145 public:
146  BEGIN_COM_MAP(GoogleUpdateJobObserver)
147    COM_INTERFACE_ENTRY(IJobObserver)
148  END_COM_MAP()
149
150  GoogleUpdateJobObserver()
151    : result_(UPGRADE_ERROR) {
152  }
153  virtual ~GoogleUpdateJobObserver() {}
154
155  // Notifications from Google Update:
156  STDMETHOD(OnShow)() {
157    return S_OK;
158  }
159  STDMETHOD(OnCheckingForUpdate)() {
160    result_ = UPGRADE_CHECK_STARTED;
161    return S_OK;
162  }
163  STDMETHOD(OnUpdateAvailable)(const TCHAR* version_string) {
164    result_ = UPGRADE_IS_AVAILABLE;
165    new_version_ = version_string;
166    return S_OK;
167  }
168  STDMETHOD(OnWaitingToDownload)() {
169    return S_OK;
170  }
171  STDMETHOD(OnDownloading)(int time_remaining_ms, int pos) {
172    return S_OK;
173  }
174  STDMETHOD(OnWaitingToInstall)() {
175    return S_OK;
176  }
177  STDMETHOD(OnInstalling)() {
178    result_ = UPGRADE_STARTED;
179    return S_OK;
180  }
181  STDMETHOD(OnPause)() {
182    return S_OK;
183  }
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  }
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.
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.
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
244GoogleUpdate::GoogleUpdate()
245    : listener_(NULL) {
246}
247
248GoogleUpdate::~GoogleUpdate() {
249}
250
251////////////////////////////////////////////////////////////////////////////////
252// GoogleUpdate, views::DialogDelegate implementation:
253
254void 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
267bool 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
362void 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
371bool 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