Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "remoting/host/plugin/daemon_controller.h" | 5 #include "remoting/host/plugin/daemon_controller.h" |
| 6 | 6 |
| 7 #include <objbase.h> | 7 #include <objbase.h> |
| 8 | 8 |
| 9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/bind_helpers.h" | 11 #include "base/bind_helpers.h" |
| 12 #include "base/compiler_specific.h" | 12 #include "base/compiler_specific.h" |
| 13 #include "base/file_path.h" | 13 #include "base/file_path.h" |
| 14 #include "base/file_util.h" | 14 #include "base/file_util.h" |
| 15 #include "base/json/json_reader.h" | 15 #include "base/json/json_reader.h" |
| 16 #include "base/json/json_writer.h" | 16 #include "base/json/json_writer.h" |
| 17 #include "base/logging.h" | 17 #include "base/logging.h" |
| 18 #include "base/string16.h" | 18 #include "base/string16.h" |
| 19 #include "base/stringize_macros.h" | 19 #include "base/stringize_macros.h" |
| 20 #include "base/threading/thread.h" | 20 #include "base/threading/thread.h" |
| 21 #include "base/time.h" | 21 #include "base/time.h" |
| 22 #include "base/timer.h" | 22 #include "base/timer.h" |
| 23 #include "base/utf_string_conversions.h" | 23 #include "base/utf_string_conversions.h" |
| 24 #include "base/values.h" | 24 #include "base/values.h" |
| 25 #include "base/win/scoped_bstr.h" | 25 #include "base/win/scoped_bstr.h" |
| 26 #include "base/win/scoped_comptr.h" | 26 #include "base/win/scoped_comptr.h" |
| 27 #include "base/win/windows_version.h" | 27 #include "base/win/windows_version.h" |
| 28 #include "remoting/base/scoped_sc_handle_win.h" | 28 #include "remoting/base/scoped_sc_handle_win.h" |
| 29 #include "remoting/host/branding.h" | 29 #include "remoting/host/branding.h" |
| 30 #include "remoting/host/breakpad.h" | |
| 30 #include "remoting/host/plugin/daemon_installer_win.h" | 31 #include "remoting/host/plugin/daemon_installer_win.h" |
| 31 | 32 |
| 32 // MIDL-generated declarations and definitions. | 33 // MIDL-generated declarations and definitions. |
| 33 #include "remoting/host/elevated_controller.h" | 34 #include "remoting/host/elevated_controller.h" |
| 34 | 35 |
| 35 using base::win::ScopedBstr; | 36 using base::win::ScopedBstr; |
| 36 using base::win::ScopedComPtr; | 37 using base::win::ScopedComPtr; |
| 37 | 38 |
| 38 namespace remoting { | 39 namespace remoting { |
| 39 | 40 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 76 virtual State GetState() OVERRIDE; | 77 virtual State GetState() OVERRIDE; |
| 77 virtual void GetConfig(const GetConfigCallback& callback) OVERRIDE; | 78 virtual void GetConfig(const GetConfigCallback& callback) OVERRIDE; |
| 78 virtual void SetConfigAndStart( | 79 virtual void SetConfigAndStart( |
| 79 scoped_ptr<base::DictionaryValue> config, | 80 scoped_ptr<base::DictionaryValue> config, |
| 80 const CompletionCallback& done_callback) OVERRIDE; | 81 const CompletionCallback& done_callback) OVERRIDE; |
| 81 virtual void UpdateConfig(scoped_ptr<base::DictionaryValue> config, | 82 virtual void UpdateConfig(scoped_ptr<base::DictionaryValue> config, |
| 82 const CompletionCallback& done_callback) OVERRIDE; | 83 const CompletionCallback& done_callback) OVERRIDE; |
| 83 virtual void Stop(const CompletionCallback& done_callback) OVERRIDE; | 84 virtual void Stop(const CompletionCallback& done_callback) OVERRIDE; |
| 84 virtual void SetWindow(void* window_handle) OVERRIDE; | 85 virtual void SetWindow(void* window_handle) OVERRIDE; |
| 85 virtual void GetVersion(const GetVersionCallback& done_callback) OVERRIDE; | 86 virtual void GetVersion(const GetVersionCallback& done_callback) OVERRIDE; |
| 87 virtual void GetUsageStatsConsent( | |
| 88 const GetUsageStatsConsentCallback& done_callback) OVERRIDE; | |
| 89 virtual void SetUsageStatsConsent(bool consent) OVERRIDE; | |
| 86 | 90 |
| 87 private: | 91 private: |
| 88 // Activates an unprivileged instance of the daemon controller and caches it. | 92 // Activates an unprivileged instance of the daemon controller and caches it. |
| 89 HRESULT ActivateController(); | 93 HRESULT ActivateController(); |
| 90 | 94 |
| 91 // Activates an elevated instance of the daemon controller and caches it. | 95 // Activates an elevated instance of the daemon controller and caches it. |
| 92 HRESULT ActivateElevatedController(); | 96 HRESULT ActivateElevatedController(); |
| 93 | 97 |
| 94 // Releases the cached instance of the controller. | 98 // Releases the cached instance of the controller. |
| 95 void ReleaseController(); | 99 void ReleaseController(); |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 118 void DoGetConfig(const GetConfigCallback& callback); | 122 void DoGetConfig(const GetConfigCallback& callback); |
| 119 void DoInstallAsNeededAndStart(scoped_ptr<base::DictionaryValue> config, | 123 void DoInstallAsNeededAndStart(scoped_ptr<base::DictionaryValue> config, |
| 120 const CompletionCallback& done_callback); | 124 const CompletionCallback& done_callback); |
| 121 void DoSetConfigAndStart(scoped_ptr<base::DictionaryValue> config, | 125 void DoSetConfigAndStart(scoped_ptr<base::DictionaryValue> config, |
| 122 const CompletionCallback& done_callback); | 126 const CompletionCallback& done_callback); |
| 123 void DoUpdateConfig(scoped_ptr<base::DictionaryValue> config, | 127 void DoUpdateConfig(scoped_ptr<base::DictionaryValue> config, |
| 124 const CompletionCallback& done_callback); | 128 const CompletionCallback& done_callback); |
| 125 void DoStop(const CompletionCallback& done_callback); | 129 void DoStop(const CompletionCallback& done_callback); |
| 126 void DoSetWindow(void* window_handle); | 130 void DoSetWindow(void* window_handle); |
| 127 void DoGetVersion(const GetVersionCallback& callback); | 131 void DoGetVersion(const GetVersionCallback& callback); |
| 132 void DoGetUsageStatsConsent( | |
| 133 const GetUsageStatsConsentCallback& callback); | |
| 134 void DoSetUsageStatsConsent(bool consent); | |
| 128 | 135 |
| 129 // |control_| holds a reference to an instance of the daemon controller | 136 // |control_| and |control2_| hold references to an instance of the daemon |
| 130 // to prevent a UAC prompt on every operation. | 137 // controller to prevent a UAC prompt on every operation. |
| 131 ScopedComPtr<IDaemonControl> control_; | 138 ScopedComPtr<IDaemonControl> control_; |
| 139 ScopedComPtr<IDaemonControl2> control2_; | |
| 132 | 140 |
| 133 // True if |control_| holds a reference to an elevated instance of the daemon | 141 // True if |control_| holds a reference to an elevated instance of the daemon |
| 134 // controller. | 142 // controller. |
| 135 bool control_is_elevated_; | 143 bool control_is_elevated_; |
| 136 | 144 |
| 137 // This timer is used to release |control_| after a timeout. | 145 // This timer is used to release |control_| after a timeout. |
| 138 scoped_ptr<base::OneShotTimer<DaemonControllerWin> > release_timer_; | 146 scoped_ptr<base::OneShotTimer<DaemonControllerWin> > release_timer_; |
| 139 | 147 |
| 140 // Handle of the plugin window. | 148 // Handle of the plugin window. |
| 141 HWND window_handle_; | 149 HWND window_handle_; |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 251 window_handle)); | 259 window_handle)); |
| 252 } | 260 } |
| 253 | 261 |
| 254 void DaemonControllerWin::GetVersion(const GetVersionCallback& callback) { | 262 void DaemonControllerWin::GetVersion(const GetVersionCallback& callback) { |
| 255 worker_thread_.message_loop_proxy()->PostTask( | 263 worker_thread_.message_loop_proxy()->PostTask( |
| 256 FROM_HERE, | 264 FROM_HERE, |
| 257 base::Bind(&DaemonControllerWin::DoGetVersion, | 265 base::Bind(&DaemonControllerWin::DoGetVersion, |
| 258 base::Unretained(this), callback)); | 266 base::Unretained(this), callback)); |
| 259 } | 267 } |
| 260 | 268 |
| 269 void DaemonControllerWin::GetUsageStatsConsent( | |
| 270 const GetUsageStatsConsentCallback& callback) { | |
| 271 worker_thread_.message_loop_proxy()->PostTask( | |
| 272 FROM_HERE, | |
| 273 base::Bind(&DaemonControllerWin::DoGetUsageStatsConsent, | |
| 274 base::Unretained(this), callback)); | |
| 275 } | |
| 276 | |
| 277 void DaemonControllerWin::SetUsageStatsConsent(bool consent) { | |
| 278 worker_thread_.message_loop_proxy()->PostTask( | |
| 279 FROM_HERE, | |
| 280 base::Bind(&DaemonControllerWin::DoSetUsageStatsConsent, | |
| 281 base::Unretained(this), consent)); | |
| 282 } | |
| 283 | |
| 261 HRESULT DaemonControllerWin::ActivateController() { | 284 HRESULT DaemonControllerWin::ActivateController() { |
| 262 DCHECK(worker_thread_.message_loop_proxy()->BelongsToCurrentThread()); | 285 DCHECK(worker_thread_.message_loop_proxy()->BelongsToCurrentThread()); |
| 263 | 286 |
| 264 if (control_.get() == NULL) { | 287 if (control_.get() == NULL) { |
| 265 CLSID class_id; | 288 CLSID class_id; |
| 266 HRESULT hr = CLSIDFromProgID(kDaemonController, &class_id); | 289 HRESULT hr = CLSIDFromProgID(kDaemonController, &class_id); |
| 267 if (FAILED(hr)) { | 290 if (FAILED(hr)) { |
| 268 return hr; | 291 return hr; |
| 269 } | 292 } |
| 270 | 293 |
| 271 hr = CoCreateInstance(class_id, NULL, CLSCTX_LOCAL_SERVER, | 294 hr = CoCreateInstance(class_id, NULL, CLSCTX_LOCAL_SERVER, |
| 272 IID_IDaemonControl, control_.ReceiveVoid()); | 295 IID_IDaemonControl, control_.ReceiveVoid()); |
| 273 if (FAILED(hr)) { | 296 if (FAILED(hr)) { |
| 274 return hr; | 297 return hr; |
| 275 } | 298 } |
| 299 | |
| 300 // Ignore the error. IID_IDaemonControl2 is optional. | |
| 301 control_.QueryInterface(IID_IDaemonControl2, control2_.ReceiveVoid()); | |
| 276 } | 302 } |
| 277 | 303 |
| 278 return S_OK; | 304 return S_OK; |
| 279 } | 305 } |
| 280 | 306 |
| 281 HRESULT DaemonControllerWin::ActivateElevatedController() { | 307 HRESULT DaemonControllerWin::ActivateElevatedController() { |
| 282 DCHECK(worker_thread_.message_loop_proxy()->BelongsToCurrentThread()); | 308 DCHECK(worker_thread_.message_loop_proxy()->BelongsToCurrentThread()); |
| 283 | 309 |
| 284 // Release an unprivileged instance of the daemon controller if any. | 310 // Release an unprivileged instance of the daemon controller if any. |
| 285 if (!control_is_elevated_) { | 311 if (!control_is_elevated_) { |
| 286 ReleaseController(); | 312 ReleaseController(); |
| 287 } | 313 } |
| 288 | 314 |
| 289 if (control_.get() == NULL) { | 315 if (control_.get() == NULL) { |
| 290 BIND_OPTS3 bind_options; | 316 BIND_OPTS3 bind_options; |
| 291 memset(&bind_options, 0, sizeof(bind_options)); | 317 memset(&bind_options, 0, sizeof(bind_options)); |
| 292 bind_options.cbStruct = sizeof(bind_options); | 318 bind_options.cbStruct = sizeof(bind_options); |
| 293 bind_options.hwnd = GetTopLevelWindow(window_handle_); | 319 bind_options.hwnd = GetTopLevelWindow(window_handle_); |
| 294 bind_options.dwClassContext = CLSCTX_LOCAL_SERVER; | 320 bind_options.dwClassContext = CLSCTX_LOCAL_SERVER; |
| 295 | 321 |
| 296 HRESULT hr = ::CoGetObject( | 322 HRESULT hr = ::CoGetObject( |
| 297 kDaemonControllerElevationMoniker, | 323 kDaemonControllerElevationMoniker, |
| 298 &bind_options, | 324 &bind_options, |
| 299 IID_IDaemonControl, | 325 IID_IDaemonControl, |
| 300 control_.ReceiveVoid()); | 326 control_.ReceiveVoid()); |
| 301 if (FAILED(hr)) { | 327 if (FAILED(hr)) { |
| 302 return hr; | 328 return hr; |
| 303 } | 329 } |
| 304 | 330 |
| 331 // Ignore the error. IID_IDaemonControl2 is optional. | |
| 332 control_.QueryInterface(IID_IDaemonControl2, control2_.ReceiveVoid()); | |
|
Jamie
2012/06/14 23:43:56
Does this result in an elevated IDaemonControl2 in
alexeypa (please no reviews)
2012/06/19 23:27:29
Yes, but the UAC prompt has been shown to the user
Jamie
2012/06/21 18:47:52
My point is that if the code is designed to be run
alexeypa (please no reviews)
2012/06/21 23:30:25
The code was designed to be running as either non-
| |
| 333 | |
| 305 // Note that we hold a reference to an elevated instance now. | 334 // Note that we hold a reference to an elevated instance now. |
| 306 control_is_elevated_ = true; | 335 control_is_elevated_ = true; |
| 307 | 336 |
| 308 // Release |control_| upon expiration of the timeout. | 337 // Release |control_| upon expiration of the timeout. |
| 309 release_timer_.reset(new base::OneShotTimer<DaemonControllerWin>()); | 338 release_timer_.reset(new base::OneShotTimer<DaemonControllerWin>()); |
| 310 release_timer_->Start(FROM_HERE, | 339 release_timer_->Start(FROM_HERE, |
| 311 base::TimeDelta::FromSeconds(kUacTimeoutSec), | 340 base::TimeDelta::FromSeconds(kUacTimeoutSec), |
| 312 this, | 341 this, |
| 313 &DaemonControllerWin::ReleaseController); | 342 &DaemonControllerWin::ReleaseController); |
| 314 } | 343 } |
| 315 | 344 |
| 316 return S_OK; | 345 return S_OK; |
| 317 } | 346 } |
| 318 | 347 |
| 319 void DaemonControllerWin::ReleaseController() { | 348 void DaemonControllerWin::ReleaseController() { |
| 320 DCHECK(worker_thread_.message_loop_proxy()->BelongsToCurrentThread()); | 349 DCHECK(worker_thread_.message_loop_proxy()->BelongsToCurrentThread()); |
| 321 | 350 |
| 322 control_.Release(); | 351 control_.Release(); |
| 352 control2_.Release(); | |
| 323 release_timer_.reset(); | 353 release_timer_.reset(); |
| 324 control_is_elevated_ = false; | 354 control_is_elevated_ = false; |
| 325 } | 355 } |
| 326 | 356 |
| 327 void DaemonControllerWin::OnInstallationComplete( | 357 void DaemonControllerWin::OnInstallationComplete( |
| 328 scoped_ptr<base::DictionaryValue> config, | 358 scoped_ptr<base::DictionaryValue> config, |
| 329 const CompletionCallback& done_callback, | 359 const CompletionCallback& done_callback, |
| 330 HRESULT result) { | 360 HRESULT result) { |
| 331 DCHECK(worker_thread_.message_loop_proxy()->BelongsToCurrentThread()); | 361 DCHECK(worker_thread_.message_loop_proxy()->BelongsToCurrentThread()); |
| 332 | 362 |
| (...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 585 hr = control_->GetVersion(version.Receive()); | 615 hr = control_->GetVersion(version.Receive()); |
| 586 if (FAILED(hr)) { | 616 if (FAILED(hr)) { |
| 587 callback.Run(version_null); | 617 callback.Run(version_null); |
| 588 return; | 618 return; |
| 589 } | 619 } |
| 590 | 620 |
| 591 callback.Run(UTF16ToUTF8( | 621 callback.Run(UTF16ToUTF8( |
| 592 string16(static_cast<BSTR>(version), version.Length()))); | 622 string16(static_cast<BSTR>(version), version.Length()))); |
| 593 } | 623 } |
| 594 | 624 |
| 625 void DaemonControllerWin::DoGetUsageStatsConsent( | |
| 626 const GetUsageStatsConsentCallback& callback) { | |
| 627 DCHECK(worker_thread_.message_loop_proxy()->BelongsToCurrentThread()); | |
| 628 | |
| 629 // Activate the Daemon Controller and see if it supports |IDaemonControl2|. | |
| 630 HRESULT hr = ActivateController(); | |
| 631 if (FAILED(hr) || control2_.get() == NULL) { | |
| 632 callback.Run(false, false); | |
|
Jamie
2012/06/14 23:43:56
There should be a mechanism for reporting "not imp
alexeypa (please no reviews)
2012/06/19 23:27:29
Done.
| |
| 633 return; | |
| 634 } | |
| 635 | |
| 636 // Get the recorded user's consent. | |
| 637 BOOL set_by_policy; | |
| 638 BOOL allowed; | |
| 639 hr = control2_->GetUsageStatsConsent(&set_by_policy, &allowed); | |
| 640 if (FAILED(hr)) { | |
| 641 callback.Run(false, false); | |
| 642 return; | |
| 643 } | |
| 644 | |
| 645 callback.Run(!!set_by_policy, !!allowed); | |
| 646 } | |
| 647 | |
| 648 void DaemonControllerWin::DoSetUsageStatsConsent(bool consent) { | |
| 649 DCHECK(worker_thread_.message_loop_proxy()->BelongsToCurrentThread()); | |
| 650 | |
| 651 // Activate the Daemon Controller and see if it supports |IDaemonControl2|. | |
| 652 HRESULT hr = ActivateController(); | |
| 653 if (FAILED(hr) || control2_.get() == NULL) { | |
| 654 return; | |
|
Jamie
2012/06/14 23:43:56
It would be better to report failure to the caller
alexeypa (please no reviews)
2012/06/19 23:27:29
Done.
| |
| 655 } | |
| 656 | |
| 657 // Record the user's consent. | |
| 658 hr = control2_->SetUsageStatsConsent(consent); | |
| 659 if (FAILED(hr)) { | |
| 660 return; | |
| 661 } | |
| 662 } | |
| 663 | |
| 595 } // namespace | 664 } // namespace |
| 596 | 665 |
| 597 scoped_ptr<DaemonController> remoting::DaemonController::Create() { | 666 scoped_ptr<DaemonController> remoting::DaemonController::Create() { |
| 598 return scoped_ptr<DaemonController>(new DaemonControllerWin()); | 667 return scoped_ptr<DaemonController>(new DaemonControllerWin()); |
| 599 } | 668 } |
| 600 | 669 |
| 601 } // namespace remoting | 670 } // namespace remoting |
| OLD | NEW |