Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / remoting / host / daemon_process_win.cc
bloba67a8dba881db02e1fcee549009a0109655f9c5c
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.
5 #include "remoting/host/daemon_process.h"
7 #include "base/base_switches.h"
8 #include "base/bind.h"
9 #include "base/bind_helpers.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/process/process.h"
15 #include "base/single_thread_task_runner.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/time/time.h"
18 #include "base/timer/timer.h"
19 #include "base/win/registry.h"
20 #include "base/win/scoped_handle.h"
21 #include "ipc/ipc_message.h"
22 #include "ipc/ipc_message_macros.h"
23 #include "remoting/base/auto_thread_task_runner.h"
24 #include "remoting/base/scoped_sc_handle_win.h"
25 #include "remoting/host/branding.h"
26 #include "remoting/host/chromoting_messages.h"
27 #include "remoting/host/desktop_session_win.h"
28 #include "remoting/host/host_exit_codes.h"
29 #include "remoting/host/host_main.h"
30 #include "remoting/host/ipc_constants.h"
31 #include "remoting/host/pairing_registry_delegate_win.h"
32 #include "remoting/host/screen_resolution.h"
33 #include "remoting/host/win/launch_process_with_token.h"
34 #include "remoting/host/win/unprivileged_process_delegate.h"
35 #include "remoting/host/win/worker_process_launcher.h"
37 using base::win::ScopedHandle;
38 using base::TimeDelta;
40 namespace {
42 // Duplicates |key| into |target_process| and returns the value that can be sent
43 // over IPC.
44 IPC::PlatformFileForTransit GetRegistryKeyForTransit(
45 base::ProcessHandle target_process,
46 const base::win::RegKey& key) {
47 base::PlatformFile handle =
48 reinterpret_cast<base::PlatformFile>(key.Handle());
49 return IPC::GetFileHandleForProcess(handle, target_process, false);
52 } // namespace
54 namespace remoting {
56 class WtsTerminalMonitor;
58 // The command line parameters that should be copied from the service's command
59 // line to the host process.
60 const char kEnableVp9SwitchName[] = "enable-vp9";
61 const char* kCopiedSwitchNames[] =
62 { switches::kV, switches::kVModule, kEnableVp9SwitchName };
64 class DaemonProcessWin : public DaemonProcess {
65 public:
66 DaemonProcessWin(
67 scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
68 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
69 const base::Closure& stopped_callback);
70 virtual ~DaemonProcessWin();
72 // WorkerProcessIpcDelegate implementation.
73 virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
74 virtual void OnPermanentError(int exit_code) OVERRIDE;
76 // DaemonProcess overrides.
77 virtual void SendToNetwork(IPC::Message* message) OVERRIDE;
78 virtual bool OnDesktopSessionAgentAttached(
79 int terminal_id,
80 base::ProcessHandle desktop_process,
81 IPC::PlatformFileForTransit desktop_pipe) OVERRIDE;
83 protected:
84 // DaemonProcess implementation.
85 virtual scoped_ptr<DesktopSession> DoCreateDesktopSession(
86 int terminal_id,
87 const ScreenResolution& resolution,
88 bool virtual_terminal) OVERRIDE;
89 virtual void DoCrashNetworkProcess(
90 const tracked_objects::Location& location) OVERRIDE;
91 virtual void LaunchNetworkProcess() OVERRIDE;
93 // Changes the service start type to 'manual'.
94 void DisableAutoStart();
96 // Initializes the pairing registry on the host side by sending
97 // ChromotingDaemonNetworkMsg_InitializePairingRegistry message.
98 bool InitializePairingRegistry();
100 // Opens the pairing registry keys.
101 bool OpenPairingRegistry();
103 private:
104 scoped_ptr<WorkerProcessLauncher> network_launcher_;
106 // Handle of the network process.
107 ScopedHandle network_process_;
109 base::win::RegKey pairing_registry_privileged_key_;
110 base::win::RegKey pairing_registry_unprivileged_key_;
112 DISALLOW_COPY_AND_ASSIGN(DaemonProcessWin);
115 DaemonProcessWin::DaemonProcessWin(
116 scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
117 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
118 const base::Closure& stopped_callback)
119 : DaemonProcess(caller_task_runner, io_task_runner, stopped_callback) {
122 DaemonProcessWin::~DaemonProcessWin() {
125 void DaemonProcessWin::OnChannelConnected(int32 peer_pid) {
126 // Obtain the handle of the network process.
127 network_process_.Set(OpenProcess(PROCESS_DUP_HANDLE, false, peer_pid));
128 if (!network_process_.IsValid()) {
129 CrashNetworkProcess(FROM_HERE);
130 return;
133 if (!InitializePairingRegistry()) {
134 CrashNetworkProcess(FROM_HERE);
135 return;
138 DaemonProcess::OnChannelConnected(peer_pid);
141 void DaemonProcessWin::OnPermanentError(int exit_code) {
142 // Change the service start type to 'manual' if the host has been deleted
143 // remotely. This way the host will not be started every time the machine
144 // boots until the user re-enable it again.
145 if (exit_code == kInvalidHostIdExitCode)
146 DisableAutoStart();
148 DaemonProcess::OnPermanentError(exit_code);
151 void DaemonProcessWin::SendToNetwork(IPC::Message* message) {
152 if (network_launcher_) {
153 network_launcher_->Send(message);
154 } else {
155 delete message;
159 bool DaemonProcessWin::OnDesktopSessionAgentAttached(
160 int terminal_id,
161 base::ProcessHandle desktop_process,
162 IPC::PlatformFileForTransit desktop_pipe) {
163 // Prepare |desktop_process| handle for sending over to the network process.
164 base::ProcessHandle desktop_process_for_transit;
165 if (!DuplicateHandle(GetCurrentProcess(),
166 desktop_process,
167 network_process_,
168 &desktop_process_for_transit,
170 FALSE,
171 DUPLICATE_SAME_ACCESS)) {
172 PLOG(ERROR) << "Failed to duplicate the desktop process handle";
173 return false;
176 // |desktop_pipe| is a handle in the desktop process. It will be duplicated
177 // by the network process directly from the desktop process.
178 SendToNetwork(new ChromotingDaemonNetworkMsg_DesktopAttached(
179 terminal_id, desktop_process_for_transit, desktop_pipe));
180 return true;
183 scoped_ptr<DesktopSession> DaemonProcessWin::DoCreateDesktopSession(
184 int terminal_id,
185 const ScreenResolution& resolution,
186 bool virtual_terminal) {
187 DCHECK(caller_task_runner()->BelongsToCurrentThread());
189 if (virtual_terminal) {
190 return DesktopSessionWin::CreateForVirtualTerminal(
191 caller_task_runner(), io_task_runner(), this, terminal_id, resolution);
192 } else {
193 return DesktopSessionWin::CreateForConsole(
194 caller_task_runner(), io_task_runner(), this, terminal_id, resolution);
198 void DaemonProcessWin::DoCrashNetworkProcess(
199 const tracked_objects::Location& location) {
200 DCHECK(caller_task_runner()->BelongsToCurrentThread());
202 network_launcher_->Crash(location);
205 void DaemonProcessWin::LaunchNetworkProcess() {
206 DCHECK(caller_task_runner()->BelongsToCurrentThread());
207 DCHECK(!network_launcher_);
209 // Construct the host binary name.
210 base::FilePath host_binary;
211 if (!GetInstalledBinaryPath(kHostBinaryName, &host_binary)) {
212 Stop();
213 return;
216 scoped_ptr<CommandLine> target(new CommandLine(host_binary));
217 target->AppendSwitchASCII(kProcessTypeSwitchName, kProcessTypeHost);
218 target->CopySwitchesFrom(*CommandLine::ForCurrentProcess(),
219 kCopiedSwitchNames,
220 arraysize(kCopiedSwitchNames));
222 scoped_ptr<UnprivilegedProcessDelegate> delegate(
223 new UnprivilegedProcessDelegate(io_task_runner(), target.Pass()));
224 network_launcher_.reset(new WorkerProcessLauncher(
225 delegate.PassAs<WorkerProcessLauncher::Delegate>(), this));
228 scoped_ptr<DaemonProcess> DaemonProcess::Create(
229 scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
230 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
231 const base::Closure& stopped_callback) {
232 scoped_ptr<DaemonProcessWin> daemon_process(
233 new DaemonProcessWin(caller_task_runner, io_task_runner,
234 stopped_callback));
235 daemon_process->Initialize();
236 return daemon_process.PassAs<DaemonProcess>();
239 void DaemonProcessWin::DisableAutoStart() {
240 ScopedScHandle scmanager(
241 OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE,
242 SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE));
243 if (!scmanager.IsValid()) {
244 PLOG(INFO) << "Failed to connect to the service control manager";
245 return;
248 DWORD desired_access = SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS;
249 ScopedScHandle service(
250 OpenService(scmanager, kWindowsServiceName, desired_access));
251 if (!service.IsValid()) {
252 PLOG(INFO) << "Failed to open to the '" << kWindowsServiceName
253 << "' service";
254 return;
257 // Change the service start type to 'manual'. All |NULL| parameters below mean
258 // that there is no change to the corresponding service parameter.
259 if (!ChangeServiceConfig(service,
260 SERVICE_NO_CHANGE,
261 SERVICE_DEMAND_START,
262 SERVICE_NO_CHANGE,
263 NULL,
264 NULL,
265 NULL,
266 NULL,
267 NULL,
268 NULL,
269 NULL)) {
270 PLOG(INFO) << "Failed to change the '" << kWindowsServiceName
271 << "'service start type to 'manual'";
275 bool DaemonProcessWin::InitializePairingRegistry() {
276 if (!pairing_registry_privileged_key_.Valid()) {
277 if (!OpenPairingRegistry())
278 return false;
281 // Duplicate handles to the network process.
282 IPC::PlatformFileForTransit privileged_key = GetRegistryKeyForTransit(
283 network_process_, pairing_registry_privileged_key_);
284 IPC::PlatformFileForTransit unprivileged_key = GetRegistryKeyForTransit(
285 network_process_, pairing_registry_unprivileged_key_);
286 if (!(privileged_key && unprivileged_key))
287 return false;
289 // Initialize the pairing registry in the network process. This has to be done
290 // before the host configuration is sent, otherwise the host will not use
291 // the passed handles.
292 SendToNetwork(new ChromotingDaemonNetworkMsg_InitializePairingRegistry(
293 privileged_key, unprivileged_key));
294 return true;
297 bool DaemonProcessWin::OpenPairingRegistry() {
298 DCHECK(!pairing_registry_privileged_key_.Valid());
299 DCHECK(!pairing_registry_unprivileged_key_.Valid());
301 // Open the root of the pairing registry.
302 base::win::RegKey root;
303 LONG result = root.Open(HKEY_LOCAL_MACHINE, kPairingRegistryKeyName,
304 KEY_READ);
305 if (result != ERROR_SUCCESS) {
306 SetLastError(result);
307 PLOG(ERROR) << "Failed to open HKLM\\" << kPairingRegistryKeyName;
308 return false;
311 base::win::RegKey privileged;
312 result = privileged.Open(root.Handle(), kPairingRegistryClientsKeyName,
313 KEY_READ | KEY_WRITE);
314 if (result != ERROR_SUCCESS) {
315 SetLastError(result);
316 PLOG(ERROR) << "Failed to open HKLM\\" << kPairingRegistryKeyName << "\\"
317 << kPairingRegistryClientsKeyName;
318 return false;
321 base::win::RegKey unprivileged;
322 result = unprivileged.Open(root.Handle(), kPairingRegistrySecretsKeyName,
323 KEY_READ | KEY_WRITE);
324 if (result != ERROR_SUCCESS) {
325 SetLastError(result);
326 PLOG(ERROR) << "Failed to open HKLM\\" << kPairingRegistrySecretsKeyName
327 << "\\" << kPairingRegistrySecretsKeyName;
328 return false;
331 pairing_registry_privileged_key_.Set(privileged.Take());
332 pairing_registry_unprivileged_key_.Set(unprivileged.Take());
333 return true;
336 } // namespace remoting