url_forwarder_configurator_win.cc 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. // Copyright 2021 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. #include "remoting/host/remote_open_url/url_forwarder_configurator_win.h"
  5. #include <windows.h>
  6. #include <wtsapi32.h>
  7. #include <memory>
  8. #include <string>
  9. #include "base/base_paths.h"
  10. #include "base/bind.h"
  11. #include "base/command_line.h"
  12. #include "base/files/file_path.h"
  13. #include "base/location.h"
  14. #include "base/logging.h"
  15. #include "base/notreached.h"
  16. #include "base/path_service.h"
  17. #include "base/process/launch.h"
  18. #include "base/sequence_checker.h"
  19. #include "base/task/task_traits.h"
  20. #include "base/task/thread_pool.h"
  21. #include "base/time/time.h"
  22. #include "base/win/scoped_handle.h"
  23. #include "base/win/windows_types.h"
  24. #include "remoting/base/logging.h"
  25. #include "remoting/host/base/switches.h"
  26. #include "remoting/host/win/wts_session_change_observer.h"
  27. namespace remoting {
  28. namespace {
  29. // If the user has already changed the default browser to the URL forwarder,
  30. // then the setup process will finish immediately without showing any UI, so we
  31. // delay reporting USER_INTERVENTION_REQUIRED so that the client doesn't pop up
  32. // a toast when it's unnecessary.
  33. constexpr base::TimeDelta kReportUserInterventionRequiredDelay =
  34. base::Milliseconds(500);
  35. base::win::ScopedHandle GetCurrentUserToken() {
  36. HANDLE user_token = nullptr;
  37. if (!WTSQueryUserToken(WTS_CURRENT_SESSION, &user_token)) {
  38. PLOG(ERROR) << "Failed to get current user token";
  39. return base::win::ScopedHandle();
  40. }
  41. return base::win::ScopedHandle(user_token);
  42. }
  43. // If |switch_name| is empty, the process will be launched with no extra
  44. // switches.
  45. bool LaunchConfiguratorProcess(const std::string& switch_name,
  46. base::win::ScopedHandle user_token) {
  47. DCHECK(user_token.IsValid());
  48. base::LaunchOptions launch_options;
  49. launch_options.as_user = user_token.Get();
  50. // The remoting_desktop.exe binary (where this code runs) has extra manifest
  51. // flags (uiAccess and requireAdministrator) that are undesirable for the
  52. // url_forwarder_configurator child process, so remoting_host.exe is used
  53. // instead.
  54. base::FilePath path;
  55. if (!base::PathService::Get(base::DIR_EXE, &path)) {
  56. LOG(ERROR) << "Failed to get executable path.";
  57. return false;
  58. }
  59. path = path.AppendASCII("remoting_host.exe");
  60. base::CommandLine command(path);
  61. command.AppendSwitchASCII(kProcessTypeSwitchName,
  62. kProcessTypeUrlForwarderConfigurator);
  63. if (!switch_name.empty()) {
  64. command.AppendSwitch(switch_name);
  65. }
  66. int exit_code = -1;
  67. base::LaunchProcess(command, launch_options).WaitForExit(&exit_code);
  68. return exit_code == 0;
  69. }
  70. } // namespace
  71. UrlForwarderConfiguratorWin::UrlForwarderConfiguratorWin()
  72. : io_task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
  73. {base::MayBlock(), base::WithBaseSyncPrimitives()})) {}
  74. UrlForwarderConfiguratorWin::~UrlForwarderConfiguratorWin() {
  75. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  76. }
  77. void UrlForwarderConfiguratorWin::IsUrlForwarderSetUp(
  78. IsUrlForwarderSetUpCallback callback) {
  79. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  80. auto user_token = GetCurrentUserToken();
  81. if (user_token.IsValid()) {
  82. io_task_runner_->PostTaskAndReplyWithResult(
  83. FROM_HERE,
  84. base::BindOnce(&LaunchConfiguratorProcess, std::string(),
  85. std::move(user_token)),
  86. std::move(callback));
  87. return;
  88. }
  89. if (GetLastError() != ERROR_NO_TOKEN) {
  90. std::move(callback).Run(false);
  91. return;
  92. }
  93. if (is_url_forwarder_set_up_callback_) {
  94. LOG(ERROR) << "Query is already in progress.";
  95. std::move(callback).Run(false);
  96. return;
  97. }
  98. DCHECK(!wts_session_change_observer_);
  99. HOST_LOG << "Can't determine URL Forwarder state as no user is signed in. "
  100. << "Will check again after user signs in.";
  101. is_url_forwarder_set_up_callback_ = std::move(callback);
  102. wts_session_change_observer_ = std::make_unique<WtsSessionChangeObserver>();
  103. bool start_success = wts_session_change_observer_->Start(
  104. base::BindRepeating(&UrlForwarderConfiguratorWin::OnWtsSessionChange,
  105. base::Unretained(this)));
  106. if (!start_success) {
  107. std::move(is_url_forwarder_set_up_callback_).Run(false);
  108. }
  109. }
  110. void UrlForwarderConfiguratorWin::SetUpUrlForwarder(
  111. const SetUpUrlForwarderCallback& callback) {
  112. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  113. if (set_up_url_forwarder_callback_) {
  114. LOG(ERROR) << "Setup is already in progress.";
  115. callback.Run(SetUpUrlForwarderResponse::FAILED);
  116. return;
  117. }
  118. set_up_url_forwarder_callback_ = callback;
  119. report_user_intervention_required_timer_.Start(
  120. FROM_HERE, kReportUserInterventionRequiredDelay, this,
  121. &UrlForwarderConfiguratorWin::OnReportUserInterventionRequired);
  122. auto user_token = GetCurrentUserToken();
  123. if (!user_token.IsValid()) {
  124. OnSetUpResponse(false);
  125. return;
  126. }
  127. io_task_runner_->PostTaskAndReplyWithResult(
  128. FROM_HERE,
  129. base::BindOnce(&LaunchConfiguratorProcess, kSetUpUrlForwarderSwitchName,
  130. std::move(user_token)),
  131. base::BindOnce(&UrlForwarderConfiguratorWin::OnSetUpResponse,
  132. weak_factory_.GetWeakPtr()));
  133. }
  134. void UrlForwarderConfiguratorWin::OnSetUpResponse(bool success) {
  135. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  136. report_user_intervention_required_timer_.AbandonAndStop();
  137. set_up_url_forwarder_callback_.Run(success
  138. ? SetUpUrlForwarderResponse::COMPLETE
  139. : SetUpUrlForwarderResponse::FAILED);
  140. set_up_url_forwarder_callback_.Reset();
  141. }
  142. void UrlForwarderConfiguratorWin::OnReportUserInterventionRequired() {
  143. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  144. set_up_url_forwarder_callback_.Run(
  145. SetUpUrlForwarderResponse::USER_INTERVENTION_REQUIRED);
  146. }
  147. void UrlForwarderConfiguratorWin::OnWtsSessionChange(uint32_t event,
  148. uint32_t session_id) {
  149. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  150. if (event != WTS_SESSION_LOGON) {
  151. return;
  152. }
  153. DCHECK(is_url_forwarder_set_up_callback_);
  154. HOST_LOG << "User logged in. Checking URL forwarder setup state now.";
  155. auto user_token = GetCurrentUserToken();
  156. if (!user_token.IsValid()) {
  157. std::move(is_url_forwarder_set_up_callback_).Run(false);
  158. return;
  159. }
  160. io_task_runner_->PostTaskAndReplyWithResult(
  161. FROM_HERE,
  162. base::BindOnce(&LaunchConfiguratorProcess, std::string(),
  163. std::move(user_token)),
  164. std::move(is_url_forwarder_set_up_callback_));
  165. wts_session_change_observer_.reset();
  166. }
  167. // static
  168. std::unique_ptr<UrlForwarderConfigurator> UrlForwarderConfigurator::Create() {
  169. return std::make_unique<UrlForwarderConfiguratorWin>();
  170. }
  171. } // namespace remoting