daemon_process_win.cc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  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
  3. // found in the LICENSE file.
  4. #include "remoting/host/daemon_process.h"
  5. #include <stdint.h>
  6. #include <memory>
  7. #include <utility>
  8. #include <vector>
  9. #include "base/base_switches.h"
  10. #include "base/bind.h"
  11. #include "base/callback_helpers.h"
  12. #include "base/command_line.h"
  13. #include "base/location.h"
  14. #include "base/logging.h"
  15. #include "base/memory/ref_counted.h"
  16. #include "base/process/process.h"
  17. #include "base/strings/utf_string_conversions.h"
  18. #include "base/task/single_thread_task_runner.h"
  19. #include "base/time/time.h"
  20. #include "base/values.h"
  21. #include "base/win/registry.h"
  22. #include "base/win/scoped_handle.h"
  23. #include "base/win/win_util.h"
  24. #include "mojo/core/embedder/scoped_ipc_support.h"
  25. #include "mojo/public/cpp/bindings/associated_remote.h"
  26. #include "mojo/public/cpp/system/message_pipe.h"
  27. #include "remoting/base/auto_thread.h"
  28. #include "remoting/base/auto_thread_task_runner.h"
  29. #include "remoting/base/scoped_sc_handle_win.h"
  30. #include "remoting/host/base/host_exit_codes.h"
  31. #include "remoting/host/base/screen_resolution.h"
  32. #include "remoting/host/base/switches.h"
  33. #include "remoting/host/branding.h"
  34. #include "remoting/host/desktop_session_win.h"
  35. #include "remoting/host/host_config.h"
  36. #include "remoting/host/host_main.h"
  37. #include "remoting/host/ipc_constants.h"
  38. #include "remoting/host/mojom/remoting_host.mojom.h"
  39. #include "remoting/host/pairing_registry_delegate_win.h"
  40. #include "remoting/host/win/etw_trace_consumer.h"
  41. #include "remoting/host/win/host_event_file_logger.h"
  42. #include "remoting/host/win/host_event_windows_event_logger.h"
  43. #include "remoting/host/win/launch_process_with_token.h"
  44. #include "remoting/host/win/security_descriptor.h"
  45. #include "remoting/host/win/unprivileged_process_delegate.h"
  46. #include "remoting/host/win/worker_process_launcher.h"
  47. #include "third_party/abseil-cpp/absl/types/optional.h"
  48. using base::win::ScopedHandle;
  49. namespace {
  50. constexpr char kEtwTracingThreadName[] = "ETW Trace Consumer";
  51. // Duplicates |key| and returns a value that can be sent over IPC.
  52. base::win::ScopedHandle DuplicateRegistryKeyHandle(
  53. const base::win::RegKey& key) {
  54. HANDLE duplicate_handle = INVALID_HANDLE_VALUE;
  55. BOOL result = ::DuplicateHandle(::GetCurrentProcess(),
  56. reinterpret_cast<HANDLE>(key.Handle()),
  57. ::GetCurrentProcess(), &duplicate_handle, 0,
  58. FALSE, DUPLICATE_SAME_ACCESS);
  59. if (!result || duplicate_handle == INVALID_HANDLE_VALUE) {
  60. return base::win::ScopedHandle();
  61. }
  62. return base::win::ScopedHandle(duplicate_handle);
  63. }
  64. #if defined(OFFICIAL_BUILD)
  65. constexpr wchar_t kLoggingRegistryKeyName[] =
  66. L"SOFTWARE\\Google\\Chrome Remote Desktop\\logging";
  67. #else
  68. constexpr wchar_t kLoggingRegistryKeyName[] = L"SOFTWARE\\Chromoting\\logging";
  69. #endif
  70. constexpr wchar_t kLogToFileRegistryValue[] = L"LogToFile";
  71. constexpr wchar_t kLogToEventLogRegistryValue[] = L"LogToEventLog";
  72. } // namespace
  73. namespace remoting {
  74. class WtsTerminalMonitor;
  75. const char* kCopiedSwitchNames[] = {switches::kV, switches::kVModule};
  76. class DaemonProcessWin : public DaemonProcess {
  77. public:
  78. DaemonProcessWin(scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
  79. scoped_refptr<AutoThreadTaskRunner> io_task_runner,
  80. base::OnceClosure stopped_callback);
  81. DaemonProcessWin(const DaemonProcessWin&) = delete;
  82. DaemonProcessWin& operator=(const DaemonProcessWin&) = delete;
  83. ~DaemonProcessWin() override;
  84. // WorkerProcessIpcDelegate implementation.
  85. void OnChannelConnected(int32_t peer_pid) override;
  86. void OnPermanentError(int exit_code) override;
  87. void OnWorkerProcessStopped() override;
  88. // DaemonProcess overrides.
  89. bool OnDesktopSessionAgentAttached(
  90. int terminal_id,
  91. int session_id,
  92. mojo::ScopedMessagePipeHandle desktop_pipe) override;
  93. // If event logging has been configured, creates an ETW trace consumer which
  94. // listens for logged events from our host processes. Tracing stops when
  95. // |etw_trace_consumer_| is destroyed. Logging destinations are configured
  96. // via the registry.
  97. void ConfigureHostLogging();
  98. protected:
  99. // DaemonProcess implementation.
  100. std::unique_ptr<DesktopSession> DoCreateDesktopSession(
  101. int terminal_id,
  102. const ScreenResolution& resolution,
  103. bool virtual_terminal) override;
  104. void DoCrashNetworkProcess(const base::Location& location) override;
  105. void LaunchNetworkProcess() override;
  106. void SendHostConfigToNetworkProcess(
  107. const std::string& serialized_config) override;
  108. void SendTerminalDisconnected(int terminal_id) override;
  109. // Changes the service start type to 'manual'.
  110. void DisableAutoStart();
  111. // Initializes the pairing registry on the host side.
  112. bool InitializePairingRegistry();
  113. // Opens the pairing registry keys.
  114. bool OpenPairingRegistry();
  115. private:
  116. // Mojo keeps the task runner passed to it alive forever, so an
  117. // AutoThreadTaskRunner should not be passed to it. Otherwise, the process may
  118. // never shut down cleanly.
  119. mojo::core::ScopedIPCSupport ipc_support_;
  120. std::unique_ptr<WorkerProcessLauncher> network_launcher_;
  121. // Handle of the network process.
  122. ScopedHandle network_process_;
  123. base::win::RegKey pairing_registry_privileged_key_;
  124. base::win::RegKey pairing_registry_unprivileged_key_;
  125. std::unique_ptr<EtwTraceConsumer> etw_trace_consumer_;
  126. mojo::AssociatedRemote<mojom::DesktopSessionConnectionEvents>
  127. desktop_session_connection_events_;
  128. mojo::AssociatedRemote<mojom::RemotingHostControl> remoting_host_control_;
  129. };
  130. DaemonProcessWin::DaemonProcessWin(
  131. scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
  132. scoped_refptr<AutoThreadTaskRunner> io_task_runner,
  133. base::OnceClosure stopped_callback)
  134. : DaemonProcess(caller_task_runner,
  135. io_task_runner,
  136. std::move(stopped_callback)),
  137. ipc_support_(io_task_runner->task_runner(),
  138. mojo::core::ScopedIPCSupport::ShutdownPolicy::FAST) {}
  139. DaemonProcessWin::~DaemonProcessWin() = default;
  140. void DaemonProcessWin::OnChannelConnected(int32_t peer_pid) {
  141. // Obtain the handle of the network process.
  142. network_process_.Set(OpenProcess(PROCESS_DUP_HANDLE, false, peer_pid));
  143. if (!network_process_.IsValid()) {
  144. CrashNetworkProcess(FROM_HERE);
  145. return;
  146. }
  147. // Typically the Daemon process is responsible for disconnecting the remote
  148. // however in cases where the network process crashes, we want to ensure that
  149. // |remoting_host_control_| is reset so it can be reused after the network
  150. // process is relaunched.
  151. remoting_host_control_.reset();
  152. network_launcher_->GetRemoteAssociatedInterface(
  153. remoting_host_control_.BindNewEndpointAndPassReceiver());
  154. desktop_session_connection_events_.reset();
  155. network_launcher_->GetRemoteAssociatedInterface(
  156. desktop_session_connection_events_.BindNewEndpointAndPassReceiver());
  157. if (!InitializePairingRegistry()) {
  158. CrashNetworkProcess(FROM_HERE);
  159. return;
  160. }
  161. DaemonProcess::OnChannelConnected(peer_pid);
  162. }
  163. void DaemonProcessWin::OnPermanentError(int exit_code) {
  164. DCHECK(kMinPermanentErrorExitCode <= exit_code &&
  165. exit_code <= kMaxPermanentErrorExitCode);
  166. // Both kInvalidHostIdExitCode and kInvalidOauthCredentialsExitCode are
  167. // errors that will never go away with the current config.
  168. // Disabling automatic service start until the host is re-enabled and config
  169. // updated.
  170. if (exit_code == kInvalidHostIdExitCode ||
  171. exit_code == kInvalidOauthCredentialsExitCode) {
  172. DisableAutoStart();
  173. }
  174. DaemonProcess::OnPermanentError(exit_code);
  175. }
  176. void DaemonProcessWin::OnWorkerProcessStopped() {
  177. // Reset our IPC remote so it's ready to re-init if the network process is
  178. // re-launched.
  179. remoting_host_control_.reset();
  180. desktop_session_connection_events_.reset();
  181. DaemonProcess::OnWorkerProcessStopped();
  182. }
  183. bool DaemonProcessWin::OnDesktopSessionAgentAttached(
  184. int terminal_id,
  185. int session_id,
  186. mojo::ScopedMessagePipeHandle desktop_pipe) {
  187. if (desktop_session_connection_events_) {
  188. desktop_session_connection_events_->OnDesktopSessionAgentAttached(
  189. terminal_id, session_id, std::move(desktop_pipe));
  190. }
  191. return true;
  192. }
  193. std::unique_ptr<DesktopSession> DaemonProcessWin::DoCreateDesktopSession(
  194. int terminal_id,
  195. const ScreenResolution& resolution,
  196. bool virtual_terminal) {
  197. DCHECK(caller_task_runner()->BelongsToCurrentThread());
  198. if (virtual_terminal) {
  199. return DesktopSessionWin::CreateForVirtualTerminal(
  200. caller_task_runner(), io_task_runner(), this, terminal_id, resolution);
  201. } else {
  202. return DesktopSessionWin::CreateForConsole(
  203. caller_task_runner(), io_task_runner(), this, terminal_id, resolution);
  204. }
  205. }
  206. void DaemonProcessWin::DoCrashNetworkProcess(const base::Location& location) {
  207. DCHECK(caller_task_runner()->BelongsToCurrentThread());
  208. network_launcher_->Crash(location);
  209. }
  210. void DaemonProcessWin::LaunchNetworkProcess() {
  211. DCHECK(caller_task_runner()->BelongsToCurrentThread());
  212. DCHECK(!network_launcher_);
  213. // Construct the host binary name.
  214. base::FilePath host_binary;
  215. if (!GetInstalledBinaryPath(kHostBinaryName, &host_binary)) {
  216. Stop();
  217. return;
  218. }
  219. std::unique_ptr<base::CommandLine> target(new base::CommandLine(host_binary));
  220. target->AppendSwitchASCII(kProcessTypeSwitchName, kProcessTypeHost);
  221. target->CopySwitchesFrom(*base::CommandLine::ForCurrentProcess(),
  222. kCopiedSwitchNames, std::size(kCopiedSwitchNames));
  223. std::unique_ptr<UnprivilegedProcessDelegate> delegate(
  224. new UnprivilegedProcessDelegate(io_task_runner(), std::move(target)));
  225. network_launcher_ =
  226. std::make_unique<WorkerProcessLauncher>(std::move(delegate), this);
  227. }
  228. void DaemonProcessWin::SendHostConfigToNetworkProcess(
  229. const std::string& serialized_config) {
  230. if (!remoting_host_control_) {
  231. return;
  232. }
  233. LOG_IF(ERROR, !remoting_host_control_.is_connected())
  234. << "IPC channel not connected. HostConfig message will be dropped.";
  235. absl::optional<base::Value> config(HostConfigFromJson(serialized_config));
  236. if (!config.has_value()) {
  237. LOG(ERROR) << "Invalid host config, shutting down.";
  238. OnPermanentError(kInvalidHostConfigurationExitCode);
  239. return;
  240. }
  241. remoting_host_control_->ApplyHostConfig(std::move(config.value()));
  242. }
  243. void DaemonProcessWin::SendTerminalDisconnected(int terminal_id) {
  244. if (desktop_session_connection_events_) {
  245. desktop_session_connection_events_->OnTerminalDisconnected(terminal_id);
  246. }
  247. }
  248. std::unique_ptr<DaemonProcess> DaemonProcess::Create(
  249. scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
  250. scoped_refptr<AutoThreadTaskRunner> io_task_runner,
  251. base::OnceClosure stopped_callback) {
  252. auto daemon_process = std::make_unique<DaemonProcessWin>(
  253. caller_task_runner, io_task_runner, std::move(stopped_callback));
  254. // Configure host logging first so we can capture subsequent events.
  255. daemon_process->ConfigureHostLogging();
  256. daemon_process->Initialize();
  257. return std::move(daemon_process);
  258. }
  259. void DaemonProcessWin::DisableAutoStart() {
  260. ScopedScHandle scmanager(
  261. OpenSCManager(nullptr, SERVICES_ACTIVE_DATABASE,
  262. SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE));
  263. if (!scmanager.IsValid()) {
  264. PLOG(INFO) << "Failed to connect to the service control manager";
  265. return;
  266. }
  267. DWORD desired_access = SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS;
  268. ScopedScHandle service(
  269. OpenService(scmanager.Get(), kWindowsServiceName, desired_access));
  270. if (!service.IsValid()) {
  271. PLOG(INFO) << "Failed to open to the '" << kWindowsServiceName
  272. << "' service";
  273. return;
  274. }
  275. // Change the service start type to 'manual'. All |nullptr| parameters below
  276. // mean that there is no change to the corresponding service parameter.
  277. if (!ChangeServiceConfig(service.Get(),
  278. SERVICE_NO_CHANGE,
  279. SERVICE_DEMAND_START,
  280. SERVICE_NO_CHANGE,
  281. nullptr,
  282. nullptr,
  283. nullptr,
  284. nullptr,
  285. nullptr,
  286. nullptr,
  287. nullptr)) {
  288. PLOG(INFO) << "Failed to change the '" << kWindowsServiceName
  289. << "'service start type to 'manual'";
  290. }
  291. }
  292. bool DaemonProcessWin::InitializePairingRegistry() {
  293. if (!pairing_registry_privileged_key_.Valid()) {
  294. if (!OpenPairingRegistry())
  295. return false;
  296. }
  297. // Initialize the pairing registry in the network process. This has to be done
  298. // before the host configuration is sent, otherwise the host will not use
  299. // the passed handles.
  300. // Duplicate handles for the network process.
  301. base::win::ScopedHandle privileged_key =
  302. DuplicateRegistryKeyHandle(pairing_registry_privileged_key_);
  303. base::win::ScopedHandle unprivileged_key =
  304. DuplicateRegistryKeyHandle(pairing_registry_unprivileged_key_);
  305. if (!(privileged_key.IsValid() && unprivileged_key.IsValid()))
  306. return false;
  307. if (!remoting_host_control_)
  308. return false;
  309. remoting_host_control_->InitializePairingRegistry(
  310. mojo::PlatformHandle(std::move(privileged_key)),
  311. mojo::PlatformHandle(std::move(unprivileged_key)));
  312. return true;
  313. }
  314. // A chromoting top crasher revealed that the pairing registry keys sometimes
  315. // cannot be opened. The speculation is that those keys are absent for some
  316. // reason. To reduce the host crashes we create those keys here if they are
  317. // absent. See crbug.com/379360 for details.
  318. bool DaemonProcessWin::OpenPairingRegistry() {
  319. DCHECK(!pairing_registry_privileged_key_.Valid());
  320. DCHECK(!pairing_registry_unprivileged_key_.Valid());
  321. // Open the root of the pairing registry. Create if absent.
  322. base::win::RegKey root;
  323. DWORD disposition;
  324. LONG result = root.CreateWithDisposition(
  325. HKEY_LOCAL_MACHINE, kPairingRegistryKeyName, &disposition,
  326. KEY_READ | KEY_CREATE_SUB_KEY);
  327. if (result != ERROR_SUCCESS) {
  328. ::SetLastError(result);
  329. PLOG(ERROR) << "Failed to open or create HKLM\\" << kPairingRegistryKeyName;
  330. return false;
  331. }
  332. if (disposition == REG_CREATED_NEW_KEY)
  333. LOG(WARNING) << "Created pairing registry root key which was absent.";
  334. // Open the pairing registry clients key. Create if absent.
  335. base::win::RegKey unprivileged;
  336. result = unprivileged.CreateWithDisposition(
  337. root.Handle(), kPairingRegistryClientsKeyName, &disposition,
  338. KEY_READ | KEY_WRITE);
  339. if (result != ERROR_SUCCESS) {
  340. ::SetLastError(result);
  341. PLOG(ERROR) << "Failed to open or create HKLM\\" << kPairingRegistryKeyName
  342. << "\\" << kPairingRegistryClientsKeyName;
  343. return false;
  344. }
  345. if (disposition == REG_CREATED_NEW_KEY)
  346. LOG(WARNING) << "Created pairing registry client key which was absent.";
  347. // Open the pairing registry secret key.
  348. base::win::RegKey privileged;
  349. result = privileged.Open(
  350. root.Handle(), kPairingRegistrySecretsKeyName, KEY_READ | KEY_WRITE);
  351. if (result == ERROR_FILE_NOT_FOUND) {
  352. LOG(WARNING) << "Pairing registry privileged key absent, creating.";
  353. // Create a security descriptor that gives full access to local system and
  354. // administrators and denies access by anyone else.
  355. std::string security_descriptor = "O:BAG:BAD:(A;;GA;;;BA)(A;;GA;;;SY)";
  356. ScopedSd sd = ConvertSddlToSd(security_descriptor);
  357. if (!sd) {
  358. PLOG(ERROR) << "Failed to create a security descriptor for the pairing"
  359. << "registry privileged key.";
  360. return false;
  361. }
  362. SECURITY_ATTRIBUTES security_attributes = {0};
  363. security_attributes.nLength = sizeof(security_attributes);
  364. security_attributes.lpSecurityDescriptor = sd.get();
  365. security_attributes.bInheritHandle = FALSE;
  366. HKEY key = nullptr;
  367. result = ::RegCreateKeyEx(
  368. root.Handle(), kPairingRegistrySecretsKeyName, 0, nullptr, 0,
  369. KEY_READ | KEY_WRITE, &security_attributes, &key, &disposition);
  370. privileged.Set(key);
  371. }
  372. if (result != ERROR_SUCCESS) {
  373. ::SetLastError(result);
  374. PLOG(ERROR) << "Failed to open or create HKLM\\" << kPairingRegistryKeyName
  375. << "\\" << kPairingRegistrySecretsKeyName;
  376. return false;
  377. }
  378. pairing_registry_privileged_key_.Set(privileged.Take());
  379. pairing_registry_unprivileged_key_.Set(unprivileged.Take());
  380. return true;
  381. }
  382. void DaemonProcessWin::ConfigureHostLogging() {
  383. DCHECK(!etw_trace_consumer_);
  384. base::win::RegKey logging_reg_key;
  385. LONG result = logging_reg_key.Open(HKEY_LOCAL_MACHINE,
  386. kLoggingRegistryKeyName, KEY_READ);
  387. if (result != ERROR_SUCCESS) {
  388. ::SetLastError(result);
  389. PLOG(ERROR) << "Failed to open HKLM\\" << kLoggingRegistryKeyName;
  390. return;
  391. }
  392. std::vector<std::unique_ptr<HostEventLogger>> loggers;
  393. // Check to see if file logging has been enabled.
  394. if (logging_reg_key.HasValue(kLogToFileRegistryValue)) {
  395. DWORD enabled = 0;
  396. result = logging_reg_key.ReadValueDW(kLogToFileRegistryValue, &enabled);
  397. if (result != ERROR_SUCCESS) {
  398. ::SetLastError(result);
  399. PLOG(ERROR) << "Failed to read HKLM\\" << kLoggingRegistryKeyName << "\\"
  400. << kLogToFileRegistryValue;
  401. } else if (enabled) {
  402. auto file_logger = HostEventFileLogger::Create();
  403. if (file_logger) {
  404. loggers.push_back(std::move(file_logger));
  405. }
  406. }
  407. }
  408. // Check to see if Windows event logging has been enabled.
  409. if (logging_reg_key.HasValue(kLogToEventLogRegistryValue)) {
  410. DWORD enabled = 0;
  411. result = logging_reg_key.ReadValueDW(kLogToEventLogRegistryValue, &enabled);
  412. if (result != ERROR_SUCCESS) {
  413. ::SetLastError(result);
  414. PLOG(ERROR) << "Failed to read HKLM\\" << kLoggingRegistryKeyName << "\\"
  415. << kLogToEventLogRegistryValue;
  416. } else if (enabled) {
  417. auto event_logger = HostEventWindowsEventLogger::Create();
  418. if (event_logger) {
  419. loggers.push_back(std::move(event_logger));
  420. }
  421. }
  422. }
  423. if (loggers.empty()) {
  424. VLOG(1) << "No host event loggers have been configured.";
  425. return;
  426. }
  427. etw_trace_consumer_ = EtwTraceConsumer::Create(
  428. AutoThread::CreateWithType(kEtwTracingThreadName, caller_task_runner(),
  429. base::MessagePumpType::IO),
  430. std::move(loggers));
  431. }
  432. } // namespace remoting