Explicitly add python-numpy dependency to install-build-deps.
[chromium-blink-merge.git] / remoting / host / daemon_process_win.cc
blob4c83bb061fdde30d561cbe54dc604568150a92e8
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/win/registry.h"
19 #include "base/win/scoped_handle.h"
20 #include "ipc/ipc_message.h"
21 #include "ipc/ipc_message_macros.h"
22 #include "remoting/base/auto_thread_task_runner.h"
23 #include "remoting/base/scoped_sc_handle_win.h"
24 #include "remoting/host/branding.h"
25 #include "remoting/host/chromoting_messages.h"
26 #include "remoting/host/desktop_session_win.h"
27 #include "remoting/host/host_exit_codes.h"
28 #include "remoting/host/host_main.h"
29 #include "remoting/host/ipc_constants.h"
30 #include "remoting/host/pairing_registry_delegate_win.h"
31 #include "remoting/host/screen_resolution.h"
32 #include "remoting/host/win/launch_process_with_token.h"
33 #include "remoting/host/win/unprivileged_process_delegate.h"
34 #include "remoting/host/win/worker_process_launcher.h"
36 using base::win::ScopedHandle;
37 using base::TimeDelta;
39 namespace {
41 // Duplicates |key| into |target_process| and returns the value that can be sent
42 // over IPC.
43 IPC::PlatformFileForTransit GetRegistryKeyForTransit(
44 base::ProcessHandle target_process,
45 const base::win::RegKey& key) {
46 base::PlatformFile handle =
47 reinterpret_cast<base::PlatformFile>(key.Handle());
48 return IPC::GetFileHandleForProcess(handle, target_process, false);
51 } // namespace
53 namespace remoting {
55 class WtsTerminalMonitor;
57 // The command line parameters that should be copied from the service's command
58 // line to the host process.
59 const char kEnableVp9SwitchName[] = "enable-vp9";
60 const char* kCopiedSwitchNames[] =
61 { switches::kV, switches::kVModule, kEnableVp9SwitchName };
63 class DaemonProcessWin : public DaemonProcess {
64 public:
65 DaemonProcessWin(
66 scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
67 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
68 const base::Closure& stopped_callback);
69 virtual ~DaemonProcessWin();
71 // WorkerProcessIpcDelegate implementation.
72 virtual void OnChannelConnected(int32 peer_pid) override;
73 virtual void OnPermanentError(int exit_code) override;
75 // DaemonProcess overrides.
76 virtual void SendToNetwork(IPC::Message* message) override;
77 virtual bool OnDesktopSessionAgentAttached(
78 int terminal_id,
79 base::ProcessHandle desktop_process,
80 IPC::PlatformFileForTransit desktop_pipe) override;
82 protected:
83 // DaemonProcess implementation.
84 virtual scoped_ptr<DesktopSession> DoCreateDesktopSession(
85 int terminal_id,
86 const ScreenResolution& resolution,
87 bool virtual_terminal) override;
88 virtual void DoCrashNetworkProcess(
89 const tracked_objects::Location& location) override;
90 virtual void LaunchNetworkProcess() override;
92 // Changes the service start type to 'manual'.
93 void DisableAutoStart();
95 // Initializes the pairing registry on the host side by sending
96 // ChromotingDaemonNetworkMsg_InitializePairingRegistry message.
97 bool InitializePairingRegistry();
99 // Opens the pairing registry keys.
100 bool OpenPairingRegistry();
102 private:
103 scoped_ptr<WorkerProcessLauncher> network_launcher_;
105 // Handle of the network process.
106 ScopedHandle network_process_;
108 base::win::RegKey pairing_registry_privileged_key_;
109 base::win::RegKey pairing_registry_unprivileged_key_;
111 DISALLOW_COPY_AND_ASSIGN(DaemonProcessWin);
114 DaemonProcessWin::DaemonProcessWin(
115 scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
116 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
117 const base::Closure& stopped_callback)
118 : DaemonProcess(caller_task_runner, io_task_runner, stopped_callback) {
121 DaemonProcessWin::~DaemonProcessWin() {
124 void DaemonProcessWin::OnChannelConnected(int32 peer_pid) {
125 // Obtain the handle of the network process.
126 network_process_.Set(OpenProcess(PROCESS_DUP_HANDLE, false, peer_pid));
127 if (!network_process_.IsValid()) {
128 CrashNetworkProcess(FROM_HERE);
129 return;
132 if (!InitializePairingRegistry()) {
133 CrashNetworkProcess(FROM_HERE);
134 return;
137 DaemonProcess::OnChannelConnected(peer_pid);
140 void DaemonProcessWin::OnPermanentError(int exit_code) {
141 // Change the service start type to 'manual' if the host has been deleted
142 // remotely. This way the host will not be started every time the machine
143 // boots until the user re-enable it again.
144 if (exit_code == kInvalidHostIdExitCode)
145 DisableAutoStart();
147 DaemonProcess::OnPermanentError(exit_code);
150 void DaemonProcessWin::SendToNetwork(IPC::Message* message) {
151 if (network_launcher_) {
152 network_launcher_->Send(message);
153 } else {
154 delete message;
158 bool DaemonProcessWin::OnDesktopSessionAgentAttached(
159 int terminal_id,
160 base::ProcessHandle desktop_process,
161 IPC::PlatformFileForTransit desktop_pipe) {
162 // Prepare |desktop_process| handle for sending over to the network process.
163 base::ProcessHandle desktop_process_for_transit;
164 if (!DuplicateHandle(GetCurrentProcess(),
165 desktop_process,
166 network_process_.Get(),
167 &desktop_process_for_transit,
169 FALSE,
170 DUPLICATE_SAME_ACCESS)) {
171 PLOG(ERROR) << "Failed to duplicate the desktop process handle";
172 return false;
175 // |desktop_pipe| is a handle in the desktop process. It will be duplicated
176 // by the network process directly from the desktop process.
177 SendToNetwork(new ChromotingDaemonNetworkMsg_DesktopAttached(
178 terminal_id, desktop_process_for_transit, desktop_pipe));
179 return true;
182 scoped_ptr<DesktopSession> DaemonProcessWin::DoCreateDesktopSession(
183 int terminal_id,
184 const ScreenResolution& resolution,
185 bool virtual_terminal) {
186 DCHECK(caller_task_runner()->BelongsToCurrentThread());
188 if (virtual_terminal) {
189 return DesktopSessionWin::CreateForVirtualTerminal(
190 caller_task_runner(), io_task_runner(), this, terminal_id, resolution);
191 } else {
192 return DesktopSessionWin::CreateForConsole(
193 caller_task_runner(), io_task_runner(), this, terminal_id, resolution);
197 void DaemonProcessWin::DoCrashNetworkProcess(
198 const tracked_objects::Location& location) {
199 DCHECK(caller_task_runner()->BelongsToCurrentThread());
201 network_launcher_->Crash(location);
204 void DaemonProcessWin::LaunchNetworkProcess() {
205 DCHECK(caller_task_runner()->BelongsToCurrentThread());
206 DCHECK(!network_launcher_);
208 // Construct the host binary name.
209 base::FilePath host_binary;
210 if (!GetInstalledBinaryPath(kHostBinaryName, &host_binary)) {
211 Stop();
212 return;
215 scoped_ptr<CommandLine> target(new CommandLine(host_binary));
216 target->AppendSwitchASCII(kProcessTypeSwitchName, kProcessTypeHost);
217 target->CopySwitchesFrom(*CommandLine::ForCurrentProcess(),
218 kCopiedSwitchNames,
219 arraysize(kCopiedSwitchNames));
221 scoped_ptr<UnprivilegedProcessDelegate> delegate(
222 new UnprivilegedProcessDelegate(io_task_runner(), target.Pass()));
223 network_launcher_.reset(new WorkerProcessLauncher(delegate.Pass(), this));
226 scoped_ptr<DaemonProcess> DaemonProcess::Create(
227 scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
228 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
229 const base::Closure& stopped_callback) {
230 scoped_ptr<DaemonProcessWin> daemon_process(
231 new DaemonProcessWin(caller_task_runner, io_task_runner,
232 stopped_callback));
233 daemon_process->Initialize();
234 return daemon_process.Pass();
237 void DaemonProcessWin::DisableAutoStart() {
238 ScopedScHandle scmanager(
239 OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE,
240 SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE));
241 if (!scmanager.IsValid()) {
242 PLOG(INFO) << "Failed to connect to the service control manager";
243 return;
246 DWORD desired_access = SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS;
247 ScopedScHandle service(
248 OpenService(scmanager.Get(), kWindowsServiceName, desired_access));
249 if (!service.IsValid()) {
250 PLOG(INFO) << "Failed to open to the '" << kWindowsServiceName
251 << "' service";
252 return;
255 // Change the service start type to 'manual'. All |NULL| parameters below mean
256 // that there is no change to the corresponding service parameter.
257 if (!ChangeServiceConfig(service.Get(),
258 SERVICE_NO_CHANGE,
259 SERVICE_DEMAND_START,
260 SERVICE_NO_CHANGE,
261 NULL,
262 NULL,
263 NULL,
264 NULL,
265 NULL,
266 NULL,
267 NULL)) {
268 PLOG(INFO) << "Failed to change the '" << kWindowsServiceName
269 << "'service start type to 'manual'";
273 bool DaemonProcessWin::InitializePairingRegistry() {
274 if (!pairing_registry_privileged_key_.Valid()) {
275 if (!OpenPairingRegistry())
276 return false;
279 // Duplicate handles to the network process.
280 IPC::PlatformFileForTransit privileged_key = GetRegistryKeyForTransit(
281 network_process_.Get(), pairing_registry_privileged_key_);
282 IPC::PlatformFileForTransit unprivileged_key = GetRegistryKeyForTransit(
283 network_process_.Get(), pairing_registry_unprivileged_key_);
284 if (!(privileged_key && unprivileged_key))
285 return false;
287 // Initialize the pairing registry in the network process. This has to be done
288 // before the host configuration is sent, otherwise the host will not use
289 // the passed handles.
290 SendToNetwork(new ChromotingDaemonNetworkMsg_InitializePairingRegistry(
291 privileged_key, unprivileged_key));
292 return true;
295 bool DaemonProcessWin::OpenPairingRegistry() {
296 DCHECK(!pairing_registry_privileged_key_.Valid());
297 DCHECK(!pairing_registry_unprivileged_key_.Valid());
299 // Open the root of the pairing registry.
300 base::win::RegKey root;
301 LONG result = root.Open(HKEY_LOCAL_MACHINE, kPairingRegistryKeyName,
302 KEY_READ);
303 if (result != ERROR_SUCCESS) {
304 SetLastError(result);
305 PLOG(ERROR) << "Failed to open HKLM\\" << kPairingRegistryKeyName;
306 return false;
309 base::win::RegKey privileged;
310 result = privileged.Open(root.Handle(), kPairingRegistryClientsKeyName,
311 KEY_READ | KEY_WRITE);
312 if (result != ERROR_SUCCESS) {
313 SetLastError(result);
314 PLOG(ERROR) << "Failed to open HKLM\\" << kPairingRegistryKeyName << "\\"
315 << kPairingRegistryClientsKeyName;
316 return false;
319 base::win::RegKey unprivileged;
320 result = unprivileged.Open(root.Handle(), kPairingRegistrySecretsKeyName,
321 KEY_READ | KEY_WRITE);
322 if (result != ERROR_SUCCESS) {
323 SetLastError(result);
324 PLOG(ERROR) << "Failed to open HKLM\\" << kPairingRegistrySecretsKeyName
325 << "\\" << kPairingRegistrySecretsKeyName;
326 return false;
329 pairing_registry_privileged_key_.Set(privileged.Take());
330 pairing_registry_unprivileged_key_.Set(unprivileged.Take());
331 return true;
334 } // namespace remoting