123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- // Copyright 2021 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "remoting/host/remote_open_url/url_forwarder_configurator_win.h"
- #include <windows.h>
- #include <wtsapi32.h>
- #include <memory>
- #include <string>
- #include "base/base_paths.h"
- #include "base/bind.h"
- #include "base/command_line.h"
- #include "base/files/file_path.h"
- #include "base/location.h"
- #include "base/logging.h"
- #include "base/notreached.h"
- #include "base/path_service.h"
- #include "base/process/launch.h"
- #include "base/sequence_checker.h"
- #include "base/task/task_traits.h"
- #include "base/task/thread_pool.h"
- #include "base/time/time.h"
- #include "base/win/scoped_handle.h"
- #include "base/win/windows_types.h"
- #include "remoting/base/logging.h"
- #include "remoting/host/base/switches.h"
- #include "remoting/host/win/wts_session_change_observer.h"
- namespace remoting {
- namespace {
- // If the user has already changed the default browser to the URL forwarder,
- // then the setup process will finish immediately without showing any UI, so we
- // delay reporting USER_INTERVENTION_REQUIRED so that the client doesn't pop up
- // a toast when it's unnecessary.
- constexpr base::TimeDelta kReportUserInterventionRequiredDelay =
- base::Milliseconds(500);
- base::win::ScopedHandle GetCurrentUserToken() {
- HANDLE user_token = nullptr;
- if (!WTSQueryUserToken(WTS_CURRENT_SESSION, &user_token)) {
- PLOG(ERROR) << "Failed to get current user token";
- return base::win::ScopedHandle();
- }
- return base::win::ScopedHandle(user_token);
- }
- // If |switch_name| is empty, the process will be launched with no extra
- // switches.
- bool LaunchConfiguratorProcess(const std::string& switch_name,
- base::win::ScopedHandle user_token) {
- DCHECK(user_token.IsValid());
- base::LaunchOptions launch_options;
- launch_options.as_user = user_token.Get();
- // The remoting_desktop.exe binary (where this code runs) has extra manifest
- // flags (uiAccess and requireAdministrator) that are undesirable for the
- // url_forwarder_configurator child process, so remoting_host.exe is used
- // instead.
- base::FilePath path;
- if (!base::PathService::Get(base::DIR_EXE, &path)) {
- LOG(ERROR) << "Failed to get executable path.";
- return false;
- }
- path = path.AppendASCII("remoting_host.exe");
- base::CommandLine command(path);
- command.AppendSwitchASCII(kProcessTypeSwitchName,
- kProcessTypeUrlForwarderConfigurator);
- if (!switch_name.empty()) {
- command.AppendSwitch(switch_name);
- }
- int exit_code = -1;
- base::LaunchProcess(command, launch_options).WaitForExit(&exit_code);
- return exit_code == 0;
- }
- } // namespace
- UrlForwarderConfiguratorWin::UrlForwarderConfiguratorWin()
- : io_task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
- {base::MayBlock(), base::WithBaseSyncPrimitives()})) {}
- UrlForwarderConfiguratorWin::~UrlForwarderConfiguratorWin() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- }
- void UrlForwarderConfiguratorWin::IsUrlForwarderSetUp(
- IsUrlForwarderSetUpCallback callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- auto user_token = GetCurrentUserToken();
- if (user_token.IsValid()) {
- io_task_runner_->PostTaskAndReplyWithResult(
- FROM_HERE,
- base::BindOnce(&LaunchConfiguratorProcess, std::string(),
- std::move(user_token)),
- std::move(callback));
- return;
- }
- if (GetLastError() != ERROR_NO_TOKEN) {
- std::move(callback).Run(false);
- return;
- }
- if (is_url_forwarder_set_up_callback_) {
- LOG(ERROR) << "Query is already in progress.";
- std::move(callback).Run(false);
- return;
- }
- DCHECK(!wts_session_change_observer_);
- HOST_LOG << "Can't determine URL Forwarder state as no user is signed in. "
- << "Will check again after user signs in.";
- is_url_forwarder_set_up_callback_ = std::move(callback);
- wts_session_change_observer_ = std::make_unique<WtsSessionChangeObserver>();
- bool start_success = wts_session_change_observer_->Start(
- base::BindRepeating(&UrlForwarderConfiguratorWin::OnWtsSessionChange,
- base::Unretained(this)));
- if (!start_success) {
- std::move(is_url_forwarder_set_up_callback_).Run(false);
- }
- }
- void UrlForwarderConfiguratorWin::SetUpUrlForwarder(
- const SetUpUrlForwarderCallback& callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (set_up_url_forwarder_callback_) {
- LOG(ERROR) << "Setup is already in progress.";
- callback.Run(SetUpUrlForwarderResponse::FAILED);
- return;
- }
- set_up_url_forwarder_callback_ = callback;
- report_user_intervention_required_timer_.Start(
- FROM_HERE, kReportUserInterventionRequiredDelay, this,
- &UrlForwarderConfiguratorWin::OnReportUserInterventionRequired);
- auto user_token = GetCurrentUserToken();
- if (!user_token.IsValid()) {
- OnSetUpResponse(false);
- return;
- }
- io_task_runner_->PostTaskAndReplyWithResult(
- FROM_HERE,
- base::BindOnce(&LaunchConfiguratorProcess, kSetUpUrlForwarderSwitchName,
- std::move(user_token)),
- base::BindOnce(&UrlForwarderConfiguratorWin::OnSetUpResponse,
- weak_factory_.GetWeakPtr()));
- }
- void UrlForwarderConfiguratorWin::OnSetUpResponse(bool success) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- report_user_intervention_required_timer_.AbandonAndStop();
- set_up_url_forwarder_callback_.Run(success
- ? SetUpUrlForwarderResponse::COMPLETE
- : SetUpUrlForwarderResponse::FAILED);
- set_up_url_forwarder_callback_.Reset();
- }
- void UrlForwarderConfiguratorWin::OnReportUserInterventionRequired() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- set_up_url_forwarder_callback_.Run(
- SetUpUrlForwarderResponse::USER_INTERVENTION_REQUIRED);
- }
- void UrlForwarderConfiguratorWin::OnWtsSessionChange(uint32_t event,
- uint32_t session_id) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (event != WTS_SESSION_LOGON) {
- return;
- }
- DCHECK(is_url_forwarder_set_up_callback_);
- HOST_LOG << "User logged in. Checking URL forwarder setup state now.";
- auto user_token = GetCurrentUserToken();
- if (!user_token.IsValid()) {
- std::move(is_url_forwarder_set_up_callback_).Run(false);
- return;
- }
- io_task_runner_->PostTaskAndReplyWithResult(
- FROM_HERE,
- base::BindOnce(&LaunchConfiguratorProcess, std::string(),
- std::move(user_token)),
- std::move(is_url_forwarder_set_up_callback_));
- wts_session_change_observer_.reset();
- }
- // static
- std::unique_ptr<UrlForwarderConfigurator> UrlForwarderConfigurator::Create() {
- return std::make_unique<UrlForwarderConfiguratorWin>();
- }
- } // namespace remoting
|