• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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